Soft Patch Panel
 help / color / mirror / Atom feed
* [spp] Proposal - spp_vf(SR-IOV like feature) addition to SPP
@ 2017-12-25  4:41 Nakamura Hioryuki
  2017-12-26  1:54 ` Yasufumi Ogawa
  2018-01-15 11:04 ` [spp] Proposal - spp_vf(SR-IOV like feature) addition to SPP Ferruh Yigit
  0 siblings, 2 replies; 97+ messages in thread
From: Nakamura Hioryuki @ 2017-12-25  4:41 UTC (permalink / raw)
  To: spp

Hi everyone,

As announced in DPDK Summit, we would like to introduce a SR-IOV like network 
functionality to SPP on DPDK17.08[1].

To support such functionality, we have developed new 
controller(spp_vf.py) and secondary process(spp_vf).

spp_vf process has three kinds of component, classifier, forwarder and merger.
These components communicate each other via ring-pmd, 
and provides SR-IOV like packet classification function according to virtual 
MAC address.

Classifier:
This component provides packet forwarding function from one port to one port.
Classifier has table of virtual MAC address.
According to this table, classifier lookups L2 destination MAC address
and determines which port to be transferred to incoming packets.
L2 Multicast feature is also supported. 

Forwarder:
This provides function for packet processing from one port to one port.
Incoming packets from port are to be transferred to specific one port.
The direction of this transferring is specified by `port` command.

Merger:
This component provides packet forwarding function from multiple ports to one port.
Incoming packets from multiple ports are to be transferred to one specific port.
The flow of this merging process is specified by `port` command.

By the combination of these component, following SR-IOV like function can be configured.

                   +----------+           +-----------+
                   |Classifier|->ringPMD->|Forwarder#1|->vhost->VM#1 --------+
Packet(dstMAC:A/B) |          |           +-----------+         (vMAC:A)     |
------phy--------> |          |           +-----------+                      |
                   |          |->ringPMD->|Forwarder#2|->vhost->VM#2 ---+    |
                   |          |           +-----------+         (vMAC:B)|    |
                   +----------+                                         |    |
                                                                        |    |
                   +----------+           +-----------+                 |    |
                   |Merger    |<-ringPMD<-|Forwarder#3|<-vhost --==----------+
                   |          |           +-----------+                 |
 <------phy--------|          |           +-----------+                 |
                   |          |<-ringPMD<-|Forwarder#4|<-vhost ---------+
                   +----------+           +-----------+ 

Limitaion#1: vlan support is not yet, this feature is in still our backlogs.
Limitaion#2: Support DPDK17.11 is not yet.
                   
Code changes will be posted in the following emails.

Regard,


-- Hiroyuki Nakamura
NTT TechnoCross Corporation

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

* Re: [spp] Proposal - spp_vf(SR-IOV like feature) addition to SPP
  2017-12-25  4:41 [spp] Proposal - spp_vf(SR-IOV like feature) addition to SPP Nakamura Hioryuki
@ 2017-12-26  1:54 ` Yasufumi Ogawa
  2017-12-28  4:55   ` [spp] [PATCH 01/57] spp_vf: add vf functions x-fn-spp
                     ` (56 more replies)
  2018-01-15 11:04 ` [spp] Proposal - spp_vf(SR-IOV like feature) addition to SPP Ferruh Yigit
  1 sibling, 57 replies; 97+ messages in thread
From: Yasufumi Ogawa @ 2017-12-26  1:54 UTC (permalink / raw)
  To: Nakamura Hioryuki, spp

Hi,

Thanks Hiroyuki for proposing new feature. I did not tell you the link 
of reference.
[1] 
https://dpdksummit.com/Archive/pdf/2017USA/Implementation%20and%20Testing%20of%20Soft%20Patch%20Panel.pdf

I'm waiting for your patches!

Thanks,
Yasufumi

On 2017/12/25 13:41, Nakamura Hioryuki wrote:
> Hi everyone,
> 
> As announced in DPDK Summit, we would like to introduce a SR-IOV like network
> functionality to SPP on DPDK17.08[1].
> 
> To support such functionality, we have developed new
> controller(spp_vf.py) and secondary process(spp_vf).
> 
> spp_vf process has three kinds of component, classifier, forwarder and merger.
> These components communicate each other via ring-pmd,
> and provides SR-IOV like packet classification function according to virtual
> MAC address.
> 
> Classifier:
> This component provides packet forwarding function from one port to one port.
> Classifier has table of virtual MAC address.
> According to this table, classifier lookups L2 destination MAC address
> and determines which port to be transferred to incoming packets.
> L2 Multicast feature is also supported.
> 
> Forwarder:
> This provides function for packet processing from one port to one port.
> Incoming packets from port are to be transferred to specific one port.
> The direction of this transferring is specified by `port` command.
> 
> Merger:
> This component provides packet forwarding function from multiple ports to one port.
> Incoming packets from multiple ports are to be transferred to one specific port.
> The flow of this merging process is specified by `port` command.
> 
> By the combination of these component, following SR-IOV like function can be configured.
> 
>                     +----------+           +-----------+
>                     |Classifier|->ringPMD->|Forwarder#1|->vhost->VM#1 --------+
> Packet(dstMAC:A/B) |          |           +-----------+         (vMAC:A)     |
> ------phy--------> |          |           +-----------+                      |
>                     |          |->ringPMD->|Forwarder#2|->vhost->VM#2 ---+    |
>                     |          |           +-----------+         (vMAC:B)|    |
>                     +----------+                                         |    |
>                                                                          |    |
>                     +----------+           +-----------+                 |    |
>                     |Merger    |<-ringPMD<-|Forwarder#3|<-vhost --==----------+
>                     |          |           +-----------+                 |
>   <------phy--------|          |           +-----------+                 |
>                     |          |<-ringPMD<-|Forwarder#4|<-vhost ---------+
>                     +----------+           +-----------+
> 
> Limitaion#1: vlan support is not yet, this feature is in still our backlogs.
> Limitaion#2: Support DPDK17.11 is not yet.
>                     
> Code changes will be posted in the following emails.
> 
> Regard,
> 
> 
> -- Hiroyuki Nakamura
> NTT TechnoCross Corporation
> 
> 
> 
> 


-- 
Yasufumi Ogawa
NTT Network Service Systems Labs

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

* [spp] [PATCH 01/57] spp_vf: add vf functions
  2017-12-26  1:54 ` Yasufumi Ogawa
@ 2017-12-28  4:55   ` x-fn-spp
  2017-12-28  8:49     ` Yasufumi Ogawa
  2017-12-28  4:55   ` [spp] [PATCH 02/57] spp_vf: support multi process x-fn-spp
                     ` (55 subsequent siblings)
  56 siblings, 1 reply; 97+ messages in thread
From: x-fn-spp @ 2017-12-28  4:55 UTC (permalink / raw)
  To: spp

From: Hiroyuki Nakamura <nakamura.hioryuki@po.ntt-tx.co.jp>

Hi everyone,

This the first patch of series for spp_vf. Some of them might not comply 
with coding style for whitespace or indenting and I would like to send 
patches to fix it later.

I also would like to send another series of patches for documentation after 
you accept first series.

Thanks,

* Classifier by MAC address
* Forwarder
* Merger

Signed-off-by: Tomoyuki Mizuguchi <mizuguchi.tomoyuki@po.ntt-tx.co.jp>
Signed-off-by: Yasufum Ogawa <ogawa.yasufumi@lab.ntt.co.jp>
---
 src/Makefile              |   1 +
 src/vf/Makefile           |  56 ++++
 src/vf/classifier_mac.c   | 233 ++++++++++++++
 src/vf/classifier_mac.h   |  12 +
 src/vf/ringlatencystats.c | 147 +++++++++
 src/vf/ringlatencystats.h |  69 ++++
 src/vf/spp_config.c       | 669 ++++++++++++++++++++++++++++++++++++++
 src/vf/spp_config.h       |  90 ++++++
 src/vf/spp_forward.c      | 106 +++++++
 src/vf/spp_forward.h      |   9 +
 src/vf/spp_vf.c           | 794 ++++++++++++++++++++++++++++++++++++++++++++++
 src/vf/spp_vf.h           |  40 +++
 12 files changed, 2226 insertions(+)
 create mode 100644 src/vf/Makefile
 create mode 100644 src/vf/classifier_mac.c
 create mode 100644 src/vf/classifier_mac.h
 create mode 100644 src/vf/ringlatencystats.c
 create mode 100644 src/vf/ringlatencystats.h
 create mode 100644 src/vf/spp_config.c
 create mode 100644 src/vf/spp_config.h
 create mode 100644 src/vf/spp_forward.c
 create mode 100644 src/vf/spp_forward.h
 create mode 100644 src/vf/spp_vf.c
 create mode 100644 src/vf/spp_vf.h

diff --git a/src/Makefile b/src/Makefile
index 6fd24b8..d2eb9b6 100644
--- a/src/Makefile
+++ b/src/Makefile
@@ -41,5 +41,6 @@ include $(RTE_SDK)/mk/rte.vars.mk
 DIRS-$(CONFIG_RTE_EXEC_ENV_LINUXAPP) += nfv
 DIRS-$(CONFIG_RTE_EXEC_ENV_LINUXAPP) += primary
 DIRS-$(CONFIG_RTE_EXEC_ENV_LINUXAPP) += vm
+DIRS-$(CONFIG_RTE_EXEC_ENV_LINUXAPP) += vf
 
 include $(RTE_SDK)/mk/rte.extsubdir.mk
diff --git a/src/vf/Makefile b/src/vf/Makefile
new file mode 100644
index 0000000..4961d2e
--- /dev/null
+++ b/src/vf/Makefile
@@ -0,0 +1,56 @@
+#   BSD LICENSE
+#
+#   Copyright(c) 2015-2016 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 overriden by command line or environment
+include $(RTE_SDK)/mk/rte.vars.mk
+
+# binary name
+APP = spp_vf
+
+# all source are stored in SRCS-y
+SRCS-y := spp_vf.c spp_config.c classifier_mac.c spp_forward.c ringlatencystats.c ../shared/common.c
+
+CFLAGS += $(WERROR_FLAGS) -O3
+CFLAGS += -I$(SRCDIR)/../shared
+#CFLAGS += -DSPP_DEMONIZE
+#CFLAGS += -DSPP_RINGLATENCYSTATS_ENABLE
+
+LDLIBS += -ljansson
+ifeq ($(CONFIG_RTE_BUILD_SHARED_LIB),y)
+LDLIBS += -lrte_pmd_ring
+LDLIBS += -lrte_pmd_vhost
+endif
+
+include $(RTE_SDK)/mk/rte.extapp.mk
diff --git a/src/vf/classifier_mac.c b/src/vf/classifier_mac.c
new file mode 100644
index 0000000..da03905
--- /dev/null
+++ b/src/vf/classifier_mac.c
@@ -0,0 +1,233 @@
+#include <unistd.h>
+#include <sys/types.h>
+#include <stdio.h>
+#include <stdint.h>
+#include <stddef.h>
+#include <math.h>
+
+#include <rte_mbuf.h>
+#include <rte_log.h>
+#include <rte_cycles.h>
+#include <rte_malloc.h>
+#include <rte_memcpy.h>
+#include <rte_random.h>
+#include <rte_byteorder.h>
+#include <rte_per_lcore.h>
+#include <rte_eal.h>
+#include <rte_launch.h>
+#include <rte_hash.h>
+
+#include "spp_vf.h"
+#include "ringlatencystats.h"
+#include "classifier_mac.h"
+
+#define RTE_LOGTYPE_SPP_CLASSIFIER_MAC RTE_LOGTYPE_USER1
+
+#ifdef RTE_MACHINE_CPUFLAG_SSE4_2
+#include <rte_hash_crc.h>
+#define DEFAULT_HASH_FUNC rte_hash_crc
+#else
+#include <rte_jhash.h>
+#define DEFAULT_HASH_FUNC rte_jhash
+#endif
+
+/* number of classifier mac table entry */
+#define NUM_CLASSIFIER_MAC_TABLE_ENTRY 128
+
+/* interval that transmit burst packet, if buffer is not filled.
+		nano second */
+#define DRAIN_TX_PACKET_INTERVAL 100
+
+/* mac address string(xx:xx:xx:xx:xx:xx) buffer size */
+static const size_t ETHER_ADDR_STR_BUF_SZ =
+		ETHER_ADDR_LEN * 2 + (ETHER_ADDR_LEN - 1) + 1;
+
+/* classified data (destination port, target packets, etc) */
+struct classified_data {
+	int      if_no;
+	uint8_t  tx_port;
+	uint16_t num_pkt;
+	struct rte_mbuf *pkts[MAX_PKT_BURST];
+};
+
+/* initialize classifier. */
+static int
+init_classifier(const struct spp_core_info *core_info,
+		struct rte_hash **classifier_mac_table, struct classified_data *classified_data)
+{
+	int ret = -1;
+	int i;
+	struct ether_addr eth_addr;
+	char mac_addr_str[ETHER_ADDR_STR_BUF_SZ];
+
+	/* set hash creating parameters */
+	struct rte_hash_parameters hash_params = {
+			.name      = "classifier_mac_table",
+			.entries   = NUM_CLASSIFIER_MAC_TABLE_ENTRY,
+			.key_len   = sizeof(struct ether_addr),
+			.hash_func = DEFAULT_HASH_FUNC,
+			.hash_func_init_val = 0,
+			.socket_id = rte_socket_id(),
+	};
+
+#ifdef RTE_MACHINE_CPUFLAG_SSE4_2
+	RTE_LOG(DEBUG, SPP_CLASSIFIER_MAC, "Enabled SSE4.2. use crc hash.\n");
+#else
+	RTE_LOG(DEBUG, SPP_CLASSIFIER_MAC, "Disabled SSE4.2. use jenkins hash.\n");
+#endif
+
+	/* create classifier mac table (hash table) */
+	*classifier_mac_table = rte_hash_create(&hash_params);
+	if (unlikely(*classifier_mac_table == NULL)) {
+		RTE_LOG(ERR, SPP_CLASSIFIER_MAC, "Cannot create classifier mac table\n");
+		return -1;
+	}
+
+	/* populate the hash */
+	for (i = 0; i < core_info->num_tx_port; i++) {
+		rte_memcpy(&eth_addr, &core_info->tx_ports[i].mac_addr, ETHER_ADDR_LEN);
+
+		/* add entry to classifier mac table */
+		ret = rte_hash_add_key_data(*classifier_mac_table, (void*)&eth_addr, (void*)(long)i);
+		if (unlikely(ret < 0)) {
+			ether_format_addr(mac_addr_str, sizeof(mac_addr_str), &eth_addr);
+			RTE_LOG(ERR, SPP_CLASSIFIER_MAC,
+					"Cannot add entry to classifier mac table. "
+					"ret=%d, mac_addr=%s\n", ret, mac_addr_str);
+			rte_hash_free(*classifier_mac_table);
+			*classifier_mac_table = NULL;
+			return -1;
+		}
+
+		/* set value */
+		classified_data[i].if_no   = i;
+		classified_data[i].tx_port = core_info->tx_ports[i].dpdk_port;
+		classified_data[i].num_pkt = 0;
+	}
+
+	return 0;
+}
+
+/* transimit packet to one destination. */
+static inline void
+transimit_packet(struct classified_data *classified_data)
+{
+	int i;
+	uint16_t n_tx;
+
+	/* set ringlatencystats */
+	spp_ringlatencystats_add_time_stamp(classified_data->if_no,
+			classified_data->pkts, classified_data->num_pkt);
+
+	/* transimit packets */
+	n_tx = rte_eth_tx_burst(classified_data->tx_port, 0,
+			classified_data->pkts, classified_data->num_pkt);
+
+	/* free cannnot transiit packets */
+	if (unlikely(n_tx != classified_data->num_pkt)) {
+		for (i = n_tx; i < classified_data->num_pkt; i++)
+			rte_pktmbuf_free(classified_data->pkts[i]);
+		RTE_LOG(DEBUG, SPP_CLASSIFIER_MAC,
+				"drop packets(tx). num=%hu, dpdk_port=%hhu\n",
+				classified_data->num_pkt - n_tx, classified_data->tx_port);
+	}
+
+	classified_data->num_pkt = 0;
+}
+
+/* classify packet by destination mac address,
+		and transimit packet (conditional). */
+static inline void
+classify_packet(struct rte_mbuf **rx_pkts, uint16_t n_rx,
+		struct rte_hash *classifier_mac_table, struct classified_data *classified_data)
+{
+	int ret;
+	int i;
+	struct ether_hdr *eth;
+	struct classified_data *cd;
+	void *lookup_data;
+	char mac_addr_str[ETHER_ADDR_STR_BUF_SZ];
+
+	for (i = 0; i < n_rx; i++) {
+		eth = rte_pktmbuf_mtod(rx_pkts[i], struct ether_hdr *);
+
+		/* find in table (by destination mac address)*/
+		ret = rte_hash_lookup_data(classifier_mac_table,
+				(const void*)&eth->d_addr, &lookup_data);
+		if (unlikely(ret < 0)) {
+			ether_format_addr(mac_addr_str, sizeof(mac_addr_str), &eth->d_addr);
+			RTE_LOG(ERR, SPP_CLASSIFIER_MAC,
+					"unknown mac address. ret=%d, mac_addr=%s\n", ret, mac_addr_str);
+			rte_pktmbuf_free(rx_pkts[i]);
+			continue;
+		}
+
+		/* set mbuf pointer to tx buffer */
+		cd = classified_data + (long)lookup_data;
+		cd->pkts[cd->num_pkt++] = rx_pkts[i];
+
+		/* transimit packet, if buffer is filled */
+		if (unlikely(cd->num_pkt == MAX_PKT_BURST))
+			transimit_packet(cd);
+	}
+}
+
+/* classifier(mac address) thread function. */
+int
+spp_classifier_mac_do(void *arg)
+{
+	int ret = -1;
+	int i;
+	int n_rx;
+	struct spp_core_info *core_info = (struct spp_core_info *)arg;
+	struct rte_mbuf *rx_pkts[MAX_PKT_BURST];
+
+	struct rte_hash *classifier_mac_table = NULL;
+	const int n_classified_data = core_info->num_tx_port;
+	struct classified_data classified_data[n_classified_data];
+
+	uint64_t cur_tsc, prev_tsc = 0;
+	const uint64_t drain_tsc = (rte_get_tsc_hz() + US_PER_S - 1) /
+			US_PER_S * DRAIN_TX_PACKET_INTERVAL;
+
+	/* initialize */
+	ret = init_classifier(core_info, &classifier_mac_table, classified_data);
+	if (unlikely(ret != 0))
+		return ret;
+
+	/* to idle  */
+	core_info->status = SPP_CORE_IDLE;
+	while(likely(core_info->status == SPP_CORE_IDLE) ||
+			likely(core_info->status == SPP_CORE_FORWARD)) {
+
+		while(likely(core_info->status == SPP_CORE_FORWARD)) {
+			/* drain tx packets, if buffer is not filled for interval */
+			cur_tsc = rte_rdtsc();
+			if (unlikely(cur_tsc - prev_tsc > drain_tsc)) {
+				for (i = 0; i < n_classified_data; i++) {
+					if (unlikely(classified_data[i].num_pkt != 0))
+						transimit_packet(&classified_data[i]);
+				}
+				prev_tsc = cur_tsc;
+			}
+
+			/* retrieve packets */
+			n_rx = rte_eth_rx_burst(core_info->rx_ports[0].dpdk_port, 0,
+					rx_pkts, MAX_PKT_BURST);
+			if (unlikely(n_rx == 0))
+				continue;
+
+			/* classify and transimit (filled) */
+			classify_packet(rx_pkts, n_rx, classifier_mac_table, classified_data);
+		}
+	}
+
+	/* uninitialize */
+	if (classifier_mac_table != NULL) {
+		rte_hash_free(classifier_mac_table);
+		classifier_mac_table = NULL;
+	}
+	core_info->status = SPP_CORE_STOP;
+
+	return 0;
+}
diff --git a/src/vf/classifier_mac.h b/src/vf/classifier_mac.h
new file mode 100644
index 0000000..2661206
--- /dev/null
+++ b/src/vf/classifier_mac.h
@@ -0,0 +1,12 @@
+#ifndef _CLASSIFIER_MAC_H_
+#define _CLASSIFIER_MAC_H_
+
+/**
+ * classifier(mac address) thread function.
+ *
+ * @param arg
+ *  pointer to struct spp_core_info.
+ */
+int spp_classifier_mac_do(void *arg);
+
+#endif /* _CLASSIFIER_MAC_H_ */
diff --git a/src/vf/ringlatencystats.c b/src/vf/ringlatencystats.c
new file mode 100644
index 0000000..8f44020
--- /dev/null
+++ b/src/vf/ringlatencystats.c
@@ -0,0 +1,147 @@
+#include <unistd.h>
+#include <sys/types.h>
+#include <stdio.h>
+#include <stddef.h>
+#include <math.h>
+
+#include <rte_mbuf.h>
+#include <rte_log.h>
+#include <rte_cycles.h>
+#include <rte_malloc.h>
+#include <rte_memcpy.h>
+
+#include "ringlatencystats.h"
+
+#define NS_PER_SEC 1E9
+
+#define RTE_LOGTYPE_SPP_RING_LATENCY_STATS RTE_LOGTYPE_USER1
+
+#ifdef SPP_RINGLATENCYSTATS_ENABLE
+
+/** ring latency statistics information */
+struct ring_latency_stats_info {
+	uint64_t timer_tsc;   /**< sampling interval counter */
+	uint64_t prev_tsc;    /**< previous time */
+	struct spp_ringlatencystats_ring_latency_stats stats;  /**< ring latency statistics list */
+};
+
+/** sampling interval */
+static uint64_t g_samp_intvl = 0;
+
+/** ring latency statistics information instance */
+static struct ring_latency_stats_info *g_stats_info = NULL;
+
+/** number of ring latency statisics */
+static uint16_t g_stats_count = 0;
+
+/* clock cycles per nano second */
+static inline uint64_t
+cycles_per_ns(void)
+{
+	return rte_get_timer_hz() / NS_PER_SEC;
+}
+
+int
+spp_ringlatencystats_init(uint64_t samp_intvl, uint16_t stats_count)
+{
+	/* allocate memory for ring latency statisics infromation */
+	g_stats_info = rte_zmalloc(
+			"global ring_latency_stats_info",
+			sizeof(struct ring_latency_stats_info) * stats_count, 0);
+	if (unlikely(g_stats_info == NULL)) {
+		RTE_LOG(ERR, SPP_RING_LATENCY_STATS,
+				"Cannot allocate memory for ring latency stats info\n");
+		return -1;
+	}
+
+	/* store global information for ring latency statistics */
+	g_samp_intvl = samp_intvl * cycles_per_ns();
+	g_stats_count = stats_count;
+
+	RTE_LOG(DEBUG, SPP_RING_LATENCY_STATS,
+			"g_samp_intvl=%lu, g_stats_count=%hu, cpns=%lu\n",
+			g_samp_intvl, g_stats_count, cycles_per_ns());
+
+	return 0;
+}
+
+void
+spp_ringlatencystats_uninit(void)
+{
+	/* free memory for ring latency statisics infromation */
+	if (likely(g_stats_info != NULL)) {
+		rte_free(g_stats_info);
+		g_stats_count = 0;
+	}
+}
+
+void
+spp_ringlatencystats_add_time_stamp(int ring_id,
+			struct rte_mbuf **pkts, uint16_t nb_pkts)
+{
+	unsigned int i;
+	uint64_t diff_tsc, now;
+	struct ring_latency_stats_info *stats_info = &g_stats_info[ring_id];
+
+	for (i = 0; i < nb_pkts; i++) {
+
+		/* get tsc now */
+		now = rte_rdtsc();
+
+		/* calculate difference from the previous processing time */
+		diff_tsc = now - stats_info->prev_tsc;
+		stats_info->timer_tsc += diff_tsc;
+
+		/* when it is over sampling interval */
+		/* set tsc to mbuf::timestamp */
+		if (unlikely(stats_info->timer_tsc >= g_samp_intvl)) {
+			pkts[i]->timestamp = now;
+			stats_info->timer_tsc = 0;
+		}
+
+		/* update previus tsc */
+		stats_info->prev_tsc = now;
+	}
+}
+
+void
+spp_ringlatencystats_calculate_latency(int ring_id,
+			struct rte_mbuf **pkts, uint16_t nb_pkts)
+{
+	unsigned int i;
+	uint64_t now;
+	int64_t latency;
+	struct ring_latency_stats_info *stats_info = &g_stats_info[ring_id];
+
+	now = rte_rdtsc();
+	for (i = 0; i < nb_pkts; i++) {
+		if (likely(pkts[i]->timestamp == 0))
+			continue;
+
+		/* when mbuf::timestamp is not zero */
+		/* calculate latency */
+		latency = (uint64_t)floor((now - pkts[i]->timestamp) / cycles_per_ns());
+		if (likely(latency < SPP_RINGLATENCYSTATS_STATS_SLOT_COUNT-1))
+			stats_info->stats.slot[latency]++;
+		else
+			stats_info->stats.slot[SPP_RINGLATENCYSTATS_STATS_SLOT_COUNT-1]++;
+	}
+}
+
+int
+spp_ringlatencystats_get_count(void)
+{
+	return g_stats_count;
+}
+
+void
+spp_ringlatencystats_get_stats(int ring_id,
+		struct spp_ringlatencystats_ring_latency_stats *stats)
+{
+	struct ring_latency_stats_info *stats_info = &g_stats_info[ring_id];
+
+	rte_memcpy(stats, &stats_info->stats,
+			sizeof(struct spp_ringlatencystats_ring_latency_stats));
+}
+
+#endif /* SPP_RINGLATENCYSTATS_ENABLE */
diff --git a/src/vf/ringlatencystats.h b/src/vf/ringlatencystats.h
new file mode 100644
index 0000000..bc47699
--- /dev/null
+++ b/src/vf/ringlatencystats.h
@@ -0,0 +1,69 @@
+#ifndef _RINGLATENCYSTATS_H_
+#define _RINGLATENCYSTATS_H_
+
+#include <rte_mbuf.h>
+
+/** number of slots to save latency. 0ns~99ns and 100ns over */
+#define SPP_RINGLATENCYSTATS_STATS_SLOT_COUNT 101
+
+/** ring latency statistics */
+struct spp_ringlatencystats_ring_latency_stats {
+	uint64_t slot[SPP_RINGLATENCYSTATS_STATS_SLOT_COUNT]; /**< slots to save latency */
+};
+
+
+#ifdef SPP_RINGLATENCYSTATS_ENABLE
+/**
+ * initialize ring latency statisics.
+ *
+ * @retval 0: succeeded.
+ * @retval -1: failed.
+ */
+int spp_ringlatencystats_init(uint64_t samp_intvl, uint16_t stats_count);
+
+/**
+ *uninitialize ring latency statisics.
+ */
+void spp_ringlatencystats_uninit(void);
+
+/**
+ * add time-stamp to mbuf's member.
+ *
+ * call at enqueue.
+ */
+void spp_ringlatencystats_add_time_stamp(int ring_id,
+			struct rte_mbuf **pkts, uint16_t nb_pkts);
+
+/**
+ * calculate latency.
+ *
+ * call at dequeue.
+ */
+void spp_ringlatencystats_calculate_latency(int ring_id,
+			struct rte_mbuf **pkts, uint16_t nb_pkts);
+
+/**
+ * get number of ring latency statisics.
+ *
+ * @return spp_ringlatencystats_init's parameter "stats_count"
+ */
+int spp_ringlatencystats_get_count(void);
+
+/**
+ *get specific ring latency statisics.
+ */
+void spp_ringlatencystats_get_stats(int ring_id,
+		struct spp_ringlatencystats_ring_latency_stats *stats);
+
+#else
+
+#define spp_ringlatencystats_init(arg1, arg2) 0
+#define spp_ringlatencystats_uninit()
+#define spp_ringlatencystats_add_time_stamp(arg1, arg2, arg3)
+#define spp_ringlatencystats_calculate_latency(arg1, arg2, arg3)
+#define spp_ringlatencystats_get_count() 0
+#define spp_ringlatencystats_get_stats(arg1, arg2)
+
+#endif /* SPP_RINGLATENCYSTATS_ENABLE */
+
+#endif /* _RINGLATENCYSTATS_H_ */
diff --git a/src/vf/spp_config.c b/src/vf/spp_config.c
new file mode 100644
index 0000000..63b85f2
--- /dev/null
+++ b/src/vf/spp_config.c
@@ -0,0 +1,669 @@
+#include <sys/types.h>
+#include <jansson.h>
+
+#include <rte_log.h>
+
+#include "spp_config.h"
+
+#define CONFIG_CORE_TYPE_CLASSIFIER_MAC "classifier_mac"
+#define CONFIG_CORE_TYPE_MERGE          "merge"
+#define CONFIG_CORE_TYPE_FORWARD        "forward"
+
+#define JSONPATH_CLASSIFIER_TABLE "$.classifier_table"
+#define JSONPATH_PROC_TABLE "$.vfs"
+#define JSONPATH_NAME       "$.name"
+#define JSONPATH_TABLE      "$.table"
+#define JSONPATH_MAC        "$.mac"
+#define JSONPATH_PORT       "$.port"
+#define JSONPATH_NUM_VHOST  "$.num_vhost"
+#define JSONPATH_NUM_RING   "$.num_ring"
+#define JSONPATH_FUNCTIONS  "$.functions"
+#define JSONPATH_CORE_NO    "$.core"
+#define JSONPATH_CORE_TYPE  "$.type"
+#define JSONPATH_RX_PORT    "$.rx_port"
+#define JSONPATH_TX_PORT    "$.tx_port"
+#define JSONPATH_TX_TABLE   "$.tx_port_table"
+
+/*
+ * Get integer data from config
+ */
+static int
+config_get_int_value(const json_t *obj, const char *path, int *value)
+{
+	/* 指定パラメータのJsonオブジェクト取得 */
+	json_t *tmp_obj = json_path_get(obj, path);
+	if (unlikely(tmp_obj == NULL)) {
+		/* 必須でないデータを取得する場合を考慮し、DEBUGログとする。 */
+		RTE_LOG(DEBUG, APP, "No parameter. (path = %s)\n", path);
+		return -1;
+	}
+
+	/* Integer type check */
+	if (unlikely(!json_is_integer(tmp_obj))) {
+		/* 必須でないデータを取得する場合を考慮し、DEBUGログとする。 */
+		RTE_LOG(DEBUG, APP, "Not an integer. (path = %s)\n", path);
+		return -1;
+	}
+
+	/* Set to OUT parameter */
+	*value = json_integer_value(tmp_obj);
+	RTE_LOG(DEBUG, APP, "get value = %d\n", *value);
+	return 0;
+}
+
+/*
+ * Get String data from config
+ */
+static int
+config_get_str_value(const json_t *obj, const char *path, char *value)
+{
+	/* 指定パラメータのJsonオブジェクト取得 */
+	json_t *tmp_obj = json_path_get(obj, path);
+	if (unlikely(tmp_obj == NULL)) {
+		RTE_LOG(DEBUG, APP, "No parameter. (path = %s)\n", path);
+		return -1;
+	}
+
+	/* String type check */
+	if (unlikely(!json_is_string(tmp_obj))) {
+		RTE_LOG(DEBUG, APP, "Not a string. (path = %s)\n", path);
+		return -1;
+	}
+
+	/* Set to OUT parameter */
+	strcpy(value, json_string_value(tmp_obj));
+	RTE_LOG(DEBUG, APP, "get value = %s\n", value);
+	return 0;
+}
+
+/*
+ * コンフィグ情報初期化
+ */
+static void
+config_init_data(struct spp_config_area *config)
+{
+	/* 0クリア */
+	memset(config, 0x00, sizeof(struct spp_config_area));
+	int core_cnt, port_cnt, table_cnt;
+
+	/* IF種別初期設定 */
+	for (core_cnt = 0; core_cnt < SPP_CONFIG_CORE_MAX; core_cnt++) {
+		for (port_cnt = 0; port_cnt < RTE_MAX_ETHPORTS; port_cnt++) {
+			config->proc.functions[core_cnt].rx_ports[port_cnt].if_type = UNDEF;
+			config->proc.functions[core_cnt].tx_ports[port_cnt].if_type = UNDEF;
+		}
+	}
+	for (table_cnt = 0; table_cnt < SPP_CONFIG_MAC_TABLE_MAX; table_cnt++) {
+		config->classifier_table.mac_tables[table_cnt].port.if_type = UNDEF;
+	}
+
+	return;
+}
+
+/*
+ * IFの情報からIF種別とIF番号を取得する
+ * ("ring0" -> 種別:"ring"、番号:0)
+ */
+static int
+config_get_if_info(const char *port, enum port_type *if_type, int *if_no)
+{
+	enum port_type type = UNDEF;
+	const char *no_str = NULL;
+	char *endptr = NULL;
+
+	/* IF type check */
+	if (strncmp(port, SPP_CONFIG_IFTYPE_NIC, strlen(SPP_CONFIG_IFTYPE_NIC)) == 0) {
+		/* NIC */
+		type = PHY;
+		no_str = &port[strlen(SPP_CONFIG_IFTYPE_NIC)];
+	} else if (strncmp(port, SPP_CONFIG_IFTYPE_VHOST, strlen(SPP_CONFIG_IFTYPE_VHOST)) == 0) {
+		/* VHOST */
+		type = VHOST;
+		no_str = &port[strlen(SPP_CONFIG_IFTYPE_VHOST)];
+	} else if (strncmp(port, SPP_CONFIG_IFTYPE_RING, strlen(SPP_CONFIG_IFTYPE_RING)) == 0) {
+		/* RING */
+		type = RING;
+		no_str = &port[strlen(SPP_CONFIG_IFTYPE_RING)];
+	} else {
+		/* OTHER */
+		RTE_LOG(ERR, APP, "Unknown interface type. (port = %s)\n", port);
+		return -1;
+	}
+
+	/* IF番号を文字列から数値変換 */
+	int ret_no = strtol(no_str, &endptr, 0);
+	if (unlikely(no_str == endptr) || unlikely(*endptr != '\0')) { 
+		/* No IF number */
+		RTE_LOG(ERR, APP, "No interface number. (port = %s)\n", port);
+		return -1;
+	}
+
+	/* Set OUT parameter */
+	*if_type = type;
+	*if_no = ret_no;
+
+	RTE_LOG(DEBUG, APP, "Port = %s => Type = %d No = %d\n",
+			port, *if_type, *if_no);
+	return 0;
+}
+
+/*
+ * MAC addressを文字列から数値へ変換
+ */
+int64_t
+config_change_mac_str_to_int64(const char *mac)
+{
+	int64_t ret_mac = 0;
+	int64_t token_val = 0;
+	int token_cnt = 0;
+	char tmp_mac[SPP_CONFIG_STR_LEN];
+	char *str = tmp_mac;
+	char *saveptr = NULL;
+	char *endptr = NULL;
+
+	RTE_LOG(DEBUG, APP, "MAC address change. (mac = %s)\n", mac);
+
+	strcpy(tmp_mac, mac);
+	while(1) {
+		/* Split by clolon(':') */
+		char *ret_tok = strtok_r(str, ":", &saveptr);
+		if (unlikely(ret_tok == NULL)) {
+			break;
+		}
+
+		/* Convert string to hex value */
+		int ret_tol = strtol(ret_tok, &endptr, 16);
+		if (unlikely(ret_tok == endptr) || unlikely(*endptr != '\0')) {
+			break;
+		}
+
+		/* 各数値をまとめる */
+		token_val = (int64_t)ret_tol;
+		ret_mac |= token_val << (token_cnt * 8);
+		token_cnt++;
+		str = NULL;
+	}
+
+	/* 区切り文字が5個以外 */
+	if (unlikely(token_cnt != ETHER_ADDR_LEN)) {
+		RTE_LOG(ERR, APP, "MAC address format error. (mac = %s)\n",
+				 mac);
+		return -1;
+	}
+
+	RTE_LOG(DEBUG, APP, "MAC address change. (mac = %s => 0x%08lx)\n",
+			 mac, ret_mac);
+	return ret_mac;
+}
+
+/*
+ * Classifier table読み込み
+ */
+static int
+config_load_classifier_table(const json_t *obj,
+		struct spp_config_classifier_table *classifier_table)
+{
+	/* classifier_table用オブジェクト取得 */
+	json_t *classifier_obj = json_path_get(obj, JSONPATH_CLASSIFIER_TABLE);
+	if (unlikely(classifier_obj == NULL)) {
+		RTE_LOG(ERR, APP, "Json object get failed. (path = %s)\n",
+				JSONPATH_CLASSIFIER_TABLE);
+		return -1;
+	}
+
+	/* name取得 */
+	int ret_name = config_get_str_value(classifier_obj, JSONPATH_NAME,
+			classifier_table->name);
+	if (unlikely(ret_name != 0)) {
+		RTE_LOG(ERR, APP, "Classifier table name get failed.\n");
+		return -1;
+	}
+
+	/* table用オブジェクト取得 */
+	json_t *array_obj = json_path_get(classifier_obj, JSONPATH_TABLE);
+	if (unlikely(!array_obj)) {
+		RTE_LOG(ERR, APP, "Json object get failed. (path = %s)\n",
+				JSONPATH_TABLE);
+		return -1;
+	}
+
+	/* table用オブジェクトが配列かチェック */
+	if (unlikely(!json_is_array(array_obj))) {
+		RTE_LOG(ERR, APP, "Not an array. (path = %s)\n",
+				JSONPATH_TABLE);
+		return -1;
+	}
+
+	/* table用オブジェクトの要素数取得 */
+	int array_num = json_array_size(array_obj);
+	if (unlikely(array_num <= 0) ||
+			unlikely(array_num >= SPP_CONFIG_MAC_TABLE_MAX)) {
+		RTE_LOG(ERR, APP, "Table size out of range. (path = %s, size = %d)\n",
+				JSONPATH_TABLE, array_num);
+		return -1;
+	}
+	classifier_table->num_table = array_num;
+
+	/* テーブルの各要素毎にデータ取得 */
+	struct spp_config_mac_table_element *tmp_table = NULL;
+	char if_str[SPP_CONFIG_STR_LEN];
+	int table_cnt = 0;
+	for (table_cnt = 0; table_cnt < array_num; table_cnt++) {
+		tmp_table = &classifier_table->mac_tables[table_cnt];
+
+		/* 要素取得 */
+		json_t *elements_obj = json_array_get(array_obj, table_cnt);
+		if (unlikely(elements_obj == NULL)) {
+			RTE_LOG(ERR, APP,
+				"Element get failed. (No = %d, path = %s)\n",
+				table_cnt, JSONPATH_TABLE);
+			return -1;
+		}
+
+		/* MACアドレス(文字列)取得 */
+		int ret_mac = config_get_str_value(elements_obj, JSONPATH_MAC,
+				tmp_table->mac_addr_str);
+		if (unlikely(ret_mac != 0)) {
+			RTE_LOG(ERR, APP,
+				"MAC address get failed. (No = %d, path = %s)\n",
+				table_cnt, JSONPATH_MAC);
+			return -1;
+		}
+
+		/* MACアドレス数値変換 */
+		int64_t ret_mac64 = config_change_mac_str_to_int64(
+				tmp_table->mac_addr_str);
+		if (unlikely(ret_mac64 == -1)) {
+			RTE_LOG(ERR, APP,
+				"MAC address change failed. (No = %d, mac = %s)\n",
+				table_cnt, tmp_table->mac_addr_str);
+			return -1;
+		}
+		tmp_table->mac_addr = ret_mac64;
+
+		/* IF情報取得 */
+		int ret_if_str = config_get_str_value(elements_obj,
+				JSONPATH_PORT, if_str);
+		if (unlikely(ret_if_str != 0)) {
+			RTE_LOG(ERR, APP,
+				"Interface get failed. (No = %d, path = %s)\n",
+				table_cnt, JSONPATH_PORT);
+			return -1;
+		}
+
+		/* IF種別とIF番号に分割 */
+		int ret_if = config_get_if_info(if_str, &tmp_table->port.if_type,
+				&tmp_table->port.if_no);
+		if (unlikely(ret_if != 0)) {
+			RTE_LOG(ERR, APP,
+				"Interface change failed. (No = %d, IF = %s)\n",
+				table_cnt, if_str);
+			return -1;
+		}
+	}
+
+	return 0;
+}
+
+/*
+ * 処理種別を文字列から数値変換
+ */
+static enum spp_core_type
+config_change_core_type(const char *core_type)
+{
+	if(strncmp(core_type, CONFIG_CORE_TYPE_CLASSIFIER_MAC,
+			 strlen(CONFIG_CORE_TYPE_CLASSIFIER_MAC)+1) == 0) {
+		/* Classifier */
+		return SPP_CONFIG_CLASSIFIER_MAC;
+	} else if (strncmp(core_type, CONFIG_CORE_TYPE_MERGE,
+			 strlen(CONFIG_CORE_TYPE_MERGE)+1) == 0) {
+		/* Merge */
+		return SPP_CONFIG_MERGE;
+	} else if (strncmp(core_type, CONFIG_CORE_TYPE_FORWARD,
+			 strlen(CONFIG_CORE_TYPE_FORWARD)+1) == 0) {
+		/* Forward */
+		return SPP_CONFIG_FORWARD;
+	}
+	return SPP_CONFIG_UNUSE;
+}
+
+/*
+ * 受信ポート取得
+ */
+static int
+config_set_rx_port(enum spp_core_type type, json_t *obj,
+		struct spp_config_functions *functions)
+{
+	struct spp_config_port_info *tmp_rx_port = NULL;
+	char if_str[SPP_CONFIG_STR_LEN];
+	if (type == SPP_CONFIG_MERGE) {
+		/* Merge */
+		/* 受信ポート用オブジェクト取得 */
+		json_t *array_obj = json_path_get(obj, JSONPATH_RX_PORT);
+		if (unlikely(!array_obj)) {
+			RTE_LOG(ERR, APP, "Json object get failed. (path = %s, route = merge)\n",
+				JSONPATH_RX_PORT);
+			return -1;
+		}
+
+		/* 受信ポート用オブジェクトが配列かチェック */
+		if (unlikely(!json_is_array(array_obj))) {
+			RTE_LOG(ERR, APP, "Not an array. (path = %s, route = merge)\n",
+				JSONPATH_TABLE);
+			return -1;
+		}
+
+		/* 受信ポート用オブジェクトの要素数取得 */
+		int port_num = json_array_size(array_obj);
+		if (unlikely(port_num <= 0) ||
+				unlikely(port_num >= RTE_MAX_ETHPORTS)) {
+			RTE_LOG(ERR, APP, "RX port out of range. (path = %s, port = %d, route = merge)\n",
+					JSONPATH_RX_PORT, port_num);
+			return -1;
+		}
+		functions->num_rx_port = port_num;
+
+		/* 要素毎にデータ取得 */
+		int array_cnt = 0;
+		for (array_cnt = 0; array_cnt < port_num; array_cnt++) {
+			tmp_rx_port = &functions->rx_ports[array_cnt];
+
+			/* 要素取得 */
+			json_t *elements_obj = json_array_get(array_obj, array_cnt);
+			if (unlikely(elements_obj == NULL)) {
+				RTE_LOG(ERR, APP,
+					"Element get failed. (No = %d, path = %s, route = merge)\n",
+					array_cnt, JSONPATH_RX_PORT);
+				return -1;
+			}
+
+			/* String type check */
+			if (unlikely(!json_is_string(elements_obj))) {
+				RTE_LOG(ERR, APP, "Not a string. (path = %s, No = %d, route = merge)\n",
+						JSONPATH_RX_PORT, array_cnt);
+				return -1;
+			}
+			strcpy(if_str, json_string_value(elements_obj));
+
+			/* IF種別とIF番号に分割 */
+			int ret_if = config_get_if_info(if_str, &tmp_rx_port->if_type,
+					&tmp_rx_port->if_no);
+			if (unlikely(ret_if != 0)) {
+				RTE_LOG(ERR, APP,
+					"Interface change failed. (No = %d, port = %s, route = merge)\n",
+					array_cnt, if_str);
+				return -1;
+			}
+		}
+	} else {
+		/* Classifier/Forward */
+		tmp_rx_port = &functions->rx_ports[0];
+		functions->num_rx_port = 1;
+
+		/* 受信ポート取得 */
+		int ret_rx_port = config_get_str_value(obj, JSONPATH_RX_PORT, if_str);
+		if (unlikely(ret_rx_port != 0)) {
+			RTE_LOG(ERR, APP, "RX port get failed.\n");
+			return -1;
+		}
+
+		/* IF種別とIF番号に分割 */
+		int ret_if = config_get_if_info(if_str, &tmp_rx_port->if_type,
+				&tmp_rx_port->if_no);
+		if (unlikely(ret_if != 0)) {
+			RTE_LOG(ERR, APP,
+				"Interface change failed. (port = %s)\n", if_str);
+			return -1;
+		}
+	}
+
+	return 0;
+}
+
+/*
+ * 送信先ポート情報取得
+ */
+static int
+config_set_tx_port(enum spp_core_type type, json_t *obj,
+		struct spp_config_functions *functions,
+		struct spp_config_classifier_table *classifier_table)
+{
+	struct spp_config_port_info *tmp_tx_port = NULL;
+	char if_str[SPP_CONFIG_STR_LEN];
+	if ((type == SPP_CONFIG_MERGE) || (type == SPP_CONFIG_FORWARD)) {
+		/* Merge or Forward */
+		tmp_tx_port = &functions->tx_ports[0];
+		functions->num_tx_port = 1;
+
+		/* 送信ポート取得 */
+		int ret_tx_port = config_get_str_value(obj,
+				JSONPATH_TX_PORT, if_str);
+		if (unlikely(ret_tx_port != 0)) {
+			RTE_LOG(ERR, APP, "TX port get failed.\n");
+			return -1;
+		}
+
+		/* IF種別とIF番号に分割 */
+		int ret_if = config_get_if_info(if_str, &tmp_tx_port->if_type,
+				&tmp_tx_port->if_no);
+		if (unlikely(ret_if != 0)) {
+			RTE_LOG(ERR, APP,
+				"Interface change failed. (port = %s)\n",
+				if_str);
+			return -1;
+		}
+	} else {
+		/* Classifier */
+		int cnt = 0;
+		functions->num_tx_port = classifier_table->num_table;
+		struct spp_config_mac_table_element *tmp_mac_table = NULL;
+		for (cnt = 0; cnt < classifier_table->num_table; cnt++) {
+			tmp_tx_port = &functions->tx_ports[cnt];
+			tmp_mac_table = &classifier_table->mac_tables[cnt];
+
+			/* MAC振り分けテーブルより設定 */
+			tmp_tx_port->if_type = tmp_mac_table->port.if_type;
+			tmp_tx_port->if_no   = tmp_mac_table->port.if_no;
+		}
+	}
+
+	return 0;
+}
+
+/*
+ * プロセス情報取得
+ */
+static int
+config_load_proc_info(const json_t *obj, int node_id, struct spp_config_area *config)
+{
+	struct spp_config_proc_info *proc = &config->proc;
+	struct spp_config_classifier_table *classifier_table = &config->classifier_table;
+
+	/* proc_table用オブジェクト取得 */
+	json_t *proc_table_obj = json_path_get(obj, JSONPATH_PROC_TABLE);
+	if (unlikely(proc_table_obj == NULL)) {
+		RTE_LOG(ERR, APP, "Json object get failed. (path = %s)\n",
+				JSONPATH_PROC_TABLE);
+		return -1;
+	}
+
+	/* table用オブジェクトが配列かチェック */
+	if (unlikely(!json_is_array(proc_table_obj))) {
+		RTE_LOG(ERR, APP, "Not an array. (path = %s)\n",
+				JSONPATH_TABLE);
+		return -1;
+	}
+
+	/* table用オブジェクトの要素数取得 */
+	int proc_table_num = json_array_size(proc_table_obj);
+	if (unlikely(proc_table_num < node_id)) {
+		RTE_LOG(ERR, APP, "No process data. (Size = %d, Node = %d)\n",
+			proc_table_num, node_id);
+		return -1;
+	}
+
+	/* 要素取得 */
+	json_t *proc_obj = json_array_get(proc_table_obj, node_id);
+	if (unlikely(proc_obj == NULL)) {
+		RTE_LOG(ERR, APP, "Process data get failed. (Node = %d)\n",
+				node_id);
+		return -1;
+	}
+
+	/* name取得 */
+	int ret_name = config_get_str_value(proc_obj, JSONPATH_NAME, proc->name);
+	if (unlikely(ret_name != 0)) {
+		RTE_LOG(ERR, APP, "Process name get failed.\n");
+		return -1;
+	}
+
+	/* VHOST数取得 */
+	int ret_vhost = config_get_int_value(proc_obj, JSONPATH_NUM_VHOST,
+			&proc->num_vhost);
+	if (unlikely(ret_vhost != 0)) {
+		RTE_LOG(ERR, APP, "VHOST number get failed.\n");
+		return -1;
+	}
+
+	/* RING数取得 */
+	int ret_ring = config_get_int_value(proc_obj, JSONPATH_NUM_RING,
+			&proc->num_ring);
+	if (unlikely(ret_ring != 0)) {
+		RTE_LOG(ERR, APP, "RING number get failed.\n");
+		return -1;
+	}
+
+	/* functions用オブジェクト取得 */
+	json_t *array_obj = json_path_get(proc_obj, JSONPATH_FUNCTIONS);
+	if (unlikely(!array_obj)) {
+		RTE_LOG(ERR, APP, "Json object get failed. (path = %s)\n",
+				JSONPATH_FUNCTIONS);
+		return -1;
+	}
+
+	/* functions用オブジェクトが配列かチェック */
+	if (unlikely(!json_is_array(array_obj))) {
+		RTE_LOG(ERR, APP, "Not an array. (path = %s)\n",
+				JSONPATH_FUNCTIONS);
+		return -1;
+	}
+
+	/* functions用オブジェクトの要素数取得 */
+	int array_num = json_array_size(array_obj);
+	if (unlikely(array_num <= 0) ||
+			unlikely(array_num >= SPP_CONFIG_CORE_MAX)) {
+		RTE_LOG(ERR, APP, "Functions size out of range. (path = %s, size = %d)\n",
+				JSONPATH_TABLE, array_num);
+		return -1;
+	}
+	proc->num_func = array_num;
+
+	/* 要素毎にデータ取得 */
+	struct spp_config_functions *tmp_functions = NULL;
+	char core_type_str[SPP_CONFIG_STR_LEN];
+	int array_cnt = 0;
+	for (array_cnt = 0; array_cnt < array_num; array_cnt++) {
+		tmp_functions = &proc->functions[array_cnt];
+
+		/* 要素取得 */
+		json_t *elements_obj = json_array_get(array_obj, array_cnt);
+		if (unlikely(elements_obj == NULL)) {
+			RTE_LOG(ERR, APP,
+				"Element get failed. (No = %d, path = %s)\n",
+				array_cnt, JSONPATH_FUNCTIONS);
+			return -1;
+		}
+
+		/* CORE番号取得 */
+		int ret_core = config_get_int_value(elements_obj, JSONPATH_CORE_NO,
+				&tmp_functions->core_no);
+		if (unlikely(ret_core != 0)) {
+			RTE_LOG(ERR, APP, "Core number get failed. (No = %d)\n",
+					array_cnt);
+			return -1;
+		}
+
+		/* 処理種別取得 */
+		int ret_core_type = config_get_str_value(elements_obj,
+				 JSONPATH_CORE_TYPE, core_type_str);
+		if (unlikely(ret_core_type != 0)) {
+			RTE_LOG(ERR, APP, "Core type get failed. (No = %d)\n",
+					array_cnt);
+			return -1;
+		}
+
+		/* 処理種別を数値に変換 */
+		enum spp_core_type core_type = config_change_core_type(core_type_str);
+		if (unlikely(core_type == SPP_CONFIG_UNUSE)) {
+			RTE_LOG(ERR, APP,
+				"Unknown core type. (No = %d, type = %s)\n",
+				array_cnt, core_type_str);
+			return -1;
+		}
+		tmp_functions->type = core_type;
+
+		/* 受信ポート取得 */
+		int ret_rx_port = config_set_rx_port(core_type, elements_obj,
+				tmp_functions);
+		if (unlikely(ret_rx_port != 0)) {
+			RTE_LOG(ERR, APP, "RX port set failure. (No = %d)\n",
+					array_cnt);
+			return -1;
+		}
+
+		/* 送信ポート取得 */
+		int ret_tx_port = config_set_tx_port(core_type, elements_obj,
+				tmp_functions, classifier_table);
+		if (unlikely(ret_tx_port != 0)) {
+			RTE_LOG(ERR, APP, "TX port set failure. (No = %d)\n",
+					array_cnt);
+			return -1;
+		}
+	}
+
+	return 0;
+}
+
+/*
+ * Load config file
+ * OK : 0
+ * NG : -1
+ */
+int
+spp_config_load_file(int node_id, struct spp_config_area *config)
+{
+	/* Config initialize */
+	config_init_data(config);
+	
+	/* Config load */
+	json_error_t json_error;
+	json_t *conf_obj = json_load_file(SPP_CONFIG_FILE_PATH, 0, &json_error);
+	if (unlikely(conf_obj == NULL)) {
+		/* Load error */
+		RTE_LOG(ERR, APP, "Config load failed. (path = %s, text = %s)\n",
+				 SPP_CONFIG_FILE_PATH, json_error.text);
+		return -1;
+	}
+
+	/* classifier table */
+	int ret_classifier = config_load_classifier_table(conf_obj,
+			&config->classifier_table);
+	if (unlikely(ret_classifier != 0)) {
+		RTE_LOG(ERR, APP, "Classifier table load failed.\n");
+		json_decref(conf_obj);
+		return -1;
+	}
+
+	/* proc info */
+	int ret_proc = config_load_proc_info(conf_obj, node_id, config);
+	if (unlikely(ret_proc != 0)) {
+		RTE_LOG(ERR, APP, "Process table load failed.\n");
+		json_decref(conf_obj);
+		return -1;
+	}
+
+	/* Config object release */
+	json_decref(conf_obj);
+
+	return 0;
+}
diff --git a/src/vf/spp_config.h b/src/vf/spp_config.h
new file mode 100644
index 0000000..d2a6a4b
--- /dev/null
+++ b/src/vf/spp_config.h
@@ -0,0 +1,90 @@
+#ifndef __SPP_CONFIG_H__
+#define __SPP_CONFIG_H__
+
+#include "common.h"
+
+#define SPP_CONFIG_FILE_PATH "/usr/local/etc/spp/spp.json"
+
+#define SPP_CONFIG_IFTYPE_NIC   "nic"
+#define SPP_CONFIG_IFTYPE_VHOST "vhost"
+#define SPP_CONFIG_IFTYPE_RING  "ring"
+
+#define SPP_CONFIG_STR_LEN 32
+#define SPP_CONFIG_MAC_TABLE_MAX 16
+#define SPP_CONFIG_CORE_MAX 64
+
+/*
+ * Process type for each CORE
+ */
+enum spp_core_type {
+	SPP_CONFIG_UNUSE,
+	SPP_CONFIG_CLASSIFIER_MAC,
+	SPP_CONFIG_MERGE,
+	SPP_CONFIG_FORWARD,
+};
+
+/*
+ * Interface information structure
+ */
+struct spp_config_port_info {
+	enum port_type	if_type;
+	int		if_no;
+};
+
+/*
+ * MAC Table information structure
+ */
+struct spp_config_mac_table_element {
+	struct		spp_config_port_info port;
+	char		mac_addr_str[SPP_CONFIG_STR_LEN];
+	uint64_t	mac_addr;
+};
+
+/*
+ * Classifier Table information structure
+ */
+struct spp_config_classifier_table {
+	char	name[SPP_CONFIG_STR_LEN];
+	int	num_table;
+	struct spp_config_mac_table_element mac_tables[SPP_CONFIG_MAC_TABLE_MAX];
+};
+
+/*
+ * Functions information structure
+ */
+struct spp_config_functions {
+	int	core_no;
+	enum	spp_core_type type;
+	int	num_rx_port;
+	int	num_tx_port;
+	struct spp_config_port_info rx_ports[RTE_MAX_ETHPORTS];
+	struct spp_config_port_info tx_ports[RTE_MAX_ETHPORTS];
+};
+
+/*
+ * Process information structure
+ */
+struct spp_config_proc_info {
+	char	name[SPP_CONFIG_STR_LEN];
+	int	num_vhost;
+	int	num_ring;
+	int	num_func;
+	struct spp_config_functions functions[SPP_CONFIG_CORE_MAX];
+};
+
+/*
+ * Config information structure
+ */
+struct spp_config_area {
+	struct spp_config_proc_info proc;
+	struct spp_config_classifier_table classifier_table;
+};
+
+/*
+ * Load config file
+ * OK : 0
+ * NG : -1
+ */
+int spp_config_load_file(int node_id, struct spp_config_area *config);
+
+#endif /* __SPP_CONFIG_H__ */
diff --git a/src/vf/spp_forward.c b/src/vf/spp_forward.c
new file mode 100644
index 0000000..4396929
--- /dev/null
+++ b/src/vf/spp_forward.c
@@ -0,0 +1,106 @@
+#include "spp_vf.h"
+#include "ringlatencystats.h"
+
+#define RTE_LOGTYPE_SPP_FORWARD RTE_LOGTYPE_USER1
+
+/*
+ * 送受信ポートの経路情報
+ */
+struct rxtx {
+	struct spp_core_port_info rx;
+	struct spp_core_port_info tx;
+};
+
+/*
+ * 使用するIF情報を移し替える
+ */
+void
+set_use_interface(struct spp_core_port_info *dst,
+		struct spp_core_port_info *src)
+{
+	dst->if_type   = src->if_type;
+	dst->if_no     = src->if_no;
+	dst->dpdk_port = src->dpdk_port;
+}
+
+/*
+ * Merge/Forward
+ */
+int
+spp_forward(void *arg)
+{
+	unsigned int lcore_id = rte_lcore_id();
+	struct spp_core_info *core_info = (struct spp_core_info *)arg;
+	int if_cnt, rxtx_num = 0;
+	struct rxtx patch[RTE_MAX_ETHPORTS];
+
+	/* RX/TX Info setting */
+	rxtx_num = core_info->num_rx_port;
+	for (if_cnt = 0; if_cnt < rxtx_num; if_cnt++) {
+		set_use_interface(&patch[if_cnt].rx,
+				&core_info->rx_ports[if_cnt]);
+		if (core_info->type == SPP_CONFIG_FORWARD) {
+			/* FORWARD */
+			set_use_interface(&patch[if_cnt].tx,
+					&core_info->tx_ports[if_cnt]);
+		} else {
+			/* MERGE */
+			set_use_interface(&patch[if_cnt].tx,
+					&core_info->tx_ports[0]);
+		}
+	}
+
+	/* Thread IDLE */
+	core_info->status = SPP_CORE_IDLE;
+	RTE_LOG(INFO, FORWARD, "Core[%d] Start. (type = %d)\n", lcore_id,
+			core_info->type);
+
+	int cnt, nb_rx, nb_tx, buf;
+	struct spp_core_port_info *rx;
+	struct spp_core_port_info *tx;
+	struct rte_mbuf *bufs[MAX_PKT_BURST];
+	while (likely(core_info->status == SPP_CORE_IDLE) ||
+			likely(core_info->status == SPP_CORE_FORWARD)) {
+		while (likely(core_info->status == SPP_CORE_FORWARD)) {
+			for (cnt = 0; cnt < rxtx_num; cnt++) {
+				rx = &patch[cnt].rx;
+				tx = &patch[cnt].tx;
+
+				/* Packet receive */
+				nb_rx = rte_eth_rx_burst(rx->dpdk_port, 0, bufs, MAX_PKT_BURST);
+				if (unlikely(nb_rx == 0)) {
+					continue;
+				}
+
+#ifdef SPP_RINGLATENCYSTATS_ENABLE /* RING滞留時間 */
+				if (rx->if_type == RING) {
+					/* Receive port is RING */
+					spp_ringlatencystats_calculate_latency(rx->if_no,
+							bufs, nb_rx);
+				}
+				if (tx->if_type == RING) {
+					/* Send port is RING */
+					spp_ringlatencystats_add_time_stamp(tx->if_no,
+							bufs, nb_rx);
+				}
+#endif /* SPP_RINGLATENCYSTATS_ENABLE */
+
+				/* Send packet */
+				nb_tx = rte_eth_tx_burst(tx->dpdk_port, 0, bufs, nb_rx);
+
+				/* Free any unsent packets. */
+				if (unlikely(nb_tx < nb_rx)) {
+					for (buf = nb_tx; buf < nb_rx; buf++) {
+						rte_pktmbuf_free(bufs[buf]);
+					}
+				}
+			}
+		}
+	}
+
+	/* Thread STOP */
+	RTE_LOG(INFO, FORWARD, "Core[%d] End. (type = %d)\n", lcore_id,
+			core_info->type);
+	core_info->status = SPP_CORE_STOP;
+	return 0;
+}
diff --git a/src/vf/spp_forward.h b/src/vf/spp_forward.h
new file mode 100644
index 0000000..33208bf
--- /dev/null
+++ b/src/vf/spp_forward.h
@@ -0,0 +1,9 @@
+#ifndef __SPP_FORWARD_H__
+#define __SPP_FORWARD_H__
+
+/*
+ * Merge/Forward
+ */
+int spp_forward(void *arg);
+
+#endif /* __SPP_FORWARD_H__ */
diff --git a/src/vf/spp_vf.c b/src/vf/spp_vf.c
new file mode 100644
index 0000000..ee5cf63
--- /dev/null
+++ b/src/vf/spp_vf.c
@@ -0,0 +1,794 @@
+#include <arpa/inet.h>
+#include <getopt.h>
+
+#include <rte_eth_ring.h>
+#include <rte_eth_vhost.h>
+#include <rte_memzone.h>
+
+#include "spp_vf.h"
+#include "ringlatencystats.h"
+#include "classifier_mac.h"
+#include "spp_forward.h"
+
+/* define */
+#define SPP_CORE_STATUS_CHECK_MAX 5
+#define SPP_RING_LATENCY_STATS_SAMPLING_INTERVAL 1000000
+
+/* struct */
+struct startup_param {
+	uint64_t cpu;
+};
+
+struct patch_info {
+	int	use_flg;
+	int	dpdk_port;
+	struct spp_config_mac_table_element *mac_info;
+	struct spp_core_port_info *rx_core;
+	struct spp_core_port_info *tx_core;
+};
+
+struct if_info {
+	int num_nic;
+	int num_vhost;
+	int num_ring;
+	struct patch_info nic_patchs[RTE_MAX_ETHPORTS];
+	struct patch_info vhost_patchs[RTE_MAX_ETHPORTS];
+	struct patch_info ring_patchs[RTE_MAX_ETHPORTS];
+};
+
+static struct spp_config_area	g_config;
+static struct startup_param	g_startup_param;
+static struct if_info		g_if_info;
+static struct spp_core_info	g_core_info[SPP_CONFIG_CORE_MAX];
+
+/*
+ * print a usage message
+ */
+static void
+usage(const char *progname)
+{
+	RTE_LOG(INFO, APP, "Usage: %s [EAL args]\n\n", progname);
+}
+
+/*
+ * Set RING PMD
+ */
+static int
+add_ring_pmd(int ring_id)
+{
+	struct rte_ring *ring;
+	int ring_port_id;
+
+	/* look up ring, based on user's provided id*/
+	ring = rte_ring_lookup(get_rx_queue_name(ring_id));
+	if (unlikely(ring == NULL)) {
+		RTE_LOG(ERR, APP,
+			"Cannot get RX ring - is server process running?\n");
+		return -1;
+	}
+
+	/* create ring pmd*/
+	ring_port_id = rte_eth_from_ring(ring);
+	RTE_LOG(DEBUG, APP, "ring port id %d\n", ring_port_id);
+
+	return ring_port_id;
+}
+
+/*
+ * Set VHOST PMD
+ */
+static int
+add_vhost_pmd(int index)
+{
+	struct rte_eth_conf port_conf = {
+		.rxmode = { .max_rx_pkt_len = ETHER_MAX_LEN }
+	};
+	struct rte_mempool *mp;
+	uint8_t vhost_port_id;
+	int nr_queues = 1;
+	const char *name;
+	char devargs[64];
+	char *iface;
+	uint16_t q;
+	int ret;
+#define NR_DESCS 128
+
+	mp = rte_mempool_lookup(PKTMBUF_POOL_NAME);
+	if (unlikely(mp == NULL)) {
+		RTE_LOG(ERR, APP, "Cannot get mempool for mbufs. (name = %s)\n",
+				PKTMBUF_POOL_NAME);
+		return -1;
+	}
+
+	/* eth_vhost0 index 0 iface /tmp/sock0 on numa 0 */
+	name = get_vhost_backend_name(index);
+	iface = get_vhost_iface_name(index);
+
+	sprintf(devargs, "%s,iface=%s,queues=%d", name, iface, nr_queues);
+	ret = rte_eth_dev_attach(devargs, &vhost_port_id);
+	if (unlikely(ret < 0)) {
+		RTE_LOG(ERR, APP, "rte_eth_dev_attach error. (ret = %d)\n", ret);
+		return ret;
+	}
+
+	ret = rte_eth_dev_configure(vhost_port_id, nr_queues, nr_queues,
+		&port_conf);
+	if (unlikely(ret < 0)) {
+		RTE_LOG(ERR, APP, "rte_eth_dev_configure error. (ret = %d)\n",
+				ret);
+		return ret;
+	}
+
+	/* Allocate and set up 1 RX queue per Ethernet port. */
+	for (q = 0; q < nr_queues; q++) {
+		ret = rte_eth_rx_queue_setup(vhost_port_id, q, NR_DESCS,
+			rte_eth_dev_socket_id(vhost_port_id), NULL, mp);
+		if (unlikely(ret < 0)) {
+			RTE_LOG(ERR, APP,
+				"rte_eth_rx_queue_setup error. (ret = %d)\n",
+				ret);
+			return ret;
+		}
+	}
+
+	/* Allocate and set up 1 TX queue per Ethernet port. */
+	for (q = 0; q < nr_queues; q++) {
+		ret = rte_eth_tx_queue_setup(vhost_port_id, q, NR_DESCS,
+			rte_eth_dev_socket_id(vhost_port_id), NULL);
+		if (unlikely(ret < 0)) {
+			RTE_LOG(ERR, APP,
+				"rte_eth_tx_queue_setup error. (ret = %d)\n",
+				ret);
+			return ret;
+		}
+	}
+
+	/* Start the Ethernet port. */
+	ret = rte_eth_dev_start(vhost_port_id);
+	if (unlikely(ret < 0)) {
+		RTE_LOG(ERR, APP, "rte_eth_dev_start error. (ret = %d)\n", ret);
+		return ret;
+	}
+
+	RTE_LOG(DEBUG, APP, "vhost port id %d\n", vhost_port_id);
+
+	return vhost_port_id;
+}
+
+/*
+ * Check core status
+ */
+static int
+check_core_status(enum spp_core_status status)
+{
+	int cnt;
+	for (cnt = 0; cnt < SPP_CONFIG_CORE_MAX; cnt++) {
+		if (g_core_info[cnt].type == SPP_CONFIG_UNUSE) {
+			continue;
+		}
+		if (g_core_info[cnt].status != status) {
+			/* Status mismatch */
+			return -1;
+		}
+	}
+	return 0;
+}
+
+/*
+ * Wait for core status check
+ */
+static int
+check_core_status_wait(enum spp_core_status status)
+{
+	int cnt = 0;
+	for (cnt = 0; cnt < SPP_CORE_STATUS_CHECK_MAX; cnt++) {
+		sleep(1);
+		int ret = check_core_status(status);
+		if (ret == 0) {
+			return 0;
+		}
+	}
+
+	RTE_LOG(ERR, APP, "Status check time out. (status = %d)\n", status);
+	return -1;
+}
+
+/*
+ * Set core status
+ */
+static void
+set_core_status(enum spp_core_status status)
+{
+	int core_cnt = 0;
+	for(core_cnt = 0; core_cnt < SPP_CONFIG_CORE_MAX; core_cnt++) {
+		g_core_info[core_cnt].status = status;
+	}
+}
+
+/*
+ * Process stop
+ */
+void
+stop_process(int signal) {
+	if (unlikely(signal != SIGTERM) &&
+			unlikely(signal != SIGINT)) {
+		/* Other signals */
+		return;
+	}
+
+	set_core_status(SPP_CORE_STOP_REQUEST);
+}
+
+/*
+ * 起動パラメータのCPUのbitmapを数値へ変換
+ */
+static int
+parse_cpu_bit(uint64_t *cpu, const char *cpu_bit)
+{
+	char *endptr = NULL;
+	uint64_t temp;
+
+	temp = strtoull(cpu_bit, &endptr, 0);
+	if (unlikely(endptr == cpu_bit) || unlikely(*endptr != '\0')) {
+		return -1;
+	}
+
+	*cpu = temp;
+	RTE_LOG(DEBUG, APP, "cpu = %lu", *cpu);
+	return 0;
+}
+
+/*
+ * Parse the application arguments to the client app.
+ */
+static int
+parse_app_args(int argc, char *argv[])
+{
+	int option_index, opt;
+	char **argvopt = argv;
+	const char *progname = argv[0];
+	static struct option lgopts[] = { {0} };
+
+	/* Check DPDK parameter */
+	optind = 0;
+	opterr = 0;
+	while ((opt = getopt_long(argc, argvopt, "c:", lgopts,
+			&option_index)) != EOF) {
+		switch (opt) {
+		case 'c':
+			/* CPU */
+			if (parse_cpu_bit(&g_startup_param.cpu, optarg) != 0) {
+				usage(progname);
+				return -1;
+			}
+			break;
+		default:
+			/* CPU */
+			/* DPDKのパラメータは他にもあるので、エラーとはしない */
+			break;
+		}
+	}
+
+	return 0;
+}
+
+/*
+ * IF種別&IF番号のIF情報の領域取得
+ */
+static struct patch_info *
+get_if_area(enum port_type if_type, int if_no)
+{
+	switch (if_type) {
+	case PHY:
+		return &g_if_info.nic_patchs[if_no];
+		break;
+	case VHOST:
+		return &g_if_info.vhost_patchs[if_no];
+		break;
+	case RING:
+		return &g_if_info.ring_patchs[if_no];
+		break;
+	default:
+		/* エラー出力は呼び元でチェック */
+		return NULL;
+		break;
+	}
+}
+
+/*
+ * IF情報初期化
+ */
+static void
+init_if_info()
+{
+	memset(&g_if_info, 0x00, sizeof(g_if_info));
+}
+
+/*
+ * CORE情報初期化
+ */
+static void
+init_core_info()
+{
+	memset(&g_core_info, 0x00, sizeof(g_core_info));
+	int core_cnt, port_cnt;
+	for (core_cnt = 0; core_cnt < SPP_CONFIG_CORE_MAX; core_cnt++) {
+		for (port_cnt = 0; port_cnt < RTE_MAX_ETHPORTS; port_cnt++) {
+			g_core_info[core_cnt].rx_ports[port_cnt].if_type = UNDEF;
+			g_core_info[core_cnt].tx_ports[port_cnt].if_type = UNDEF;
+		}
+	}
+}
+
+/*
+ * Configのプロセス情報から管理情報に設定
+ */
+static int
+set_form_proc_info(struct spp_config_area *config)
+{
+	/* Configのproc_infoから内部管理情報へ設定 */
+	int core_cnt, rx_start, rx_cnt, tx_start, tx_cnt;
+	enum port_type if_type;
+	int if_no;
+	int64_t cpu_bit = 0;
+	struct spp_config_functions *core_func = NULL;
+	struct spp_core_info *core_info = NULL;
+	struct patch_info *patch_info = NULL;
+	for (core_cnt = 0; core_cnt < config->proc.num_func; core_cnt++) {
+		core_func = &config->proc.functions[core_cnt];
+		core_info = &g_core_info[core_func->core_no];
+
+		if (core_func->type == SPP_CONFIG_UNUSE) {
+			continue;
+		}
+
+		/* Forwardをまとめる事は可、他種別は不可 */
+		if ((core_info->type != SPP_CONFIG_UNUSE) &&
+				((core_info->type != SPP_CONFIG_FORWARD) &&
+				(core_func->type != SPP_CONFIG_FORWARD))) {
+			RTE_LOG(ERR, APP, "Core in use. (core = %d, type = %d/%d)\n",
+					core_func->core_no,
+					core_func->type, core_info->type);
+			return -1;
+		}
+
+		/* Set CORE type */
+		core_info->type = core_func->type;
+		cpu_bit |= 1 << core_func->core_no;
+
+		/* Set RX port */
+		rx_start = core_info->num_rx_port;
+		core_info->num_rx_port += core_func->num_rx_port;
+		for (rx_cnt = 0; rx_cnt < core_func->num_rx_port; rx_cnt++) {
+			if_type = core_func->rx_ports[rx_cnt].if_type;
+			if_no   = core_func->rx_ports[rx_cnt].if_no;
+
+			core_info->rx_ports[rx_start + rx_cnt].if_type = if_type;
+			core_info->rx_ports[rx_start + rx_cnt].if_no   = if_no;
+
+			/* IF種別とIF番号に対応するIF情報の領域取得 */
+			patch_info = get_if_area(if_type, if_no);
+
+			patch_info->use_flg = 1;
+			if (unlikely(patch_info->rx_core != NULL)) {
+				RTE_LOG(ERR, APP, "Used RX port (if_type = %d, if_no = %d)\n",
+						if_type, if_no);
+				return -1;
+			}
+
+			/* IF情報からCORE情報を変更する場合用に設定 */
+			patch_info->rx_core = &core_info->rx_ports[rx_start + rx_cnt];
+		}
+
+		/* Set TX port */
+		tx_start = core_info->num_tx_port;
+		core_info->num_tx_port += core_func->num_tx_port;
+		for (tx_cnt = 0; tx_cnt < core_func->num_tx_port; tx_cnt++) {
+			if_type = core_func->tx_ports[tx_cnt].if_type;
+			if_no   = core_func->tx_ports[tx_cnt].if_no;
+
+			core_info->tx_ports[tx_start + tx_cnt].if_type = if_type;
+			core_info->tx_ports[tx_start + tx_cnt].if_no   = if_no;
+
+			/* IF種別とIF番号に対応するIF情報の領域取得 */
+			patch_info = get_if_area(if_type, if_no);
+
+			patch_info->use_flg = 1;
+			if (unlikely(patch_info->tx_core != NULL)) {
+				RTE_LOG(ERR, APP, "Used TX port (if_type = %d, if_no = %d)\n",
+						if_type, if_no);
+				return -1;
+			}
+
+			/* IF情報からCORE情報を変更する場合用に設定 */
+			patch_info->tx_core = &core_info->tx_ports[tx_start + tx_cnt];
+		}
+	}
+
+	if (unlikely((cpu_bit & g_startup_param.cpu) != cpu_bit)) {
+		/* CPU mismatch */
+		RTE_LOG(ERR, APP, "CPU mismatch (cpu param = %lx, config = %lx)\n",
+				g_startup_param.cpu, cpu_bit);
+		return -1;
+	}
+	return 0;
+}
+
+/*
+ * ConfigのMACテーブル情報から管理情報に設定
+ */
+static int
+set_from_classifier_table(struct spp_config_area *config)
+{
+	/* MAC table */
+	enum port_type if_type;
+	int if_no = 0;
+	int mac_cnt = 0;
+	struct spp_config_mac_table_element *mac_table = NULL;
+	struct patch_info *patch_info = NULL;
+	for (mac_cnt = 0; mac_cnt < config->classifier_table.num_table; mac_cnt++) {
+		mac_table = &config->classifier_table.mac_tables[mac_cnt];
+
+		if_type = mac_table->port.if_type;
+		if_no   = mac_table->port.if_no;
+
+		/* IF種別とIF番号に対応するIF情報の領域取得 */
+		patch_info = get_if_area(if_type, if_no);
+
+		if (unlikely(patch_info->use_flg == 0)) {
+			RTE_LOG(ERR, APP, "Not used interface (if_type = %d, if_no = %d)\n",
+					if_type, if_no);
+			return -1;
+		}
+
+		/* CORE情報側にもMACアドレスの情報設定 */
+		/* MACアドレスは送信側のみに影響する為、送信側のみ設定 */
+		patch_info->mac_info = mac_table;
+		if (unlikely(patch_info->tx_core != NULL)) {
+			patch_info->tx_core->mac_addr = mac_table->mac_addr;
+			strcpy(patch_info->tx_core->mac_addr_str, mac_table->mac_addr_str);
+		}
+	}
+	return 0;
+}
+
+/*
+ * NIC用の情報設定
+ */
+static int
+set_nic_interface(struct spp_config_area *config)
+{
+	/* NIC Setting */
+	g_if_info.num_nic = rte_eth_dev_count();
+	if (g_if_info.num_nic > RTE_MAX_ETHPORTS) {
+		g_if_info.num_nic = RTE_MAX_ETHPORTS;
+	}
+
+	int nic_cnt, nic_num = 0;
+	struct patch_info *patch_info = NULL;
+	for (nic_cnt = 0; nic_cnt < RTE_MAX_ETHPORTS; nic_cnt++) {
+		patch_info = &g_if_info.nic_patchs[nic_cnt];
+		/* Set DPDK port */
+		patch_info->dpdk_port = nic_cnt;
+
+		if (patch_info->use_flg == 0) {
+			/* Not Used */
+			continue;
+		}
+
+		/* CORE情報側にもDPDKポート番号の情報設定 */
+		if (patch_info->rx_core != NULL) {
+			patch_info->rx_core->dpdk_port = nic_cnt;
+		}
+		if (patch_info->tx_core != NULL) {
+			patch_info->tx_core->dpdk_port = nic_cnt;
+		}
+
+		/* NICの設定数カウント */
+		nic_num++;
+	}
+
+	if (unlikely(nic_num > g_if_info.num_nic)) {
+		RTE_LOG(ERR, APP, "NIC Setting mismatch. (IF = %d, config = %d)\n",
+				nic_num, g_if_info.num_nic);
+		return -1;
+	}
+	
+	return 0;
+}
+
+/*
+ * VHOST用の情報設定
+ */
+static int
+set_vhost_interface(struct spp_config_area *config)
+{
+	/* VHOST Setting */
+	int vhost_cnt, vhost_num = 0;
+	g_if_info.num_vhost = config->proc.num_vhost;
+	struct patch_info *patch_info = NULL;
+	for (vhost_cnt = 0; vhost_cnt < RTE_MAX_ETHPORTS; vhost_cnt++) {
+		patch_info = &g_if_info.vhost_patchs[vhost_cnt];
+		if (patch_info->use_flg == 0) {
+			/* Not Used */
+			continue;
+		}
+
+		/* Set DPDK port */
+		int dpdk_port = add_vhost_pmd(vhost_cnt);
+		if (unlikely(dpdk_port < 0)) {
+			RTE_LOG(ERR, APP, "VHOST add failed. (no = %d)\n",
+					vhost_cnt);
+			return -1;
+		}
+		patch_info->dpdk_port = dpdk_port;
+
+		/* CORE情報側にもDPDKポート番号の情報設定 */
+		if (patch_info->rx_core != NULL) {
+			patch_info->rx_core->dpdk_port = dpdk_port;
+		}
+		if (patch_info->tx_core != NULL) {
+			patch_info->tx_core->dpdk_port = dpdk_port;
+		}
+		vhost_num++;
+	}
+	if (unlikely(vhost_num > g_if_info.num_vhost)) {
+		RTE_LOG(ERR, APP, "VHOST Setting mismatch. (IF = %d, config = %d)\n",
+				vhost_num, g_if_info.num_vhost);
+		return -1;
+	}
+	return 0;
+}
+
+/*
+ * RING用の情報設定
+ */
+static int
+set_ring_interface(struct spp_config_area *config)
+{
+	/* RING Setting */
+	int ring_cnt, ring_num = 0;
+	g_if_info.num_ring = config->proc.num_ring;
+	struct patch_info *patch_info = NULL;
+	for (ring_cnt = 0; ring_cnt < RTE_MAX_ETHPORTS; ring_cnt++) {
+		patch_info = &g_if_info.ring_patchs[ring_cnt];
+		if (patch_info->use_flg == 0) {
+			/* Not Used */
+			continue;
+		}
+
+		/* Set DPDK port */
+		int dpdk_port = add_ring_pmd(ring_cnt);
+		if (unlikely(dpdk_port < 0)) {
+			RTE_LOG(ERR, APP, "RING add failed. (no = %d)\n",
+					ring_cnt);
+			return -1;
+		}
+		patch_info->dpdk_port = dpdk_port;
+
+		/* CORE情報側にもDPDKポート番号の情報設定 */
+		if (patch_info->rx_core != NULL) {
+			patch_info->rx_core->dpdk_port = dpdk_port;
+		}
+		if (patch_info->tx_core != NULL) {
+			patch_info->tx_core->dpdk_port = dpdk_port;
+		}
+		ring_num++;
+	}
+	if (unlikely(ring_num > g_if_info.num_ring)) {
+		RTE_LOG(ERR, APP, "RING Setting mismatch. (IF = %d, config = %d)\n",
+				ring_num, g_if_info.num_ring);
+		return -1;
+	}
+	return 0;
+}
+
+/*
+ * 管理データ初期設定
+ */
+static int
+init_manage_data(struct spp_config_area *config)
+{
+	/* Initialize */
+	init_if_info(config);
+	init_core_info(config);
+
+	/* Set config data */
+	int ret_proc = set_form_proc_info(config);
+	if (unlikely(ret_proc != 0)) {
+		/* 関数内でログ出力済みなので、省略 */
+		return -1;
+	}
+	int ret_classifier = set_from_classifier_table(config);
+	if (unlikely(ret_classifier != 0)) {
+		/* 関数内でログ出力済みなので、省略 */
+		return -1;
+	}
+
+	/* Set interface data */
+	int ret_nic = set_nic_interface(config);
+	if (unlikely(ret_nic != 0)) {
+		/* 関数内でログ出力済みなので、省略 */
+		return -1;
+	}
+
+	int ret_vhost = set_vhost_interface(config);
+	if (unlikely(ret_vhost != 0)) {
+		/* 関数内でログ出力済みなので、省略 */
+		return -1;
+	}
+
+	int ret_ring = set_ring_interface(config);
+	if (unlikely(ret_ring != 0)) {
+		/* 関数内でログ出力済みなので、省略 */
+		return -1;
+	}
+
+	return 0;
+}
+
+#ifdef SPP_RINGLATENCYSTATS_ENABLE /* RING滞留時間 */
+static void
+print_ring_latency_stats()
+{
+	/* Clear screen and move to top left */
+	const char topLeft[] = { 27, '[', '1', ';', '1', 'H', '\0' };
+	const char clr[] = { 27, '[', '2', 'J', '\0' };
+	printf("%s%s", clr, topLeft);
+
+	/* Print per RING */
+	int ring_cnt, stats_cnt;
+	struct spp_ringlatencystats_ring_latency_stats stats[RTE_MAX_ETHPORTS];
+	memset(&stats, 0x00, sizeof(stats));
+
+	printf("RING Latency\n");
+	printf(" RING");
+	for (ring_cnt = 0; ring_cnt < RTE_MAX_ETHPORTS; ring_cnt++) {
+		if (g_if_info.ring_patchs[ring_cnt].use_flg == 0) {
+			continue;
+		}
+		spp_ringlatencystats_get_stats(ring_cnt, &stats[ring_cnt]);
+		printf(", %-18d", ring_cnt);
+	}
+	printf("\n");
+
+	for (stats_cnt = 0; stats_cnt < SPP_RINGLATENCYSTATS_STATS_SLOT_COUNT; stats_cnt++) {
+		printf("%3dns", stats_cnt);
+		for (ring_cnt = 0; ring_cnt < RTE_MAX_ETHPORTS; ring_cnt++) {
+			if (g_if_info.ring_patchs[ring_cnt].use_flg == 0) {
+				continue;
+			}
+
+			printf(", 0x%-16lx", stats[ring_cnt].slot[stats_cnt]);
+		}
+		printf("\n");
+	}
+
+	return;
+}
+#endif /* SPP_RINGLATENCYSTATS_ENABLE */
+
+/*
+ * main
+ */
+int
+#ifndef USE_UT_SPP_VF
+main(int argc, char *argv[])
+#else /* ifndef USE_UT_SPP_VF */
+ut_main(int argc, char *argv[])
+#endif  /* ifndef USE_UT_SPP_VF */
+{
+	int ret = -1;
+#ifdef SPP_DEMONIZE
+	/* Daemonize process */
+	int ret_daemon = daemon(0, 0);
+	if (unlikely(ret_daemon != 0)) {
+		RTE_LOG(ERR, APP, "daemonize is faild. (ret = %d)\n", ret_daemon);
+		return ret_daemon;
+	}
+#endif
+
+	/* Signal handler registration (SIGTERM/SIGINT) */
+	signal(SIGTERM, stop_process);
+	signal(SIGINT,  stop_process);
+
+	unsigned int main_lcore_id = 0xffffffff;
+	while(1) {
+		/* Parse parameters */
+		int ret_parse = parse_app_args(argc, argv);
+		if (unlikely(ret_parse != 0)) {
+			break;
+		}
+
+		/* Load config */
+		int ret_config = spp_config_load_file(0, &g_config);
+		if (unlikely(ret_config != 0)) {
+			break;
+		}
+
+		/* DPDK initialize */
+		int ret_dpdk = rte_eal_init(argc, argv);
+		if (unlikely(ret_dpdk < 0)) {
+			break;
+		}
+		/* Get core id. */
+		main_lcore_id = rte_lcore_id();
+
+		/* 起動パラメータとコンフィグチェック */
+		/* 各IF情報設定 */
+		int ret_manage = init_manage_data(&g_config);
+		if (unlikely(ret_manage != 0)) {
+			break;
+		}
+
+		/* 他機能部初期化 */
+#ifdef SPP_RINGLATENCYSTATS_ENABLE /* RING滞留時間 */
+		int ret_ringlatency = spp_ringlatencystats_init(
+				SPP_RING_LATENCY_STATS_SAMPLING_INTERVAL, g_if_info.num_ring);
+		if (unlikely(ret_ringlatency != 0)) {
+			break;
+		}
+#endif /* SPP_RINGLATENCYSTATS_ENABLE */
+
+		/* Start  thread */
+		unsigned int lcore_id = 0;
+		RTE_LCORE_FOREACH_SLAVE(lcore_id) {
+			if (g_core_info[lcore_id].type == SPP_CONFIG_CLASSIFIER_MAC) {
+				rte_eal_remote_launch(spp_classifier_mac_do,
+						(void *)&g_core_info[lcore_id],
+						lcore_id);
+			} else {
+				rte_eal_remote_launch(spp_forward,
+						(void *)&g_core_info[lcore_id],
+						lcore_id);
+			}
+		}
+
+		/* スレッド状態確認 */
+		g_core_info[main_lcore_id].status = SPP_CORE_IDLE;
+		int ret_wait = check_core_status_wait(SPP_CORE_IDLE);
+		if (unlikely(ret_wait != 0)) {
+			break;
+		}
+
+		/* Start forward */
+		set_core_status(SPP_CORE_FORWARD);
+		RTE_LOG(INFO, APP, "My ID %d start handling message\n", 0);
+		RTE_LOG(INFO, APP, "[Press Ctrl-C to quit ...]\n");
+
+		/* loop */
+#ifndef USE_UT_SPP_VF
+		while(likely(g_core_info[main_lcore_id].status != SPP_CORE_STOP_REQUEST)) {
+#else
+		{
+#endif
+			sleep(1);
+
+#ifdef SPP_RINGLATENCYSTATS_ENABLE /* RING滞留時間 */
+			print_ring_latency_stats();
+#endif /* SPP_RINGLATENCYSTATS_ENABLE */
+		}
+
+		/* 正常終了 */
+		ret = 0;
+		break;
+	}
+
+	/* exit */
+	stop_process(SIGINT);
+	if (main_lcore_id == rte_lcore_id())
+	{
+		g_core_info[main_lcore_id].status = SPP_CORE_STOP;
+		int ret_core_end = check_core_status_wait(SPP_CORE_STOP);
+		if (unlikely(ret_core_end != 0)) {
+			RTE_LOG(ERR, APP, "Core did not stop.\n");
+		}
+	}
+
+	/* 他機能部終了処理 */
+#ifdef SPP_RINGLATENCYSTATS_ENABLE /* RING滞留時間 */
+	spp_ringlatencystats_uninit();
+#endif /* SPP_RINGLATENCYSTATS_ENABLE */
+	RTE_LOG(INFO, APP, "spp_vf exit.\n");
+	return ret;
+}
diff --git a/src/vf/spp_vf.h b/src/vf/spp_vf.h
new file mode 100644
index 0000000..feb59b6
--- /dev/null
+++ b/src/vf/spp_vf.h
@@ -0,0 +1,40 @@
+#ifndef __SPP_VF_H__
+#define __SPP_VF_H__
+
+#include "common.h"
+#include "spp_config.h"
+
+/*
+ * State on core
+ */
+enum spp_core_status {
+	SPP_CORE_STOP,
+	SPP_CORE_IDLE,
+	SPP_CORE_FORWARD,
+	SPP_CORE_STOP_REQUEST
+};
+
+/*
+ * Port info on core
+ */
+struct spp_core_port_info {
+	enum		port_type if_type;
+	int		if_no;
+	int		dpdk_port;
+	uint64_t	mac_addr;
+	char		mac_addr_str[SPP_CONFIG_STR_LEN];
+};
+
+/*
+ * Core info
+ */
+struct spp_core_info {
+	enum	spp_core_status status;
+	enum	spp_core_type type;
+	int	num_rx_port;
+	int	num_tx_port;
+	struct spp_core_port_info rx_ports[RTE_MAX_ETHPORTS];
+	struct spp_core_port_info tx_ports[RTE_MAX_ETHPORTS];
+};
+
+#endif /* __SPP_VF_H__ */
-- 
1.9.1

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

* [spp] [PATCH 02/57] spp_vf: support multi process
  2017-12-26  1:54 ` Yasufumi Ogawa
  2017-12-28  4:55   ` [spp] [PATCH 01/57] spp_vf: add vf functions x-fn-spp
@ 2017-12-28  4:55   ` x-fn-spp
  2018-02-07 16:50     ` Ferruh Yigit
  2017-12-28  4:55   ` [spp] [PATCH 03/57] spp_vf: comment out check of using cores x-fn-spp
                     ` (54 subsequent siblings)
  56 siblings, 1 reply; 97+ messages in thread
From: x-fn-spp @ 2017-12-28  4:55 UTC (permalink / raw)
  To: spp

From: Hiroyuki Nakamura <nakamura.hioryuki@po.ntt-tx.co.jp>

spp_vf was only a single process so far, but spp_vf supported
multi process. Following modification has been made.

* Change naming machanism to allow hashtable on shared memory
  to be operated by multiple processes.
* Get config file path from command line argument.

And following modification has been made.
* Modify comment.
* Add and modify log message.
* Add function to remove vhost socket file.

Signed-off-by: Daiki Yamashita <yamashita.daiki.z01@as.ntt-tx.co.jp>
Signed-off-by: Yasufum Ogawa <ogawa.yasufumi@lab.ntt.co.jp>
---
 src/vf/classifier_mac.c   |  79 ++++++++++++++++++------
 src/vf/ringlatencystats.c |   6 +-
 src/vf/spp_config.c       |  14 ++---
 src/vf/spp_config.h       |   2 +-
 src/vf/spp_forward.c      |   5 +-
 src/vf/spp_vf.c           | 154 ++++++++++++++++++++++++++++++++++++++--------
 src/vf/spp_vf.h           |   4 +-
 7 files changed, 206 insertions(+), 58 deletions(-)

diff --git a/src/vf/classifier_mac.c b/src/vf/classifier_mac.c
index da03905..374f164 100644
--- a/src/vf/classifier_mac.c
+++ b/src/vf/classifier_mac.c
@@ -5,6 +5,7 @@
 #include <stddef.h>
 #include <math.h>
 
+#include <rte_common.h>
 #include <rte_mbuf.h>
 #include <rte_log.h>
 #include <rte_cycles.h>
@@ -38,18 +39,36 @@
 		nano second */
 #define DRAIN_TX_PACKET_INTERVAL 100
 
+/* hash table name buffer size
+	[reson for value]
+		in dpdk's lib/librte_hash/rte_cuckoo_hash.c
+			snprintf(ring_name, sizeof(ring_name), "HT_%s", params->name);
+			snprintf(hash_name, sizeof(hash_name), "HT_%s", params->name);
+		ring_name buffer size is RTE_RING_NAMESIZE
+		hash_name buffer size is RTE_HASH_NAMESIZE */
+static const size_t HASH_TABLE_NAME_BUF_SZ =
+		((RTE_HASH_NAMESIZE < RTE_RING_NAMESIZE) ? 
+		RTE_HASH_NAMESIZE: RTE_RING_NAMESIZE) - 3;
+
 /* mac address string(xx:xx:xx:xx:xx:xx) buffer size */
 static const size_t ETHER_ADDR_STR_BUF_SZ =
 		ETHER_ADDR_LEN * 2 + (ETHER_ADDR_LEN - 1) + 1;
 
 /* classified data (destination port, target packets, etc) */
 struct classified_data {
-	int      if_no;
-	uint8_t  tx_port;
-	uint16_t num_pkt;
+	enum port_type  if_type;
+	int             if_no;
+	uint8_t         tx_port;
+	uint16_t        num_pkt;
 	struct rte_mbuf *pkts[MAX_PKT_BURST];
 };
 
+/* hash table count. use to make hash table name.
+	[reason for value]
+		it is incremented at the time of use, 
+		but since we want to start at 0. */
+static rte_atomic16_t g_hash_table_count = RTE_ATOMIC16_INIT(0xff);
+
 /* initialize classifier. */
 static int
 init_classifier(const struct spp_core_info *core_info,
@@ -58,11 +77,19 @@ init_classifier(const struct spp_core_info *core_info,
 	int ret = -1;
 	int i;
 	struct ether_addr eth_addr;
+	char hash_table_name[HASH_TABLE_NAME_BUF_SZ];
 	char mac_addr_str[ETHER_ADDR_STR_BUF_SZ];
 
+	/* make hash table name(require uniqueness between processes) */
+	sprintf(hash_table_name, "cmtab_%08x%02hx",
+			getpid(), rte_atomic16_add_return(&g_hash_table_count, 1));
+
+	RTE_LOG(INFO, SPP_CLASSIFIER_MAC, "Create table. name=%s, bufsz=%lu\n",
+			hash_table_name, HASH_TABLE_NAME_BUF_SZ);
+
 	/* set hash creating parameters */
 	struct rte_hash_parameters hash_params = {
-			.name      = "classifier_mac_table",
+			.name      = hash_table_name,
 			.entries   = NUM_CLASSIFIER_MAC_TABLE_ENTRY,
 			.key_len   = sizeof(struct ether_addr),
 			.hash_func = DEFAULT_HASH_FUNC,
@@ -100,6 +127,7 @@ init_classifier(const struct spp_core_info *core_info,
 		}
 
 		/* set value */
+		classified_data[i].if_type = core_info->tx_ports[i].if_type;
 		classified_data[i].if_no   = i;
 		classified_data[i].tx_port = core_info->tx_ports[i].dpdk_port;
 		classified_data[i].num_pkt = 0;
@@ -108,22 +136,25 @@ init_classifier(const struct spp_core_info *core_info,
 	return 0;
 }
 
-/* transimit packet to one destination. */
+/* transmit packet to one destination. */
 static inline void
-transimit_packet(struct classified_data *classified_data)
+transmit_packet(struct classified_data *classified_data)
 {
 	int i;
 	uint16_t n_tx;
 
-	/* set ringlatencystats */
-	spp_ringlatencystats_add_time_stamp(classified_data->if_no,
-			classified_data->pkts, classified_data->num_pkt);
+#ifdef SPP_RINGLATENCYSTATS_ENABLE
+	if (classified_data->if_type == RING)
+		/* if tx-if is ring, set ringlatencystats */
+		spp_ringlatencystats_add_time_stamp(classified_data->if_no,
+				classified_data->pkts, classified_data->num_pkt);
+#endif
 
-	/* transimit packets */
+	/* transmit packets */
 	n_tx = rte_eth_tx_burst(classified_data->tx_port, 0,
 			classified_data->pkts, classified_data->num_pkt);
 
-	/* free cannnot transiit packets */
+	/* free cannnot transmit packets */
 	if (unlikely(n_tx != classified_data->num_pkt)) {
 		for (i = n_tx; i < classified_data->num_pkt; i++)
 			rte_pktmbuf_free(classified_data->pkts[i]);
@@ -136,7 +167,7 @@ transimit_packet(struct classified_data *classified_data)
 }
 
 /* classify packet by destination mac address,
-		and transimit packet (conditional). */
+		and transmit packet (conditional). */
 static inline void
 classify_packet(struct rte_mbuf **rx_pkts, uint16_t n_rx,
 		struct rte_hash *classifier_mac_table, struct classified_data *classified_data)
@@ -166,9 +197,12 @@ classify_packet(struct rte_mbuf **rx_pkts, uint16_t n_rx,
 		cd = classified_data + (long)lookup_data;
 		cd->pkts[cd->num_pkt++] = rx_pkts[i];
 
-		/* transimit packet, if buffer is filled */
-		if (unlikely(cd->num_pkt == MAX_PKT_BURST))
-			transimit_packet(cd);
+		/* transmit packet, if buffer is filled */
+		if (unlikely(cd->num_pkt == MAX_PKT_BURST)) {
+			RTE_LOG(DEBUG, SPP_CLASSIFIER_MAC,
+                        		"transimit packets (buffer is filled). index=%ld, num_pkt=%hu\n", (long)lookup_data, cd->num_pkt);
+			transmit_packet(cd);
+		}
 	}
 }
 
@@ -205,8 +239,11 @@ spp_classifier_mac_do(void *arg)
 			cur_tsc = rte_rdtsc();
 			if (unlikely(cur_tsc - prev_tsc > drain_tsc)) {
 				for (i = 0; i < n_classified_data; i++) {
-					if (unlikely(classified_data[i].num_pkt != 0))
-						transimit_packet(&classified_data[i]);
+					if (unlikely(classified_data[i].num_pkt != 0)) {
+						RTE_LOG(DEBUG, SPP_CLASSIFIER_MAC,
+                        					"transimit packets (drain). index=%d, num_pkt=%hu, interval=%lu\n", i, classified_data[i].num_pkt, cur_tsc - prev_tsc);
+						transmit_packet(&classified_data[i]);
+					}
 				}
 				prev_tsc = cur_tsc;
 			}
@@ -217,7 +254,13 @@ spp_classifier_mac_do(void *arg)
 			if (unlikely(n_rx == 0))
 				continue;
 
-			/* classify and transimit (filled) */
+#ifdef SPP_RINGLATENCYSTATS_ENABLE
+			if (core_info->rx_ports[0].if_type == RING)
+				spp_ringlatencystats_calculate_latency(
+						core_info->rx_ports[0].if_no, rx_pkts, n_rx);
+#endif
+
+			/* classify and transmit (filled) */
 			classify_packet(rx_pkts, n_rx, classifier_mac_table, classified_data);
 		}
 	}
diff --git a/src/vf/ringlatencystats.c b/src/vf/ringlatencystats.c
index 8f44020..32ff55c 100644
--- a/src/vf/ringlatencystats.c
+++ b/src/vf/ringlatencystats.c
@@ -59,8 +59,8 @@ spp_ringlatencystats_init(uint64_t samp_intvl, uint16_t stats_count)
 	g_stats_count = stats_count;
 
 	RTE_LOG(DEBUG, SPP_RING_LATENCY_STATS,
-			"g_samp_intvl=%lu, g_stats_count=%hu, cpns=%lu\n",
-			g_samp_intvl, g_stats_count, cycles_per_ns());
+			"g_samp_intvl=%lu, g_stats_count=%hu, cpns=%lu, NS_PER_SEC=%f\n",
+			g_samp_intvl, g_stats_count, cycles_per_ns(), NS_PER_SEC);
 
 	return 0;
 }
@@ -95,6 +95,8 @@ spp_ringlatencystats_add_time_stamp(int ring_id,
 		/* when it is over sampling interval */
 		/* set tsc to mbuf::timestamp */
 		if (unlikely(stats_info->timer_tsc >= g_samp_intvl)) {
+			RTE_LOG(DEBUG, SPP_RING_LATENCY_STATS,
+					"Set timestamp. ring_id=%d, pkts_index=%u, timestamp=%lu\n", ring_id, i, now);
 			pkts[i]->timestamp = now;
 			stats_info->timer_tsc = 0;
 		}
diff --git a/src/vf/spp_config.c b/src/vf/spp_config.c
index 63b85f2..a4d8a67 100644
--- a/src/vf/spp_config.c
+++ b/src/vf/spp_config.c
@@ -150,7 +150,7 @@ config_get_if_info(const char *port, enum port_type *if_type, int *if_no)
 /*
  * MAC addressを文字列から数値へ変換
  */
-int64_t
+static int64_t
 config_change_mac_str_to_int64(const char *mac)
 {
 	int64_t ret_mac = 0;
@@ -237,7 +237,7 @@ config_load_classifier_table(const json_t *obj,
 	/* table用オブジェクトの要素数取得 */
 	int array_num = json_array_size(array_obj);
 	if (unlikely(array_num <= 0) ||
-			unlikely(array_num >= SPP_CONFIG_MAC_TABLE_MAX)) {
+			unlikely(array_num > SPP_CONFIG_MAC_TABLE_MAX)) {
 		RTE_LOG(ERR, APP, "Table size out of range. (path = %s, size = %d)\n",
 				JSONPATH_TABLE, array_num);
 		return -1;
@@ -356,7 +356,7 @@ config_set_rx_port(enum spp_core_type type, json_t *obj,
 		/* 受信ポート用オブジェクトの要素数取得 */
 		int port_num = json_array_size(array_obj);
 		if (unlikely(port_num <= 0) ||
-				unlikely(port_num >= RTE_MAX_ETHPORTS)) {
+				unlikely(port_num > RTE_MAX_ETHPORTS)) {
 			RTE_LOG(ERR, APP, "RX port out of range. (path = %s, port = %d, route = merge)\n",
 					JSONPATH_RX_PORT, port_num);
 			return -1;
@@ -551,7 +551,7 @@ config_load_proc_info(const json_t *obj, int node_id, struct spp_config_area *co
 	/* functions用オブジェクトの要素数取得 */
 	int array_num = json_array_size(array_obj);
 	if (unlikely(array_num <= 0) ||
-			unlikely(array_num >= SPP_CONFIG_CORE_MAX)) {
+			unlikely(array_num > SPP_CONFIG_CORE_MAX)) {
 		RTE_LOG(ERR, APP, "Functions size out of range. (path = %s, size = %d)\n",
 				JSONPATH_TABLE, array_num);
 		return -1;
@@ -630,18 +630,18 @@ config_load_proc_info(const json_t *obj, int node_id, struct spp_config_area *co
  * NG : -1
  */
 int
-spp_config_load_file(int node_id, struct spp_config_area *config)
+spp_config_load_file(const char* config_file_path, int node_id, struct spp_config_area *config)
 {
 	/* Config initialize */
 	config_init_data(config);
 	
 	/* Config load */
 	json_error_t json_error;
-	json_t *conf_obj = json_load_file(SPP_CONFIG_FILE_PATH, 0, &json_error);
+	json_t *conf_obj = json_load_file(config_file_path, 0, &json_error);
 	if (unlikely(conf_obj == NULL)) {
 		/* Load error */
 		RTE_LOG(ERR, APP, "Config load failed. (path = %s, text = %s)\n",
-				 SPP_CONFIG_FILE_PATH, json_error.text);
+				 config_file_path, json_error.text);
 		return -1;
 	}
 
diff --git a/src/vf/spp_config.h b/src/vf/spp_config.h
index d2a6a4b..24ddd32 100644
--- a/src/vf/spp_config.h
+++ b/src/vf/spp_config.h
@@ -85,6 +85,6 @@ struct spp_config_area {
  * OK : 0
  * NG : -1
  */
-int spp_config_load_file(int node_id, struct spp_config_area *config);
+int spp_config_load_file(const char* config_file_path, int node_id, struct spp_config_area *config);
 
 #endif /* __SPP_CONFIG_H__ */
diff --git a/src/vf/spp_forward.c b/src/vf/spp_forward.c
index 4396929..e153e85 100644
--- a/src/vf/spp_forward.c
+++ b/src/vf/spp_forward.c
@@ -1,7 +1,8 @@
 #include "spp_vf.h"
 #include "ringlatencystats.h"
+#include "spp_forward.h"
 
-#define RTE_LOGTYPE_SPP_FORWARD RTE_LOGTYPE_USER1
+#define RTE_LOGTYPE_FORWARD RTE_LOGTYPE_USER1
 
 /*
  * 送受信ポートの経路情報
@@ -14,7 +15,7 @@ struct rxtx {
 /*
  * 使用するIF情報を移し替える
  */
-void
+static void
 set_use_interface(struct spp_core_port_info *dst,
 		struct spp_core_port_info *src)
 {
diff --git a/src/vf/spp_vf.c b/src/vf/spp_vf.c
index ee5cf63..f035d07 100644
--- a/src/vf/spp_vf.c
+++ b/src/vf/spp_vf.c
@@ -14,6 +14,15 @@
 #define SPP_CORE_STATUS_CHECK_MAX 5
 #define SPP_RING_LATENCY_STATS_SAMPLING_INTERVAL 1000000
 
+/* getopt_long return value for long option */
+enum SPP_LONGOPT_RETVAL {
+	SPP_LONGOPT_RETVAL__ = 127,
+
+	/* add below */
+
+	SPP_LONGOPT_RETVAL_CONFIG,
+};
+
 /* struct */
 struct startup_param {
 	uint64_t cpu;
@@ -41,13 +50,18 @@ static struct startup_param	g_startup_param;
 static struct if_info		g_if_info;
 static struct spp_core_info	g_core_info[SPP_CONFIG_CORE_MAX];
 
+static char config_file_path[PATH_MAX];
+
 /*
  * print a usage message
  */
 static void
 usage(const char *progname)
 {
-	RTE_LOG(INFO, APP, "Usage: %s [EAL args]\n\n", progname);
+	RTE_LOG(INFO, APP, "Usage: %s [EAL args] -- [--config CONFIG_FILE_PATH]\n"
+			" --config CONFIG_FILE_PATH: specific config file path\n"
+			"\n"
+			, progname);
 }
 
 /*
@@ -208,7 +222,7 @@ set_core_status(enum spp_core_status status)
 /*
  * Process stop
  */
-void
+static void
 stop_process(int signal) {
 	if (unlikely(signal != SIGTERM) &&
 			unlikely(signal != SIGINT)) {
@@ -239,16 +253,23 @@ parse_cpu_bit(uint64_t *cpu, const char *cpu_bit)
 }
 
 /*
- * Parse the application arguments to the client app.
+ * Parse the dpdk arguments for use in client app.
  */
 static int
-parse_app_args(int argc, char *argv[])
+parse_dpdk_args(int argc, char *argv[])
 {
+	int cnt;
 	int option_index, opt;
-	char **argvopt = argv;
+	const int argcopt = argc;
+	char *argvopt[argcopt];
 	const char *progname = argv[0];
 	static struct option lgopts[] = { {0} };
 
+	/* getoptを使用するとargvが並び変わるみたいなので、コピーを実施 */
+	for (cnt = 0; cnt < argcopt; cnt++) {
+		argvopt[cnt] = argv[cnt];
+	}
+
 	/* Check DPDK parameter */
 	optind = 0;
 	opterr = 0;
@@ -273,6 +294,48 @@ parse_app_args(int argc, char *argv[])
 }
 
 /*
+ * Parse the application arguments to the client app.
+ */
+static int
+parse_app_args(int argc, char *argv[])
+{
+	int cnt;
+	int option_index, opt;
+	const int argcopt = argc;
+	char *argvopt[argcopt];
+	const char *progname = argv[0];
+	static struct option lgopts[] = { 
+			{ "config", required_argument, NULL, SPP_LONGOPT_RETVAL_CONFIG },
+			{ 0 },
+	 };
+
+	/* getoptを使用するとargvが並び変わるみたいなので、コピーを実施 */
+	for (cnt = 0; cnt < argcopt; cnt++) {
+		argvopt[cnt] = argv[cnt];
+	}
+
+	/* Check application parameter */
+	optind = 0;
+	opterr = 0;
+	while ((opt = getopt_long(argc, argvopt, "", lgopts,
+			&option_index)) != EOF) {
+		switch (opt) {
+		case SPP_LONGOPT_RETVAL_CONFIG:
+			if (optarg[0] == '\0' || strlen(optarg) >= sizeof(config_file_path)) {
+				usage(progname);
+				return -1;
+			}
+			strcpy(config_file_path, optarg);
+			break;
+		default:
+			break;
+		}
+	}
+
+	return 0;
+}
+
+/*
  * IF種別&IF番号のIF情報の領域取得
  */
 static struct patch_info *
@@ -299,7 +362,7 @@ get_if_area(enum port_type if_type, int if_no)
  * IF情報初期化
  */
 static void
-init_if_info()
+init_if_info(void)
 {
 	memset(&g_if_info, 0x00, sizeof(g_if_info));
 }
@@ -308,7 +371,7 @@ init_if_info()
  * CORE情報初期化
  */
 static void
-init_core_info()
+init_core_info(void)
 {
 	memset(&g_core_info, 0x00, sizeof(g_core_info));
 	int core_cnt, port_cnt;
@@ -330,7 +393,7 @@ set_form_proc_info(struct spp_config_area *config)
 	int core_cnt, rx_start, rx_cnt, tx_start, tx_cnt;
 	enum port_type if_type;
 	int if_no;
-	int64_t cpu_bit = 0;
+	uint64_t cpu_bit = 0;
 	struct spp_config_functions *core_func = NULL;
 	struct spp_core_info *core_info = NULL;
 	struct patch_info *patch_info = NULL;
@@ -344,7 +407,7 @@ set_form_proc_info(struct spp_config_area *config)
 
 		/* Forwardをまとめる事は可、他種別は不可 */
 		if ((core_info->type != SPP_CONFIG_UNUSE) &&
-				((core_info->type != SPP_CONFIG_FORWARD) &&
+				((core_info->type != SPP_CONFIG_FORWARD) ||
 				(core_func->type != SPP_CONFIG_FORWARD))) {
 			RTE_LOG(ERR, APP, "Core in use. (core = %d, type = %d/%d)\n",
 					core_func->core_no,
@@ -371,8 +434,8 @@ set_form_proc_info(struct spp_config_area *config)
 
 			patch_info->use_flg = 1;
 			if (unlikely(patch_info->rx_core != NULL)) {
-				RTE_LOG(ERR, APP, "Used RX port (if_type = %d, if_no = %d)\n",
-						if_type, if_no);
+				RTE_LOG(ERR, APP, "Used RX port (core = %d, if_type = %d, if_no = %d)\n",
+						core_func->core_no, if_type, if_no);
 				return -1;
 			}
 
@@ -395,8 +458,8 @@ set_form_proc_info(struct spp_config_area *config)
 
 			patch_info->use_flg = 1;
 			if (unlikely(patch_info->tx_core != NULL)) {
-				RTE_LOG(ERR, APP, "Used TX port (if_type = %d, if_no = %d)\n",
-						if_type, if_no);
+				RTE_LOG(ERR, APP, "Used TX port (core = %d, if_type = %d, if_no = %d)\n",
+						core_func->core_no, if_type, if_no);
 				return -1;
 			}
 
@@ -456,7 +519,7 @@ set_from_classifier_table(struct spp_config_area *config)
  * NIC用の情報設定
  */
 static int
-set_nic_interface(struct spp_config_area *config)
+set_nic_interface(struct spp_config_area *config __attribute__ ((unused)))
 {
 	/* NIC Setting */
 	g_if_info.num_nic = rte_eth_dev_count();
@@ -590,8 +653,8 @@ static int
 init_manage_data(struct spp_config_area *config)
 {
 	/* Initialize */
-	init_if_info(config);
-	init_core_info(config);
+	init_if_info();
+	init_core_info();
 
 	/* Set config data */
 	int ret_proc = set_form_proc_info(config);
@@ -629,7 +692,7 @@ init_manage_data(struct spp_config_area *config)
 
 #ifdef SPP_RINGLATENCYSTATS_ENABLE /* RING滞留時間 */
 static void
-print_ring_latency_stats()
+print_ring_latency_stats(void)
 {
 	/* Clear screen and move to top left */
 	const char topLeft[] = { 27, '[', '1', ';', '1', 'H', '\0' };
@@ -669,6 +732,24 @@ print_ring_latency_stats()
 #endif /* SPP_RINGLATENCYSTATS_ENABLE */
 
 /*
+ * VHOST用ソケットファイル削除
+ */
+static void
+del_vhost_sockfile(struct patch_info *vhost_patchs)
+{
+	int cnt;
+	for (cnt = 0; cnt < RTE_MAX_ETHPORTS; cnt++) {
+		if (likely(vhost_patchs[cnt].use_flg == 0)) {
+			/* VHOST未使用はスキップ */
+			continue;
+		}
+
+		/* 使用していたVHOSTについて削除を行う */
+		remove(get_vhost_iface_name(cnt));
+	}
+}
+
+/*
  * main
  */
 int
@@ -692,25 +773,44 @@ ut_main(int argc, char *argv[])
 	signal(SIGTERM, stop_process);
 	signal(SIGINT,  stop_process);
 
+	/* set default config file path */
+	strcpy(config_file_path, SPP_CONFIG_FILE_PATH);
+
 	unsigned int main_lcore_id = 0xffffffff;
 	while(1) {
-		/* Parse parameters */
-		int ret_parse = parse_app_args(argc, argv);
+		/* Parse dpdk parameters */
+		int ret_parse = parse_dpdk_args(argc, argv);
 		if (unlikely(ret_parse != 0)) {
 			break;
 		}
 
-		/* Load config */
-		int ret_config = spp_config_load_file(0, &g_config);
-		if (unlikely(ret_config != 0)) {
-			break;
-		}
-
 		/* DPDK initialize */
 		int ret_dpdk = rte_eal_init(argc, argv);
 		if (unlikely(ret_dpdk < 0)) {
 			break;
 		}
+
+		/* Skip dpdk parameters */
+		argc -= ret_dpdk;
+		argv += ret_dpdk;
+
+		/* Set log level  */
+		rte_log_set_global_level(RTE_LOG_LEVEL);
+
+		/* Parse application parameters */
+		ret_parse = parse_app_args(argc, argv);
+		if (unlikely(ret_parse != 0)) {
+			break;
+		}
+
+		RTE_LOG(INFO, APP, "Load config file(%s)\n", config_file_path);
+
+		/* Load config */
+		int ret_config = spp_config_load_file(config_file_path, 0, &g_config);
+		if (unlikely(ret_config != 0)) {
+			break;
+		}
+
 		/* Get core id. */
 		main_lcore_id = rte_lcore_id();
 
@@ -775,7 +875,6 @@ ut_main(int argc, char *argv[])
 	}
 
 	/* exit */
-	stop_process(SIGINT);
 	if (main_lcore_id == rte_lcore_id())
 	{
 		g_core_info[main_lcore_id].status = SPP_CORE_STOP;
@@ -783,6 +882,9 @@ ut_main(int argc, char *argv[])
 		if (unlikely(ret_core_end != 0)) {
 			RTE_LOG(ERR, APP, "Core did not stop.\n");
 		}
+
+		/* 使用していたVHOSTのソケットファイルを削除 */
+		del_vhost_sockfile(g_if_info.vhost_patchs);
 	}
 
 	/* 他機能部終了処理 */
diff --git a/src/vf/spp_vf.h b/src/vf/spp_vf.h
index feb59b6..c0faa57 100644
--- a/src/vf/spp_vf.h
+++ b/src/vf/spp_vf.h
@@ -29,8 +29,8 @@ struct spp_core_port_info {
  * Core info
  */
 struct spp_core_info {
-	enum	spp_core_status status;
-	enum	spp_core_type type;
+	volatile enum spp_core_status status;
+	enum spp_core_type type;
 	int	num_rx_port;
 	int	num_tx_port;
 	struct spp_core_port_info rx_ports[RTE_MAX_ETHPORTS];
-- 
1.9.1

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

* [spp] [PATCH 03/57] spp_vf: comment out check of using cores
  2017-12-26  1:54 ` Yasufumi Ogawa
  2017-12-28  4:55   ` [spp] [PATCH 01/57] spp_vf: add vf functions x-fn-spp
  2017-12-28  4:55   ` [spp] [PATCH 02/57] spp_vf: support multi process x-fn-spp
@ 2017-12-28  4:55   ` x-fn-spp
  2017-12-28  4:55   ` [spp] [PATCH 04/57] spp_vf: modify classifier for upd command x-fn-spp
                     ` (53 subsequent siblings)
  56 siblings, 0 replies; 97+ messages in thread
From: x-fn-spp @ 2017-12-28  4:55 UTC (permalink / raw)
  To: spp

From: Hiroyuki Nakamura <nakamura.hioryuki@po.ntt-tx.co.jp>

Bug workaround.
Current implementation prevent use of over 32 cores due to
int type restriction.

Signed-off-by: Daiki Yamashita <yamashita.daiki.z01@as.ntt-tx.co.jp>
Signed-off-by: Yasufum Ogawa <ogawa.yasufumi@lab.ntt.co.jp>
---
 src/vf/spp_vf.c | 2 ++
 1 file changed, 2 insertions(+)

diff --git a/src/vf/spp_vf.c b/src/vf/spp_vf.c
index f035d07..830aaaa 100644
--- a/src/vf/spp_vf.c
+++ b/src/vf/spp_vf.c
@@ -468,12 +468,14 @@ set_form_proc_info(struct spp_config_area *config)
 		}
 	}
 
+#if 0 /* bugfix#385 */
 	if (unlikely((cpu_bit & g_startup_param.cpu) != cpu_bit)) {
 		/* CPU mismatch */
 		RTE_LOG(ERR, APP, "CPU mismatch (cpu param = %lx, config = %lx)\n",
 				g_startup_param.cpu, cpu_bit);
 		return -1;
 	}
+#endif
 	return 0;
 }
 
-- 
1.9.1

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

* [spp] [PATCH 04/57] spp_vf: modify classifier for upd command
  2017-12-26  1:54 ` Yasufumi Ogawa
                     ` (2 preceding siblings ...)
  2017-12-28  4:55   ` [spp] [PATCH 03/57] spp_vf: comment out check of using cores x-fn-spp
@ 2017-12-28  4:55   ` x-fn-spp
  2017-12-28  4:55   ` [spp] [PATCH 05/57] spp_vf: add procedure that mac address is null x-fn-spp
                     ` (52 subsequent siblings)
  56 siblings, 0 replies; 97+ messages in thread
From: x-fn-spp @ 2017-12-28  4:55 UTC (permalink / raw)
  To: spp

From: Hiroyuki Nakamura <nakamura.hioryuki@po.ntt-tx.co.jp>

spp_vf supports command for modifying classifier table.
* Classifier changes to have two tables (for reference and update).
* Classifier use reference-table when packet handling.
* When updating, update update-table. After the update,
  switch the roles of two table.(update->reference, reference->update)

Signed-off-by: Daiki Yamashita <yamashita.daiki.z01@as.ntt-tx.co.jp>
Signed-off-by: Yasufum Ogawa <ogawa.yasufumi@lab.ntt.co.jp>
---
 src/vf/classifier_mac.c | 223 +++++++++++++++++++++++++++++++++++++++++-------
 src/vf/classifier_mac.h |  10 +++
 2 files changed, 200 insertions(+), 33 deletions(-)

diff --git a/src/vf/classifier_mac.c b/src/vf/classifier_mac.c
index 374f164..6d8b222 100644
--- a/src/vf/classifier_mac.c
+++ b/src/vf/classifier_mac.c
@@ -35,6 +35,13 @@
 /* number of classifier mac table entry */
 #define NUM_CLASSIFIER_MAC_TABLE_ENTRY 128
 
+/* number of classifier information (reference/update) */
+#define NUM_CLASSIFIER_MAC_INFO 2
+
+/* interval that wait untill change update index
+		micro second */
+#define CHANGE_UPDATE_INDEX_WAIT_INTERVAL 10
+
 /* interval that transmit burst packet, if buffer is not filled.
 		nano second */
 #define DRAIN_TX_PACKET_INTERVAL 100
@@ -54,6 +61,18 @@ static const size_t HASH_TABLE_NAME_BUF_SZ =
 static const size_t ETHER_ADDR_STR_BUF_SZ =
 		ETHER_ADDR_LEN * 2 + (ETHER_ADDR_LEN - 1) + 1;
 
+/* classifier information */
+struct classifier_mac_info {
+	struct rte_hash *classifier_table;
+};
+
+/* classifier management information */
+struct classifier_mac_mng_info {
+	struct classifier_mac_info info[NUM_CLASSIFIER_MAC_INFO];
+	volatile int ref_index;
+	volatile int upd_index;
+};
+
 /* classified data (destination port, target packets, etc) */
 struct classified_data {
 	enum port_type  if_type;
@@ -63,16 +82,59 @@ struct classified_data {
 	struct rte_mbuf *pkts[MAX_PKT_BURST];
 };
 
+/* classifier information per lcore */
+static struct classifier_mac_mng_info g_classifier_mng_info[RTE_MAX_LCORE];
+
 /* hash table count. use to make hash table name.
 	[reason for value]
 		it is incremented at the time of use, 
 		but since we want to start at 0. */
 static rte_atomic16_t g_hash_table_count = RTE_ATOMIC16_INIT(0xff);
 
+/* initialize classifier table. */
+static int
+init_classifier_table(struct rte_hash **classifier_table,
+		struct spp_core_info *core_info)
+{
+	int ret = -1;
+	int i;
+	struct ether_addr eth_addr;
+	char mac_addr_str[ETHER_ADDR_STR_BUF_SZ];
+
+	rte_hash_reset(*classifier_table);
+
+	for (i = 0; i < core_info->num_tx_port; i++) {
+		rte_memcpy(&eth_addr, &core_info->tx_ports[i].mac_addr, ETHER_ADDR_LEN);
+
+		/* add entry to classifier mac table */
+		ret = rte_hash_add_key_data(*classifier_table,
+				(void*)&eth_addr, (void*)(long)i);
+		if (unlikely(ret < 0)) {
+			ether_format_addr(mac_addr_str, sizeof(mac_addr_str), &eth_addr);
+			RTE_LOG(ERR, SPP_CLASSIFIER_MAC,
+					"Cannot add entry to classifier mac table. "
+					"ret=%d, mac_addr=%s\n", ret, mac_addr_str);
+			rte_hash_free(*classifier_table);
+			*classifier_table = NULL;
+			return -1;
+		}
+
+		RTE_LOG(DEBUG, SPP_CLASSIFIER_MAC, "Add entry to classifier mac table. "
+				"mac_addr=%s, if_type=%d, if_no=%d, dpdk_port=%d\n",
+				mac_addr_str, 
+				core_info->tx_ports[i].if_type, 
+				core_info->tx_ports[i].if_no, 
+				core_info->tx_ports[i].dpdk_port);
+	}
+
+	return 0;
+}
+
 /* initialize classifier. */
 static int
 init_classifier(const struct spp_core_info *core_info,
-		struct rte_hash **classifier_mac_table, struct classified_data *classified_data)
+		struct classifier_mac_mng_info *classifier_mng_info, 
+		struct classified_data *classified_data)
 {
 	int ret = -1;
 	int i;
@@ -80,22 +142,11 @@ init_classifier(const struct spp_core_info *core_info,
 	char hash_table_name[HASH_TABLE_NAME_BUF_SZ];
 	char mac_addr_str[ETHER_ADDR_STR_BUF_SZ];
 
-	/* make hash table name(require uniqueness between processes) */
-	sprintf(hash_table_name, "cmtab_%08x%02hx",
-			getpid(), rte_atomic16_add_return(&g_hash_table_count, 1));
+	struct rte_hash **classifier_mac_table = NULL;
 
-	RTE_LOG(INFO, SPP_CLASSIFIER_MAC, "Create table. name=%s, bufsz=%lu\n",
-			hash_table_name, HASH_TABLE_NAME_BUF_SZ);
-
-	/* set hash creating parameters */
-	struct rte_hash_parameters hash_params = {
-			.name      = hash_table_name,
-			.entries   = NUM_CLASSIFIER_MAC_TABLE_ENTRY,
-			.key_len   = sizeof(struct ether_addr),
-			.hash_func = DEFAULT_HASH_FUNC,
-			.hash_func_init_val = 0,
-			.socket_id = rte_socket_id(),
-	};
+	memset(classifier_mng_info, 0, sizeof(struct classifier_mac_mng_info));
+	classifier_mng_info->ref_index = 0;
+	classifier_mng_info->upd_index = classifier_mng_info->ref_index + 1;
 
 #ifdef RTE_MACHINE_CPUFLAG_SSE4_2
 	RTE_LOG(DEBUG, SPP_CLASSIFIER_MAC, "Enabled SSE4.2. use crc hash.\n");
@@ -103,19 +154,48 @@ init_classifier(const struct spp_core_info *core_info,
 	RTE_LOG(DEBUG, SPP_CLASSIFIER_MAC, "Disabled SSE4.2. use jenkins hash.\n");
 #endif
 
-	/* create classifier mac table (hash table) */
-	*classifier_mac_table = rte_hash_create(&hash_params);
-	if (unlikely(*classifier_mac_table == NULL)) {
-		RTE_LOG(ERR, SPP_CLASSIFIER_MAC, "Cannot create classifier mac table\n");
-		return -1;
+	for (i = 0; i < NUM_CLASSIFIER_MAC_INFO; ++i) {
+
+		classifier_mac_table = &classifier_mng_info->info[i].classifier_table;
+
+		/* make hash table name(require uniqueness between processes) */
+		sprintf(hash_table_name, "cmtab_%07x%02hx%x",
+				getpid(), rte_atomic16_add_return(&g_hash_table_count, 1), i);
+
+		RTE_LOG(INFO, SPP_CLASSIFIER_MAC, "Create table. name=%s, bufsz=%lu\n",
+				hash_table_name, HASH_TABLE_NAME_BUF_SZ);
+
+		/* set hash creating parameters */
+		struct rte_hash_parameters hash_params = {
+				.name      = hash_table_name,
+				.entries   = NUM_CLASSIFIER_MAC_TABLE_ENTRY,
+				.key_len   = sizeof(struct ether_addr),
+				.hash_func = DEFAULT_HASH_FUNC,
+				.hash_func_init_val = 0,
+				.socket_id = rte_socket_id(),
+		};
+
+		/* create classifier mac table (hash table) */
+		*classifier_mac_table = rte_hash_create(&hash_params);
+		if (unlikely(*classifier_mac_table == NULL)) {
+			RTE_LOG(ERR, SPP_CLASSIFIER_MAC, "Cannot create classifier mac table. "
+					"name=%s\n", hash_table_name);
+			return -1;
+		}
 	}
 
-	/* populate the hash */
+	/* populate the hash at reference table */
+	classifier_mac_table = &classifier_mng_info->info[classifier_mng_info->ref_index].
+			classifier_table;
+
 	for (i = 0; i < core_info->num_tx_port; i++) {
 		rte_memcpy(&eth_addr, &core_info->tx_ports[i].mac_addr, ETHER_ADDR_LEN);
 
+		/* TODO:when modify this code, consider to use init_classifier_table function */
+
 		/* add entry to classifier mac table */
-		ret = rte_hash_add_key_data(*classifier_mac_table, (void*)&eth_addr, (void*)(long)i);
+		ret = rte_hash_add_key_data(*classifier_mac_table,
+				(void*)&eth_addr, (void*)(long)i);
 		if (unlikely(ret < 0)) {
 			ether_format_addr(mac_addr_str, sizeof(mac_addr_str), &eth_addr);
 			RTE_LOG(ERR, SPP_CLASSIFIER_MAC,
@@ -136,6 +216,20 @@ init_classifier(const struct spp_core_info *core_info,
 	return 0;
 }
 
+/* uninitialize classifier. */
+static void
+uninit_classifier(struct classifier_mac_mng_info *classifier_mng_info)
+{
+	int i;
+
+	for (i = 0; i < NUM_CLASSIFIER_MAC_INFO; ++i) {
+		if (classifier_mng_info->info[i].classifier_table != NULL){
+			rte_hash_free(classifier_mng_info->info[i].classifier_table);
+			classifier_mng_info->info[i].classifier_table = NULL;
+		}
+	}
+}
+
 /* transmit packet to one destination. */
 static inline void
 transmit_packet(struct classified_data *classified_data)
@@ -170,7 +264,8 @@ transmit_packet(struct classified_data *classified_data)
 		and transmit packet (conditional). */
 static inline void
 classify_packet(struct rte_mbuf **rx_pkts, uint16_t n_rx,
-		struct rte_hash *classifier_mac_table, struct classified_data *classified_data)
+		struct classifier_mac_info *classifier_info, 
+		struct classified_data *classified_data)
 {
 	int ret;
 	int i;
@@ -183,7 +278,7 @@ classify_packet(struct rte_mbuf **rx_pkts, uint16_t n_rx,
 		eth = rte_pktmbuf_mtod(rx_pkts[i], struct ether_hdr *);
 
 		/* find in table (by destination mac address)*/
-		ret = rte_hash_lookup_data(classifier_mac_table,
+		ret = rte_hash_lookup_data(classifier_info->classifier_table,
 				(const void*)&eth->d_addr, &lookup_data);
 		if (unlikely(ret < 0)) {
 			ether_format_addr(mac_addr_str, sizeof(mac_addr_str), &eth->d_addr);
@@ -206,6 +301,43 @@ classify_packet(struct rte_mbuf **rx_pkts, uint16_t n_rx,
 	}
 }
 
+/* classifier(mac address) update component info. */
+int
+spp_classifier_mac_update(struct spp_core_info *core_info)
+{
+	int ret = -1;
+	unsigned int lcore_id = core_info->lcore_id;
+
+	struct classifier_mac_mng_info *classifier_mng_info =
+			g_classifier_mng_info + lcore_id;
+
+	struct classifier_mac_info *classifier_info =
+			classifier_mng_info->info + classifier_mng_info->upd_index;
+
+	RTE_LOG(INFO, SPP_CLASSIFIER_MAC,
+			"Core[%u] Start update component.", lcore_id);
+
+	/* initialize update side classifier table */
+	ret = init_classifier_table(&classifier_info->classifier_table, core_info);
+	if (unlikely(ret != 0)) {
+		RTE_LOG(ERR, SPP_CLASSIFIER_MAC,
+				"Cannot update classifer mac. ret=%d\n", ret);
+		return ret;
+	}
+
+	/* change index of reference side */
+	classifier_mng_info->ref_index = classifier_mng_info->upd_index;
+
+	/* wait until no longer access the new update side */
+	while(likely(classifier_mng_info->ref_index == classifier_mng_info->upd_index))
+		rte_delay_us_block(CHANGE_UPDATE_INDEX_WAIT_INTERVAL);
+
+	RTE_LOG(INFO, SPP_CLASSIFIER_MAC,
+			"Core[%u] Complete update component.", lcore_id);
+
+	return 0;
+}
+
 /* classifier(mac address) thread function. */
 int
 spp_classifier_mac_do(void *arg)
@@ -213,10 +345,14 @@ spp_classifier_mac_do(void *arg)
 	int ret = -1;
 	int i;
 	int n_rx;
+	unsigned int lcore_id = rte_lcore_id();
 	struct spp_core_info *core_info = (struct spp_core_info *)arg;
+	struct classifier_mac_mng_info *classifier_mng_info =
+			g_classifier_mng_info + rte_lcore_id();
+
+	struct classifier_mac_info *classifier_info = NULL;
 	struct rte_mbuf *rx_pkts[MAX_PKT_BURST];
 
-	struct rte_hash *classifier_mac_table = NULL;
 	const int n_classified_data = core_info->num_tx_port;
 	struct classified_data classified_data[n_classified_data];
 
@@ -225,23 +361,46 @@ spp_classifier_mac_do(void *arg)
 			US_PER_S * DRAIN_TX_PACKET_INTERVAL;
 
 	/* initialize */
-	ret = init_classifier(core_info, &classifier_mac_table, classified_data);
+	ret = init_classifier(core_info, classifier_mng_info, classified_data);
 	if (unlikely(ret != 0))
 		return ret;
 
 	/* to idle  */
 	core_info->status = SPP_CORE_IDLE;
+	RTE_LOG(INFO, SPP_CLASSIFIER_MAC, "Core[%u] Start. (type = %d)\n",
+			lcore_id, core_info->type);
+
 	while(likely(core_info->status == SPP_CORE_IDLE) ||
 			likely(core_info->status == SPP_CORE_FORWARD)) {
 
 		while(likely(core_info->status == SPP_CORE_FORWARD)) {
+			/* change index of update side */
+			if (unlikely(classifier_mng_info->ref_index == 
+					classifier_mng_info->upd_index)) {
+				RTE_LOG(DEBUG, SPP_CLASSIFIER_MAC,
+						"Core[%u] Change update index.", lcore_id);
+				classifier_mng_info->upd_index = 
+						(classifier_mng_info->upd_index + 1) % 
+						NUM_CLASSIFIER_MAC_INFO;
+			}
+
+			/* decide classifier infomation of the current cycle */
+			classifier_info = classifier_mng_info->info + 
+					classifier_mng_info->ref_index;
+
 			/* drain tx packets, if buffer is not filled for interval */
 			cur_tsc = rte_rdtsc();
 			if (unlikely(cur_tsc - prev_tsc > drain_tsc)) {
 				for (i = 0; i < n_classified_data; i++) {
 					if (unlikely(classified_data[i].num_pkt != 0)) {
 						RTE_LOG(DEBUG, SPP_CLASSIFIER_MAC,
-                        					"transimit packets (drain). index=%d, num_pkt=%hu, interval=%lu\n", i, classified_data[i].num_pkt, cur_tsc - prev_tsc);
+                        					"transimit packets (drain). "
+								"index=%d, "
+								"num_pkt=%hu, "
+								"interval=%lu\n",
+								i,
+								classified_data[i].num_pkt,
+								cur_tsc - prev_tsc);
 						transmit_packet(&classified_data[i]);
 					}
 				}
@@ -261,15 +420,13 @@ spp_classifier_mac_do(void *arg)
 #endif
 
 			/* classify and transmit (filled) */
-			classify_packet(rx_pkts, n_rx, classifier_mac_table, classified_data);
+			classify_packet(rx_pkts, n_rx, classifier_info, classified_data);
 		}
 	}
 
 	/* uninitialize */
-	if (classifier_mac_table != NULL) {
-		rte_hash_free(classifier_mac_table);
-		classifier_mac_table = NULL;
-	}
+	uninit_classifier(classifier_mng_info);
+
 	core_info->status = SPP_CORE_STOP;
 
 	return 0;
diff --git a/src/vf/classifier_mac.h b/src/vf/classifier_mac.h
index 2661206..6bbdb15 100644
--- a/src/vf/classifier_mac.h
+++ b/src/vf/classifier_mac.h
@@ -1,6 +1,16 @@
 #ifndef _CLASSIFIER_MAC_H_
 #define _CLASSIFIER_MAC_H_
 
+struct spp_core_info;
+
+/**
+ * classifier(mac address) update component info.
+ *
+ * @param core_info
+ *  point to struct spp_core_info.
+ */
+int spp_classifier_mac_update(struct spp_core_info *core_info);
+
 /**
  * classifier(mac address) thread function.
  *
-- 
1.9.1

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

* [spp] [PATCH 05/57] spp_vf: add procedure that mac address is null
  2017-12-26  1:54 ` Yasufumi Ogawa
                     ` (3 preceding siblings ...)
  2017-12-28  4:55   ` [spp] [PATCH 04/57] spp_vf: modify classifier for upd command x-fn-spp
@ 2017-12-28  4:55   ` x-fn-spp
  2017-12-28  4:55   ` [spp] [PATCH 06/57] spp_vf: change config format for upd command x-fn-spp
                     ` (51 subsequent siblings)
  56 siblings, 0 replies; 97+ messages in thread
From: x-fn-spp @ 2017-12-28  4:55 UTC (permalink / raw)
  To: spp

From: Hiroyuki Nakamura <nakamura.hioryuki@po.ntt-tx.co.jp>

spp_vf supports command for modifying classifier table.

* Add procedure that MAC address is null.
* Refactor classifier table initialization.
* Refactor classifier table switching.

Signed-off-by: Daiki Yamashita <yamashita.daiki.z01@as.ntt-tx.co.jp>
Signed-off-by: Yasufum Ogawa <ogawa.yasufumi@lab.ntt.co.jp>
---
 src/vf/classifier_mac.c | 55 ++++++++++++++++++++++++++-----------------------
 src/vf/classifier_mac.h |  4 ++++
 2 files changed, 33 insertions(+), 26 deletions(-)

diff --git a/src/vf/classifier_mac.c b/src/vf/classifier_mac.c
index 6d8b222..6808062 100644
--- a/src/vf/classifier_mac.c
+++ b/src/vf/classifier_mac.c
@@ -104,6 +104,10 @@ init_classifier_table(struct rte_hash **classifier_table,
 	rte_hash_reset(*classifier_table);
 
 	for (i = 0; i < core_info->num_tx_port; i++) {
+		if (core_info->tx_ports[i].mac_addr == 0) {
+			continue;
+		}
+
 		rte_memcpy(&eth_addr, &core_info->tx_ports[i].mac_addr, ETHER_ADDR_LEN);
 
 		/* add entry to classifier mac table */
@@ -188,25 +192,15 @@ init_classifier(const struct spp_core_info *core_info,
 	classifier_mac_table = &classifier_mng_info->info[classifier_mng_info->ref_index].
 			classifier_table;
 
-	for (i = 0; i < core_info->num_tx_port; i++) {
-		rte_memcpy(&eth_addr, &core_info->tx_ports[i].mac_addr, ETHER_ADDR_LEN);
-
-		/* TODO:when modify this code, consider to use init_classifier_table function */
-
-		/* add entry to classifier mac table */
-		ret = rte_hash_add_key_data(*classifier_mac_table,
-				(void*)&eth_addr, (void*)(long)i);
-		if (unlikely(ret < 0)) {
-			ether_format_addr(mac_addr_str, sizeof(mac_addr_str), &eth_addr);
-			RTE_LOG(ERR, SPP_CLASSIFIER_MAC,
-					"Cannot add entry to classifier mac table. "
-					"ret=%d, mac_addr=%s\n", ret, mac_addr_str);
-			rte_hash_free(*classifier_mac_table);
-			*classifier_mac_table = NULL;
-			return -1;
-		}
+	ret = init_classifier_table(classifier_mac_table, core_info);
+	if (unlikely(ret != 0)) {
+		RTE_LOG(ERR, SPP_CLASSIFIER_MAC,
+				"Cannot initialize classifer mac table. ret=%d\n", ret);
+		return -1;
+	}
 
-		/* set value */
+	/* store ports information */
+	for (i = 0; i < core_info->num_tx_port; i++) {
 		classified_data[i].if_type = core_info->tx_ports[i].if_type;
 		classified_data[i].if_no   = i;
 		classified_data[i].tx_port = core_info->tx_ports[i].dpdk_port;
@@ -301,6 +295,19 @@ classify_packet(struct rte_mbuf **rx_pkts, uint16_t n_rx,
 	}
 }
 
+static inline void
+change_update_index(struct classifier_mac_mng_info *classifier_mng_info, unsigned int lcore_id)
+{
+	if (unlikely(classifier_mng_info->ref_index == 
+			classifier_mng_info->upd_index)) {
+		RTE_LOG(DEBUG, SPP_CLASSIFIER_MAC,
+				"Core[%u] Change update index.", lcore_id);
+		classifier_mng_info->upd_index = 
+				(classifier_mng_info->upd_index + 1) % 
+				NUM_CLASSIFIER_MAC_INFO;
+	}
+}
+
 /* classifier(mac address) update component info. */
 int
 spp_classifier_mac_update(struct spp_core_info *core_info)
@@ -375,14 +382,7 @@ spp_classifier_mac_do(void *arg)
 
 		while(likely(core_info->status == SPP_CORE_FORWARD)) {
 			/* change index of update side */
-			if (unlikely(classifier_mng_info->ref_index == 
-					classifier_mng_info->upd_index)) {
-				RTE_LOG(DEBUG, SPP_CLASSIFIER_MAC,
-						"Core[%u] Change update index.", lcore_id);
-				classifier_mng_info->upd_index = 
-						(classifier_mng_info->upd_index + 1) % 
-						NUM_CLASSIFIER_MAC_INFO;
-			}
+			change_update_index(classifier_mng_info, lcore_id);
 
 			/* decide classifier infomation of the current cycle */
 			classifier_info = classifier_mng_info->info + 
@@ -424,6 +424,9 @@ spp_classifier_mac_do(void *arg)
 		}
 	}
 
+	/* just in case */
+	change_update_index(classifier_mng_info, lcore_id);
+
 	/* uninitialize */
 	uninit_classifier(classifier_mng_info);
 
diff --git a/src/vf/classifier_mac.h b/src/vf/classifier_mac.h
index 6bbdb15..98f47a5 100644
--- a/src/vf/classifier_mac.h
+++ b/src/vf/classifier_mac.h
@@ -1,6 +1,7 @@
 #ifndef _CLASSIFIER_MAC_H_
 #define _CLASSIFIER_MAC_H_
 
+/* forward declaration */
 struct spp_core_info;
 
 /**
@@ -8,6 +9,9 @@ struct spp_core_info;
  *
  * @param core_info
  *  point to struct spp_core_info.
+ *
+ * @ret_val 0  succeeded.
+ * @ret_val -1 failed.
  */
 int spp_classifier_mac_update(struct spp_core_info *core_info);
 
-- 
1.9.1

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

* [spp] [PATCH 06/57] spp_vf: change config format for upd command
  2017-12-26  1:54 ` Yasufumi Ogawa
                     ` (4 preceding siblings ...)
  2017-12-28  4:55   ` [spp] [PATCH 05/57] spp_vf: add procedure that mac address is null x-fn-spp
@ 2017-12-28  4:55   ` x-fn-spp
  2017-12-28  4:55   ` [spp] [PATCH 07/57] spp_vf: fix compiler warning in classifier_mac.c x-fn-spp
                     ` (50 subsequent siblings)
  56 siblings, 0 replies; 97+ messages in thread
From: x-fn-spp @ 2017-12-28  4:55 UTC (permalink / raw)
  To: spp

From: Hiroyuki Nakamura <nakamura.hioryuki@po.ntt-tx.co.jp>

spp_vf supports command for modifying classifier table.
* Change the config file format.
* Modify code to support the file format change.

Signed-off-by: Kentaro Watanabe <watanabe.kentaro.z01@as.ntt-tx.co.jp>
Signed-off-by: Yasufum Ogawa <ogawa.yasufumi@lab.ntt.co.jp>
---
 src/vf/spp_config.c | 91 +++++++++++++++++++++++++++++++++++++++++++++--------
 1 file changed, 78 insertions(+), 13 deletions(-)

diff --git a/src/vf/spp_config.c b/src/vf/spp_config.c
index a4d8a67..1794e84 100644
--- a/src/vf/spp_config.c
+++ b/src/vf/spp_config.c
@@ -206,9 +206,8 @@ config_load_classifier_table(const json_t *obj,
 	/* classifier_table用オブジェクト取得 */
 	json_t *classifier_obj = json_path_get(obj, JSONPATH_CLASSIFIER_TABLE);
 	if (unlikely(classifier_obj == NULL)) {
-		RTE_LOG(ERR, APP, "Json object get failed. (path = %s)\n",
-				JSONPATH_CLASSIFIER_TABLE);
-		return -1;
+		RTE_LOG(INFO, APP, "No classifier table.\n");
+		return 0;
 	}
 
 	/* name取得 */
@@ -428,6 +427,7 @@ config_set_tx_port(enum spp_core_type type, json_t *obj,
 		struct spp_config_functions *functions,
 		struct spp_config_classifier_table *classifier_table)
 {
+	int cnt = 0;
 	struct spp_config_port_info *tmp_tx_port = NULL;
 	char if_str[SPP_CONFIG_STR_LEN];
 	if ((type == SPP_CONFIG_MERGE) || (type == SPP_CONFIG_FORWARD)) {
@@ -454,16 +454,81 @@ config_set_tx_port(enum spp_core_type type, json_t *obj,
 		}
 	} else {
 		/* Classifier */
-		int cnt = 0;
-		functions->num_tx_port = classifier_table->num_table;
-		struct spp_config_mac_table_element *tmp_mac_table = NULL;
-		for (cnt = 0; cnt < classifier_table->num_table; cnt++) {
-			tmp_tx_port = &functions->tx_ports[cnt];
-			tmp_mac_table = &classifier_table->mac_tables[cnt];
-
-			/* MAC振り分けテーブルより設定 */
-			tmp_tx_port->if_type = tmp_mac_table->port.if_type;
-			tmp_tx_port->if_no   = tmp_mac_table->port.if_no;
+		json_t *table_obj = json_path_get(obj, JSONPATH_TX_TABLE);
+		if (unlikely(table_obj != NULL)) {
+			/* Classifier Tableから取得 */
+			functions->num_tx_port = classifier_table->num_table;
+			struct spp_config_mac_table_element *tmp_mac_table = NULL;
+			for (cnt = 0; cnt < classifier_table->num_table; cnt++) {
+				tmp_tx_port = &functions->tx_ports[cnt];
+				tmp_mac_table = &classifier_table->mac_tables[cnt];
+
+				/* MAC振り分けテーブルより設定 */
+				tmp_tx_port->if_type = tmp_mac_table->port.if_type;
+				tmp_tx_port->if_no   = tmp_mac_table->port.if_no;
+			}
+			
+		}
+		else
+		{
+			/* tx_portパラメータより取得 */
+			/* 送信ポート用オブジェクト取得 */
+			json_t *array_obj = json_path_get(obj, JSONPATH_TX_PORT);
+			if (unlikely(array_obj == NULL)) {
+				RTE_LOG(ERR, APP, "Json object get failed. (path = %s, route = classifier)\n",
+					JSONPATH_TX_PORT);
+				return -1;
+			}
+
+			/* 送信ポート用オブジェクトが配列かチェック */
+			if (unlikely(!json_is_array(array_obj))) {
+				RTE_LOG(ERR, APP, "Not an array. (path = %s, route = classifier)\n",
+					JSONPATH_TX_PORT);
+				return -1;
+			}
+
+			/* 受信ポート用オブジェクトの要素数取得 */
+			int port_num = json_array_size(array_obj);
+			if (unlikely(port_num <= 0) ||
+					unlikely(port_num > RTE_MAX_ETHPORTS)) {
+				RTE_LOG(ERR, APP, "TX port out of range. (path = %s, port = %d, route = classifier)\n",
+						JSONPATH_TX_PORT, port_num);
+				return -1;
+			}
+			functions->num_tx_port = port_num;
+
+			/* 要素毎にデータ取得 */
+			int array_cnt = 0;
+			for (array_cnt = 0; array_cnt < port_num; array_cnt++) {
+				tmp_tx_port = &functions->tx_ports[array_cnt];
+
+				/* 要素取得 */
+				json_t *elements_obj = json_array_get(array_obj, array_cnt);
+				if (unlikely(elements_obj == NULL)) {
+					RTE_LOG(ERR, APP,
+						"Element get failed. (No = %d, path = %s, route = classifier)\n",
+						array_cnt, JSONPATH_TX_PORT);
+					return -1;
+				}
+
+				/* String type check */
+				if (unlikely(!json_is_string(elements_obj))) {
+					RTE_LOG(ERR, APP, "Not a string. (path = %s, No = %d, route = classifier)\n",
+							JSONPATH_TX_PORT, array_cnt);
+					return -1;
+				}
+				strcpy(if_str, json_string_value(elements_obj));
+
+				/* IF種別とIF番号に分割 */
+				int ret_if = config_get_if_info(if_str, &tmp_tx_port->if_type,
+						&tmp_tx_port->if_no);
+				if (unlikely(ret_if != 0)) {
+					RTE_LOG(ERR, APP,
+						"Interface change failed. (No = %d, port = %s, route = classifier)\n",
+						array_cnt, if_str);
+					return -1;
+				}
+			}
 		}
 	}
 
-- 
1.9.1

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

* [spp] [PATCH 07/57] spp_vf: fix compiler warning in classifier_mac.c
  2017-12-26  1:54 ` Yasufumi Ogawa
                     ` (5 preceding siblings ...)
  2017-12-28  4:55   ` [spp] [PATCH 06/57] spp_vf: change config format for upd command x-fn-spp
@ 2017-12-28  4:55   ` x-fn-spp
  2017-12-28  4:55   ` [spp] [PATCH 08/57] spp_vf: modify data struct for upd command x-fn-spp
                     ` (49 subsequent siblings)
  56 siblings, 0 replies; 97+ messages in thread
From: x-fn-spp @ 2017-12-28  4:55 UTC (permalink / raw)
  To: spp

From: Hiroyuki Nakamura <nakamura.hioryuki@po.ntt-tx.co.jp>

* Add const keyword to parameter.
* Remove unused variables.

Signed-off-by: Daiki Yamashita <yamashita.daiki.z01@as.ntt-tx.co.jp>
Signed-off-by: Yasufum Ogawa <ogawa.yasufumi@lab.ntt.co.jp>
---
 src/vf/classifier_mac.c | 4 +---
 1 file changed, 1 insertion(+), 3 deletions(-)

diff --git a/src/vf/classifier_mac.c b/src/vf/classifier_mac.c
index 6808062..0852938 100644
--- a/src/vf/classifier_mac.c
+++ b/src/vf/classifier_mac.c
@@ -94,7 +94,7 @@ static rte_atomic16_t g_hash_table_count = RTE_ATOMIC16_INIT(0xff);
 /* initialize classifier table. */
 static int
 init_classifier_table(struct rte_hash **classifier_table,
-		struct spp_core_info *core_info)
+		const struct spp_core_info *core_info)
 {
 	int ret = -1;
 	int i;
@@ -142,9 +142,7 @@ init_classifier(const struct spp_core_info *core_info,
 {
 	int ret = -1;
 	int i;
-	struct ether_addr eth_addr;
 	char hash_table_name[HASH_TABLE_NAME_BUF_SZ];
-	char mac_addr_str[ETHER_ADDR_STR_BUF_SZ];
 
 	struct rte_hash **classifier_mac_table = NULL;
 
-- 
1.9.1

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

* [spp] [PATCH 08/57] spp_vf: modify data struct for upd command
  2017-12-26  1:54 ` Yasufumi Ogawa
                     ` (6 preceding siblings ...)
  2017-12-28  4:55   ` [spp] [PATCH 07/57] spp_vf: fix compiler warning in classifier_mac.c x-fn-spp
@ 2017-12-28  4:55   ` x-fn-spp
  2017-12-28  4:55   ` [spp] [PATCH 09/57] spp_vf: add functions of command acceptance x-fn-spp
                     ` (48 subsequent siblings)
  56 siblings, 0 replies; 97+ messages in thread
From: x-fn-spp @ 2017-12-28  4:55 UTC (permalink / raw)
  To: spp

From: Hiroyuki Nakamura <nakamura.hioryuki@po.ntt-tx.co.jp>

spp_vf supports command for modifying classifier table.
* Modify internal data structure to support this command.

Signed-off-by: Kentaro Watanabe <watanabe.kentaro.z01@as.ntt-tx.co.jp>
Signed-off-by: Yasufum Ogawa <ogawa.yasufumi@lab.ntt.co.jp>
---
 src/vf/spp_vf.c | 274 +++++++++++++++++++++++++++++++++++++++++++++++++++++---
 src/vf/spp_vf.h |  47 +++++++++-
 2 files changed, 307 insertions(+), 14 deletions(-)

diff --git a/src/vf/spp_vf.c b/src/vf/spp_vf.c
index 830aaaa..4fb25a4 100644
--- a/src/vf/spp_vf.c
+++ b/src/vf/spp_vf.c
@@ -1,3 +1,4 @@
+#include <netinet/in.h>
 #include <arpa/inet.h>
 #include <getopt.h>
 
@@ -21,19 +22,26 @@ enum SPP_LONGOPT_RETVAL {
 	/* add below */
 
 	SPP_LONGOPT_RETVAL_CONFIG,
+	SPP_LONGOPT_RETVAL_PROCESS_ID
 };
 
 /* struct */
 struct startup_param {
 	uint64_t cpu;
+	int process_id;
+	char server_ip[INET_ADDRSTRLEN];
+	int server_port;
 };
 
 struct patch_info {
-	int	use_flg;
-	int	dpdk_port;
-	struct spp_config_mac_table_element *mac_info;
-	struct spp_core_port_info *rx_core;
-	struct spp_core_port_info *tx_core;
+	int      use_flg;
+	int      dpdk_port;
+	int      rx_core_no;
+	int      tx_core_no;
+	char     mac_addr_str[SPP_CONFIG_STR_LEN];
+	uint64_t mac_addr;
+	struct   spp_core_port_info *rx_core;
+	struct   spp_core_port_info *tx_core;
 };
 
 struct if_info {
@@ -49,6 +57,7 @@ static struct spp_config_area	g_config;
 static struct startup_param	g_startup_param;
 static struct if_info		g_if_info;
 static struct spp_core_info	g_core_info[SPP_CONFIG_CORE_MAX];
+static int 			g_change_core[SPP_CONFIG_CORE_MAX];
 
 static char config_file_path[PATH_MAX];
 
@@ -58,9 +67,10 @@ static char config_file_path[PATH_MAX];
 static void
 usage(const char *progname)
 {
-	RTE_LOG(INFO, APP, "Usage: %s [EAL args] -- [--config CONFIG_FILE_PATH]\n"
-			" --config CONFIG_FILE_PATH: specific config file path\n"
-			"\n"
+	RTE_LOG(INFO, APP, "Usage: %s [EAL args] -- --process-id PROC_ID [--config CONFIG_FILE_PATH] -s SERVER_IP:SERVER_PORT\n"
+			" --process-id PROCESS_ID   : My process ID\n"
+			" --config CONFIG_FILE_PATH : specific config file path\n"
+			" -s SERVER_IP:SERVER_PORT  : Access information to the server\n"
 			, progname);
 }
 
@@ -294,6 +304,47 @@ parse_dpdk_args(int argc, char *argv[])
 }
 
 /*
+ * Parses the process ID of the application argument.
+ */
+static int
+parse_app_process_id(const char *process_id_str, int *process_id)
+{
+	int id = 0;
+	char *endptr = NULL;
+
+	id = strtol(process_id_str, &endptr, 0);
+	if (unlikely(process_id_str == endptr) || unlikely(*endptr != '\0'))
+		return -1;
+
+	*process_id = id;
+	RTE_LOG(DEBUG, APP, "Set process id = %d\n", *process_id);
+	return 0;
+}
+
+/*
+ * Parses server information of application arguments.
+ */
+static int
+parse_app_server(const char *server_str, char *server_ip, int *server_port)
+{
+	const char delim[2] = ":";
+	int pos = 0;
+	int port = 0;
+	char *endptr = NULL;
+
+	pos = strcspn(server_str, delim);
+	port = strtol(&server_str[pos+1], &endptr, 0);
+	if (unlikely(&server_str[pos+1] == endptr) || unlikely(*endptr != '\0'))
+		return -1;
+
+	memcpy(server_ip, server_str, pos);
+	*server_port = port;
+	RTE_LOG(DEBUG, APP, "Set server ip   = %s\n", server_ip);
+	RTE_LOG(DEBUG, APP, "Set server port = %d\n", *server_port);
+	return 0;
+}
+
+/*
  * Parse the application arguments to the client app.
  */
 static int
@@ -306,8 +357,9 @@ parse_app_args(int argc, char *argv[])
 	const char *progname = argv[0];
 	static struct option lgopts[] = { 
 			{ "config", required_argument, NULL, SPP_LONGOPT_RETVAL_CONFIG },
+			{ "process-id", required_argument, NULL, SPP_LONGOPT_RETVAL_PROCESS_ID },
 			{ 0 },
-	 };
+	};
 
 	/* getoptを使用するとargvが並び変わるみたいなので、コピーを実施 */
 	for (cnt = 0; cnt < argcopt; cnt++) {
@@ -317,7 +369,7 @@ parse_app_args(int argc, char *argv[])
 	/* Check application parameter */
 	optind = 0;
 	opterr = 0;
-	while ((opt = getopt_long(argc, argvopt, "", lgopts,
+	while ((opt = getopt_long(argc, argvopt, "s:", lgopts,
 			&option_index)) != EOF) {
 		switch (opt) {
 		case SPP_LONGOPT_RETVAL_CONFIG:
@@ -327,11 +379,31 @@ parse_app_args(int argc, char *argv[])
 			}
 			strcpy(config_file_path, optarg);
 			break;
+		case SPP_LONGOPT_RETVAL_PROCESS_ID:
+			if (parse_app_process_id(optarg, &g_startup_param.process_id) != 0) {
+				usage(progname);
+				return -1;
+			}
+			break;
+		case 's':
+			if (parse_app_server(optarg, g_startup_param.server_ip,
+					&g_startup_param.server_port) != 0) {
+				usage(progname);
+				return -1;
+			}
+			break;
 		default:
+			usage(progname);
+			return -1;
 			break;
 		}
 	}
 
+	RTE_LOG(INFO, APP, "application arguments value. (process id = %d, config = %s, server = %s:%d)\n",
+			g_startup_param.process_id,
+			config_file_path,
+			g_startup_param.server_ip,
+			g_startup_param.server_port);
 	return 0;
 }
 
@@ -364,7 +436,16 @@ get_if_area(enum port_type if_type, int if_no)
 static void
 init_if_info(void)
 {
+	int port_cnt;
 	memset(&g_if_info, 0x00, sizeof(g_if_info));
+	for (port_cnt = 0; port_cnt < RTE_MAX_ETHPORTS; port_cnt++) {
+		g_if_info.nic_patchs[port_cnt].rx_core_no   = -1;
+		g_if_info.nic_patchs[port_cnt].tx_core_no   = -1;
+		g_if_info.vhost_patchs[port_cnt].rx_core_no = -1;
+		g_if_info.vhost_patchs[port_cnt].tx_core_no = -1;
+		g_if_info.ring_patchs[port_cnt].rx_core_no  = -1;
+		g_if_info.ring_patchs[port_cnt].tx_core_no  = -1;
+	}
 }
 
 /*
@@ -376,11 +457,13 @@ init_core_info(void)
 	memset(&g_core_info, 0x00, sizeof(g_core_info));
 	int core_cnt, port_cnt;
 	for (core_cnt = 0; core_cnt < SPP_CONFIG_CORE_MAX; core_cnt++) {
+		g_core_info[core_cnt].lcore_id = core_cnt;
 		for (port_cnt = 0; port_cnt < RTE_MAX_ETHPORTS; port_cnt++) {
 			g_core_info[core_cnt].rx_ports[port_cnt].if_type = UNDEF;
 			g_core_info[core_cnt].tx_ports[port_cnt].if_type = UNDEF;
 		}
 	}
+	memset(g_change_core, 0x00, sizeof(g_change_core));
 }
 
 /*
@@ -440,7 +523,8 @@ set_form_proc_info(struct spp_config_area *config)
 			}
 
 			/* IF情報からCORE情報を変更する場合用に設定 */
-			patch_info->rx_core = &core_info->rx_ports[rx_start + rx_cnt];
+			patch_info->rx_core_no = core_cnt;
+			patch_info->rx_core    = &core_info->rx_ports[rx_start + rx_cnt];
 		}
 
 		/* Set TX port */
@@ -464,7 +548,8 @@ set_form_proc_info(struct spp_config_area *config)
 			}
 
 			/* IF情報からCORE情報を変更する場合用に設定 */
-			patch_info->tx_core = &core_info->tx_ports[tx_start + tx_cnt];
+			patch_info->tx_core_no = core_cnt;
+			patch_info->tx_core    = &core_info->tx_ports[tx_start + tx_cnt];
 		}
 	}
 
@@ -508,7 +593,8 @@ set_from_classifier_table(struct spp_config_area *config)
 
 		/* CORE情報側にもMACアドレスの情報設定 */
 		/* MACアドレスは送信側のみに影響する為、送信側のみ設定 */
-		patch_info->mac_info = mac_table;
+		patch_info->mac_addr = mac_table->mac_addr;
+		strcpy(patch_info->mac_addr_str, mac_table->mac_addr_str);
 		if (unlikely(patch_info->tx_core != NULL)) {
 			patch_info->tx_core->mac_addr = mac_table->mac_addr;
 			strcpy(patch_info->tx_core->mac_addr_str, mac_table->mac_addr_str);
@@ -864,6 +950,8 @@ ut_main(int argc, char *argv[])
 #else
 		{
 #endif
+			/* コマンド受付追加予定箇所           */
+			/* 戻り値等があれば、判定文も追加予定 */
 			sleep(1);
 
 #ifdef SPP_RINGLATENCYSTATS_ENABLE /* RING滞留時間 */
@@ -896,3 +984,163 @@ ut_main(int argc, char *argv[])
 	RTE_LOG(INFO, APP, "spp_vf exit.\n");
 	return ret;
 }
+
+/*
+ * Get process ID
+ */
+int
+spp_get_process_id(void)
+{
+	return g_startup_param.process_id;
+}
+
+/*
+ * Check the MAC address used on the interface
+ */
+static int
+check_mac_used_interface(uint64_t mac_addr, enum port_type *if_type, int *if_no)
+{
+	int cnt = 0;
+	for (cnt = 0; cnt < RTE_MAX_ETHPORTS; cnt++) {
+		if (unlikely(g_if_info.nic_patchs[cnt].mac_addr == mac_addr)) {
+			*if_type = PHY;
+			*if_no = cnt;
+			return 0;
+		}
+		if (unlikely(g_if_info.vhost_patchs[cnt].mac_addr == mac_addr)) {
+			*if_type = VHOST;
+			*if_no = cnt;
+			return 0;
+		}
+		if (unlikely(g_if_info.ring_patchs[cnt].mac_addr == mac_addr)) {
+			*if_type = RING;
+			*if_no = cnt;
+			return 0;
+		}
+	}
+	return -1;
+}
+
+/*
+ * Update Classifier_table
+ */
+int
+spp_update_classifier_table(
+		enum spp_classifier_type type,
+		const char *data,
+		struct spp_config_port_info *port)
+{
+	enum port_type if_type = UNDEF;
+        int if_no = 0;
+	struct patch_info *patch_info = NULL;
+	int64_t ret_mac = 0;
+	uint64_t mac_addr = 0;
+	int ret_used = 0;
+
+	if (type == SPP_CLASSIFIER_TYPE_MAC) {
+		RTE_LOG(DEBUG, APP, "update_classifier_table ( type = mac, data = %s, port = %d:%d )\n",
+				data, port->if_type, port->if_no);
+
+		ret_mac = spp_config_change_mac_str_to_int64(data);
+		if (unlikely(ret_mac == -1)) {
+			RTE_LOG(ERR, APP, "MAC address format error. ( mac = %s )\n", data);
+			return SPP_RET_NG;
+		}
+
+		mac_addr = (uint64_t)ret_mac;
+
+		ret_used = check_mac_used_interface(mac_addr, &if_type, &if_no);
+		if (port->if_type == UNDEF) {
+			/* Delete(unuse) */
+			if (ret_used < 0) {
+				RTE_LOG(DEBUG, APP, "No MAC address. ( mac = %s )\n", data);
+				return SPP_RET_OK;
+			}
+
+			patch_info = get_if_area(if_type, if_no);
+			if (unlikely(patch_info == NULL)) {
+				RTE_LOG(ERR, APP, "No port. ( port = %d:%d )\n", port->if_type, port->if_no);
+				return SPP_RET_NG;
+			}
+
+			patch_info->mac_addr = 0;
+			memset(patch_info->mac_addr_str, 0x00, SPP_CONFIG_STR_LEN);
+			if (patch_info->tx_core != NULL) {
+				patch_info->tx_core->mac_addr = 0;
+				memset(patch_info->tx_core->mac_addr_str, 0x00, SPP_CONFIG_STR_LEN);
+			}
+		}
+		else
+		{
+			/* Setting */
+			if (unlikely(ret_used == 0)) {
+				if (likely(port->if_type == if_type) && likely(port->if_no == if_no)) {
+					RTE_LOG(DEBUG, APP, "Same MAC address and port. ( mac = %s, port = %d:%d )\n",
+							data, if_type, if_no);
+					return SPP_RET_OK;
+				}
+				else
+				{
+					RTE_LOG(ERR, APP, "MAC address in used. ( mac = %s )\n", data);
+					return SPP_RET_USED_MAC;
+				}
+			}
+
+			patch_info = get_if_area(port->if_type, port->if_no);
+			if (unlikely(patch_info == NULL)) {
+				RTE_LOG(ERR, APP, "No port. ( port = %d:%d )\n", port->if_type, port->if_no);
+				return SPP_RET_NG;
+			}
+
+			if (unlikely(patch_info->use_flg != 0)) {
+				RTE_LOG(ERR, APP, "Port not added. ( port = %d:%d )\n", port->if_type, port->if_no);
+				return SPP_RET_NOT_ADD_PORT;
+			}
+
+			if (unlikely(patch_info->mac_addr != 0)) {
+				RTE_LOG(ERR, APP, "Port in used. ( port = %d:%d )\n", port->if_type, port->if_no);
+				return SPP_RET_USED_PORT;
+			}
+
+			patch_info->mac_addr = mac_addr;
+			strcpy(patch_info->mac_addr_str, data);
+			if (patch_info->tx_core != NULL) {
+				patch_info->tx_core->mac_addr = mac_addr;
+				strcpy(patch_info->tx_core->mac_addr_str, data);
+			}
+		}
+	}
+
+	/* 更新コマンドで設定した場合、コア毎に変更有無を保持 */
+	g_change_core[patch_info->tx_core_no] = 1;
+	return SPP_RET_OK;
+}
+
+/*
+ * Flush SPP component
+ */
+int
+spp_flush(void)
+{
+	int core_cnt = 0;
+	int ret_classifier = 0;
+	struct spp_core_info *core_info = NULL;
+
+	for(core_cnt = 0; core_cnt < SPP_CONFIG_CORE_MAX; core_cnt++) {
+		if (g_change_core[core_cnt] == 0)
+			continue;
+
+		core_info = &g_core_info[core_cnt];
+		if (core_info->type == SPP_CONFIG_CLASSIFIER_MAC) {
+//			ret_classifier = spp_classifier_mac_update(core_info);
+			if (unlikely(ret_classifier < 0)) {
+				RTE_LOG(ERR, APP, "Flush error. ( component = classifier_mac)\n");
+				return SPP_RET_NG;
+			}
+		}
+	}
+
+	/* 更新完了により変更したコアをクリア */
+	memset(g_change_core, 0x00, sizeof(g_change_core));
+	return SPP_RET_OK;
+}
diff --git a/src/vf/spp_vf.h b/src/vf/spp_vf.h
index c0faa57..f9707d7 100644
--- a/src/vf/spp_vf.h
+++ b/src/vf/spp_vf.h
@@ -4,6 +4,8 @@
 #include "common.h"
 #include "spp_config.h"
 
+#define SPP_PROCESS_MAX 128
+
 /*
  * State on core
  */
@@ -15,10 +17,29 @@ enum spp_core_status {
 };
 
 /*
+ * Classifier Type
+ */
+enum spp_classifier_type {
+	SPP_CLASSIFIER_TYPE_NONE,
+	SPP_CLASSIFIER_TYPE_MAC
+};
+
+/*
+ * API Return value
+ */
+enum spp_return_value {
+	SPP_RET_OK = 0,
+	SPP_RET_NG = -1,
+	SPP_RET_USED_MAC = -2,
+	SPP_RET_NOT_ADD_PORT = -3,
+	SPP_RET_USED_PORT = -4
+};
+
+/*
  * Port info on core
  */
 struct spp_core_port_info {
-	enum		port_type if_type;
+	enum port_type	if_type;
 	int		if_no;
 	int		dpdk_port;
 	uint64_t	mac_addr;
@@ -29,6 +50,7 @@ struct spp_core_port_info {
  * Core info
  */
 struct spp_core_info {
+	unsigned int lcore_id;
 	volatile enum spp_core_status status;
 	enum spp_core_type type;
 	int	num_rx_port;
@@ -37,4 +59,27 @@ struct spp_core_info {
 	struct spp_core_port_info tx_ports[RTE_MAX_ETHPORTS];
 };
 
+/*
+ * Get process ID
+ * RETURN : PROCESS ID(0~127)
+ */
+int spp_get_process_id(void);
+
+/*
+ * Update Classifier_table
+ * OK : SPP_RET_OK(0)
+ * NG : SPP_RET_NG(-1)
+ *    : SPP_RET_USED_MAC(-2)
+ *    : SPP_RET_NOT_ADD_PORT(-3)
+ *    : SPP_RET_USED_PORT(-4)
+ */
+int spp_update_classifier_table(enum spp_classifier_type type, const char *data, struct spp_config_port_info *port);
+
+/*
+ * Flush SPP component
+ * OK : SPP_RET_OK(0)
+ * NG : SPP_RET_NG(-1)
+ */
+int spp_flush(void);
+
 #endif /* __SPP_VF_H__ */
-- 
1.9.1

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

* [spp] [PATCH 09/57] spp_vf: add functions of command acceptance
  2017-12-26  1:54 ` Yasufumi Ogawa
                     ` (7 preceding siblings ...)
  2017-12-28  4:55   ` [spp] [PATCH 08/57] spp_vf: modify data struct for upd command x-fn-spp
@ 2017-12-28  4:55   ` x-fn-spp
  2017-12-28  4:55   ` [spp] [PATCH 10/57] spp_vf: add command acceptance calling x-fn-spp
                     ` (47 subsequent siblings)
  56 siblings, 0 replies; 97+ messages in thread
From: x-fn-spp @ 2017-12-28  4:55 UTC (permalink / raw)
  To: spp

From: Hiroyuki Nakamura <nakamura.hioryuki@po.ntt-tx.co.jp>

spp_vf supports command for modifying classifier table.
* Add functions of command acceptance.

Signed-off-by: Daiki Yamashita <yamashita.daiki.z01@as.ntt-tx.co.jp>
Signed-off-by: Yasufum Ogawa <ogawa.yasufumi@lab.ntt.co.jp>
---
 src/vf/Makefile       |   2 +-
 src/vf/command_proc.c | 669 ++++++++++++++++++++++++++++++++++++++++++++++++++
 src/vf/command_proc.h |  25 ++
 src/vf/spp_config.c   |  20 +-
 src/vf/spp_config.h   |  15 ++
 5 files changed, 720 insertions(+), 11 deletions(-)
 create mode 100644 src/vf/command_proc.c
 create mode 100644 src/vf/command_proc.h

diff --git a/src/vf/Makefile b/src/vf/Makefile
index 4961d2e..19617f6 100644
--- a/src/vf/Makefile
+++ b/src/vf/Makefile
@@ -40,7 +40,7 @@ include $(RTE_SDK)/mk/rte.vars.mk
 APP = spp_vf
 
 # all source are stored in SRCS-y
-SRCS-y := spp_vf.c spp_config.c classifier_mac.c spp_forward.c ringlatencystats.c ../shared/common.c
+SRCS-y := spp_vf.c spp_config.c classifier_mac.c spp_forward.c command_proc.c ringlatencystats.c ../shared/common.c
 
 CFLAGS += $(WERROR_FLAGS) -O3
 CFLAGS += -I$(SRCDIR)/../shared
diff --git a/src/vf/command_proc.c b/src/vf/command_proc.c
new file mode 100644
index 0000000..f8d368f
--- /dev/null
+++ b/src/vf/command_proc.c
@@ -0,0 +1,669 @@
+#include <unistd.h>
+#include <sys/types.h>
+#include <stdio.h>
+#include <string.h>
+#include <fcntl.h>
+#include <errno.h>
+#include <arpa/inet.h>
+
+#include <rte_common.h>
+#include <rte_log.h>
+#include <rte_branch_prediction.h>
+
+#include <jansson.h>
+
+#include "spp_vf.h"
+#include "spp_config.h"
+
+
+#define RTE_LOGTYPE_SPP_COMMAND_PROC RTE_LOGTYPE_USER1
+
+
+////////////////////////////////////////////////////////////////////////////////
+
+
+#define MESSAGE_BUFFER_BLOCK_SIZE 512
+
+static char g_controller_ip[128] = "";
+static int g_controller_port = 0;
+
+/*  */
+inline char*
+msgbuf_allocate(size_t capacity)
+{
+	char* buf = (char *)malloc(capacity + sizeof(size_t));
+	if (unlikely(buf == NULL))
+		return NULL;
+
+	*((size_t *)buf) = capacity;
+
+	return buf + sizeof(size_t);
+}
+
+/*  */
+inline void
+msgbuf_free(char* msgbuf)
+{
+	if (likely(msgbuf != NULL))
+		free(msgbuf - sizeof(size_t));
+}
+
+/*  */
+inline size_t
+msgbuf_get_capacity(const char *msgbuf)
+{
+	return *((const size_t *)(msgbuf - sizeof(size_t)));
+}
+
+/*  */
+inline char*
+msgbuf_reallocate(char *msgbuf, size_t required_len)
+{
+	size_t new_cap = msgbuf_get_capacity(msgbuf) * 2;
+	char *new_msgbuf = NULL;
+
+	while (unlikely(new_cap <= required_len))
+		new_cap *= 2;
+
+	new_msgbuf = msgbuf_allocate(new_cap);
+	if (unlikely(new_msgbuf == NULL))
+		return NULL;
+
+	strcpy(new_msgbuf, msgbuf);
+	msgbuf_free(msgbuf);
+
+	return new_msgbuf;
+}
+
+/*  */
+inline char*
+msgbuf_append(char *msgbuf, const char *append, size_t append_len)
+{
+	size_t cap = msgbuf_get_capacity(msgbuf);
+	size_t len = strlen(msgbuf);
+	char *new_msgbuf = msgbuf;
+
+	if (unlikely(len + append_len >= cap)) {
+		new_msgbuf = msgbuf_reallocate(msgbuf, len + append_len);
+		if (unlikely(new_msgbuf == NULL))
+			return NULL;
+	}
+
+	memcpy(new_msgbuf + len, append, append_len);
+	*(new_msgbuf + len + append_len) = '\0';
+
+	return new_msgbuf;
+}
+
+/*  */
+inline char*
+msgbuf_remove_front(char *msgbuf, size_t remove_len)
+{
+	size_t len = strlen(msgbuf);
+	size_t new_len = len - remove_len;
+
+	if (likely(new_len == 0)) {
+		*msgbuf = '\0';
+		return msgbuf;
+	}
+
+	return memmove(msgbuf, msgbuf + remove_len, new_len + 1);
+}
+
+/*  */
+static int
+connect_to_controller(int *sock)
+{
+	static struct sockaddr_in controller_addr;
+	int ret = -1;
+	int sock_flg = 0;
+
+	if (likely(*sock >=0))
+		return 0;
+
+	if (*sock < 0) {
+		*sock = socket(AF_INET, SOCK_STREAM, 0);
+		if (*sock < 0) {
+			RTE_LOG(ERR, SPP_COMMAND_PROC, 
+					"Cannot create tcp socket. errno=%d\n", errno);
+			return -1;
+		}
+
+		memset(&controller_addr, 0, sizeof(controller_addr));
+		controller_addr.sin_family = AF_INET;
+		controller_addr.sin_addr.s_addr = inet_addr(g_controller_ip);
+		controller_addr.sin_port = htons(g_controller_port);
+	}
+
+	ret = connect(*sock, (struct sockaddr *)&controller_addr,
+			sizeof(controller_addr));
+	if (ret < 0) {
+		RTE_LOG(ERR, SPP_COMMAND_PROC,
+				"Cannot connect to controller. errno=%d\n", errno);
+		return -1;
+	}
+
+	sock_flg = fcntl(*sock, F_GETFL, 0);
+	fcntl(*sock, F_SETFL, sock_flg | O_NONBLOCK);
+
+	return 0;
+}
+
+/*  */
+static int
+receive_request(int *sock, char **msgbuf)
+{
+	int ret = -1;
+	int n_rx = 0;
+	char *new_msgbuf = NULL;
+
+	char rx_buf[MESSAGE_BUFFER_BLOCK_SIZE];
+	size_t rx_buf_sz = MESSAGE_BUFFER_BLOCK_SIZE;
+
+	ret = recv(*sock, rx_buf, rx_buf_sz, 0);
+	if (ret <= 0) {
+		if (ret == 0) {
+
+		} else {
+			if (errno != EAGAIN && errno != EWOULDBLOCK) {
+				RTE_LOG(ERR, SPP_COMMAND_PROC,
+						"Cannot receive from socket. errno=%d\n", errno);
+			}
+			return 0;
+		}
+	}
+
+	n_rx = ret;
+
+	new_msgbuf = msgbuf_append(*msgbuf, rx_buf, n_rx);
+	if (unlikely(new_msgbuf == NULL)) {
+		return -1;
+	}
+
+	*msgbuf = new_msgbuf;
+
+	return n_rx;
+}
+
+/*  */
+static int
+send_response(void)
+{
+	return 0;
+}
+
+////////////////////////////////////////////////////////////////////////////////
+
+#define CMD_MAX_COMMANDS 32
+
+#define CMD_NAME_BUFSZ 32
+
+#define CMD_CLASSIFIER_TABLE_VALUE_BUFSZ 62
+
+#define component_type spp_core_type
+
+/* command type */
+enum command_type {
+	CMDTYPE_ADD,
+	CMDTYPE_COMPONENT,
+	CMDTYPE_CLASSIFIER_TABLE,
+	CMDTYPE_FLUSH,
+	CMDTYPE_FORWARD,
+	CMDTYPE_STOP,
+
+	CMDTYPE_PROCESS,
+};
+
+/* command type string list */
+static const char *COMMAND_TYPE_STRINGS[] = {
+	"add",
+	"component",
+	"classifier_table",
+	"flush",
+	"forward",
+	"stop",
+
+	/* termination */ "",
+};
+
+/* classifier type */
+enum classifier_type {
+	CLASSIFIERTYPE_MAC,	
+};
+
+/* classifier type string list */
+static const char *CLASSIFILER_TYPE_STRINGS[] = {
+	"mac",
+
+	/* termination */ "",
+};
+
+/* "add" command parameters */
+struct add_command {
+	struct spp_config_port_info ports[RTE_MAX_ETHPORTS];
+};
+
+/* "component" command specific parameters */
+struct component_command {
+	enum component_type type;
+	unsigned int core_id;
+	struct spp_config_port_info rx_ports[RTE_MAX_ETHPORTS];
+	struct spp_config_port_info tx_ports[RTE_MAX_ETHPORTS];
+};
+
+/* "classifier_table" command specific parameters */
+struct classifier_table_command {
+	enum classifier_type type;
+	char value[CMD_CLASSIFIER_TABLE_VALUE_BUFSZ];
+	struct spp_config_port_info port;
+};
+
+#if 0
+/* "flush" command specific parameters */
+struct flush_command {
+	/* nothing specific */
+};
+#endif
+
+/* command parameters */
+struct command {
+	enum command_type type;
+
+	union {
+		struct add_command add;
+		struct component_command component;
+		struct classifier_table_command classifier_table;
+	} spec;
+};
+
+/* request parameters */
+struct request {
+	int num_command;
+	struct command commands[CMD_MAX_COMMANDS];
+};
+
+/* forward declaration */
+struct json_value_decode_rule;
+
+/* definition of decode procedure function */
+typedef int (*json_value_decode_proc)(void *, const json_t *, const struct json_value_decode_rule *);
+
+/* rule definition that decode json object to c-struct */
+struct json_value_decode_rule {
+	char name[CMD_NAME_BUFSZ];
+	json_type json_type;
+	size_t offset;
+	json_value_decode_proc decode_proc;
+#if 0
+	union {
+		size_t buf_sz;
+	} spec;
+
+	json_type sub_json_type;
+	const struct json_value_decode_rule *sub_rules;
+#endif
+	size_t sub_offset;
+	size_t sub_offset_num;
+};
+
+/* get output address for decoded json value */
+#define DR_GET_OUTPUT(output_base, rule__) ((char *)output_base + rule__->offset)
+
+/* helper */
+#define END_OF_DECODE_RULE {.name = ""},
+#define IS_END_OF_DECODE_RULE(rule) ((rule)->name[0] == '\0')
+
+/* definition helper that enum value decode procedure */
+#define DECODE_ENUM_VALUE(proc_name, enum_type, string_table)			\
+int										\
+decode_##proc_name##_value(void *output, const json_t *value_obj,		\
+		const struct json_value_decode_rule *rule)			\
+{										\
+	int i;									\
+	enum_type type;								\
+	const char *str_val = json_string_value(value_obj);			\
+										\
+	for (i = 0; string_table[i][0] != '\0'; ++i) {				\
+		if (unlikely(strcmp(str_val, string_table[i]) == 0)) {		\
+			type = i;						\
+			memcpy(output, &type, sizeof(enum_type));		\
+			return 0;						\
+		}								\
+	}									\
+										\
+	return -1;								\
+}										\
+
+/* enum value decode procedure for "command_type" */
+DECODE_ENUM_VALUE(command_type, enum command_type, COMMAND_TYPE_STRINGS)
+
+/* enum value decode procedure for "classifier_type" */
+DECODE_ENUM_VALUE(classifier_type, enum classifier_type, CLASSIFILER_TYPE_STRINGS)
+
+/* decode procedure for integer */
+static int
+decode_int_value(void *output, const json_t *value_obj,
+		const struct json_value_decode_rule *rule)
+{
+	int val = json_integer_value(value_obj);
+	memcpy(output, &val, sizeof(int));
+
+	return 0;
+}
+
+/* decode procedure for string */
+static int
+decode_string_value(void *output, const json_t *value_obj,
+		const struct json_value_decode_rule *rule)
+{
+	const char* str_val = json_string_value(value_obj);
+#if 0
+	size_t len = strlen(str_val);
+	if (unlikely(len >= rule->spec.buf_sz)) {
+		RTE_LOG(ERR, SPP_COMMAND_PROC, "Invalid json value. "
+				"name=%s\n", rule->name);
+		return -1;
+	}
+#endif
+	strcpy(output, str_val);
+
+	return 0;
+}
+
+/* decode procedure for spp_config_port_info */
+static int
+decode_port_value(void *output, const json_t *value_obj,
+		const struct json_value_decode_rule *rule)
+{
+	int ret = -1;
+	struct spp_config_port_info *port = (struct spp_config_port_info *)output;
+
+	const char* str_val = json_string_value(value_obj);
+
+	ret = spp_config_get_if_info(str_val, &port->if_type, &port->if_no);
+	if (unlikely(ret != 0))
+		return -1;
+
+	return 0;
+}
+
+/* decode json object */
+static int
+decode_json_object(void *output, const json_t *parent_obj,
+		const struct json_value_decode_rule *rules)
+{
+	int ret = -1;
+	int i, n;
+	json_t *obj;
+	json_t *value_obj;
+	const struct json_value_decode_rule *rule;
+
+	void *sub_output;
+
+	for (i = 0; unlikely(! IS_END_OF_DECODE_RULE(&rules[i])); ++ i) {
+		rule = rules + 1;
+
+		value_obj = json_object_get(parent_obj, rule->name);
+		if (unlikely(value_obj == NULL) || 
+				unlikely(json_typeof(value_obj) != rule->json_type)) {
+			RTE_LOG(ERR, SPP_COMMAND_PROC, "Invalid json value. "
+					"name=%s\n", rule->name);
+			return -1;
+		}
+
+		switch (rule->json_type) {
+		case JSON_ARRAY:
+			json_array_foreach(value_obj, n, obj) {
+				sub_output = DR_GET_OUTPUT(output, rule) + (rule->sub_offset * i);
+				ret = (*rule->decode_proc)(sub_output, obj, rule);
+			}
+			*(int *)((char *)output + rule->sub_offset_num) = n;
+			break;
+		default:
+			sub_output = DR_GET_OUTPUT(output, rule);
+			ret = (*rule->decode_proc)(sub_output, value_obj, rule);
+			break;
+		}
+	}
+
+	return 0;
+}
+
+/*  */
+const struct json_value_decode_rule DECODERULE_COMMAND_BASE[] = {
+	{
+		.name = "command",
+		.json_type = JSON_STRING,
+		.offset = offsetof(struct command, type),
+		.decode_proc = decode_command_type_value,
+	},
+	END_OF_DECODE_RULE
+};
+
+/*  */
+const struct json_value_decode_rule DECODERULE_ADD_COMMAND[] = {
+	{
+		.name = "ports",
+		.json_type = JSON_ARRAY,
+		.offset = offsetof(struct add_command, ports),
+		.decode_proc = decode_port_value,
+//		.sub_json_type = JSON_STRING,
+		.sub_offset = sizeof(struct spp_config_port_info),
+	},
+	END_OF_DECODE_RULE
+};
+
+/*  */
+const struct json_value_decode_rule DECODERULE_CLASSIFIER_TABLE_COMMAND[] = {
+	{
+		.name = "type",
+		.json_type = JSON_STRING,
+		.offset = offsetof(struct classifier_table_command, type),
+		.decode_proc = decode_classifier_type_value,
+	},{
+		.name = "value",
+		.json_type = JSON_STRING,
+		.offset = offsetof(struct classifier_table_command, value),
+		.decode_proc = decode_string_value,
+	},{
+		.name = "port",
+		.json_type = JSON_STRING,
+		.offset = offsetof(struct classifier_table_command, port),
+		.decode_proc = decode_port_value,
+	},
+	END_OF_DECODE_RULE
+};
+
+/*  */
+static int
+decode_command_object(void* output, const json_t *parent_obj,
+		const struct json_value_decode_rule *rule)
+{
+	int ret = -1;
+	struct command *command = (struct command *)output;
+	const struct json_value_decode_rule *spec_rules = NULL;
+
+	/* decode command base */
+	ret = decode_json_object(command, parent_obj, DECODERULE_COMMAND_BASE);
+	if (unlikely(ret != 0)) {
+		// TODO:コマンドがデコード失敗
+		return -1;
+	}
+
+	/* decode command specific */
+	switch (command->type) {
+		case CMDTYPE_CLASSIFIER_TABLE:
+			spec_rules = DECODERULE_CLASSIFIER_TABLE_COMMAND;
+			break;
+
+		case CMDTYPE_FLUSH:
+			break;
+
+		default:
+			break;
+	}
+
+	if (likely(spec_rules != NULL)) {
+		ret = decode_json_object(&command->spec, parent_obj, spec_rules);
+		if (unlikely(ret != 0)) {
+			// TODO:コマンドがデコード失敗
+			return -1;
+		}
+	}
+
+	return 0;
+}
+
+/*  */
+const struct json_value_decode_rule DECODERULE_REQUEST[] = {
+	{
+		.name = "commands",
+		.json_type = JSON_ARRAY,
+		.offset = offsetof(struct request, commands),
+		.decode_proc = decode_command_object,
+//		.sub_json_type = JSON_OBJECT,
+		.sub_offset = sizeof(struct command),
+		.sub_offset_num = offsetof(struct request, num_command),
+	},
+	END_OF_DECODE_RULE
+};
+
+/*  */
+static int
+decode_request(struct request *request, json_t **top_obj, const char *request_str, size_t request_str_len)
+{
+	int ret = -1;
+	int i;
+	json_error_t json_error;
+
+	/* parse json string */
+	*top_obj = json_loadb(request_str, request_str_len, 0, &json_error);
+	if (unlikely(*top_obj == NULL)) {
+		RTE_LOG(ERR, SPP_COMMAND_PROC, "Cannot parse command request. "
+				"error=%s\n", 
+				json_error.text);
+		return -1;
+	}
+
+	/* decode request object */
+	ret = decode_json_object(request, *top_obj, DECODERULE_REQUEST);
+	if (unlikely(ret != 0)) {
+		// TODO:エラー
+		return -1;
+	}
+
+	return 0;
+}
+
+/*  */
+static int
+execute_command(const struct command *command)
+{
+	int ret = -1;
+
+	switch (command->type) {
+	case CMDTYPE_CLASSIFIER_TABLE:
+		ret = spp_update_classifier_table(
+				SPP_CLASSIFIER_TYPE_MAC,
+//				command->spec.classifier_table.type,
+				command->spec.classifier_table.value,
+				&command->spec.classifier_table.port);
+		break;
+
+	case CMDTYPE_FLUSH:
+		ret = spp_flush();
+		break;
+
+	case CMDTYPE_PROCESS:
+		break;
+
+	default:
+		ret = 0;
+		break;
+	}
+
+	return 0;
+}
+
+/*  */
+static int
+process_request(const char *request_str, size_t request_str_len)
+{
+	int ret = -1;
+	int i;
+
+	struct request request;
+	json_t *top_obj;
+
+	memset(&request, 0, sizeof(struct request));
+
+	ret = decode_request(&request, &top_obj, request_str, request_str_len);
+	if (unlikely(ret != 0))
+		return -1;
+
+	for (i = 0; i < request.num_command ; ++i) {
+		ret = execute_command(request.commands + i);
+	}
+}
+
+
+////////////////////////////////////////////////////////////////////////////////
+
+
+/*  */
+int
+spp_command_proc_init(const char *controller_ip, int controller_port)
+{
+	strcpy(g_controller_ip, controller_ip);
+	g_controller_port = controller_port;
+
+	return 0;
+}
+
+/*  */
+void
+spp_command_proc_do(void)
+{
+	int ret = -1;
+	int i;
+
+	static int sock = -1;
+	static char *msgbuf = NULL;
+	static size_t msg_len = 0;
+
+	static size_t rb_cnt = 0;
+	static size_t lb_cnt = 0;
+
+	if (unlikely(msgbuf == NULL))
+		msgbuf = msgbuf_allocate(MESSAGE_BUFFER_BLOCK_SIZE);
+
+	ret = connect_to_controller(&sock);
+	if (unlikely(ret != 0))
+		return;
+
+	ret = receive_request(&sock, &msgbuf);
+	if (likely(ret == 0)) {
+		return;
+	}
+
+	for (i = 0; i < ret; ++i) {
+		switch (*(msgbuf + msg_len + i)) {
+		case '{':
+			++lb_cnt;
+			break;
+		case '}':
+			++rb_cnt;
+			break;
+		}
+
+		if (likely(lb_cnt != 0) && unlikely(rb_cnt == lb_cnt)) {
+			msg_len += (i + 1);
+			ret = process_request(msgbuf, msg_len);
+
+			msgbuf_remove_front(msgbuf, msg_len);
+			msg_len = 0;
+			rb_cnt = 0;
+			lb_cnt = 0;
+		}
+	}
+}
diff --git a/src/vf/command_proc.h b/src/vf/command_proc.h
new file mode 100644
index 0000000..8774070
--- /dev/null
+++ b/src/vf/command_proc.h
@@ -0,0 +1,25 @@
+#ifndef _COMMAND_PROC_H_
+#define _COMMAND_PROC_H_
+
+/**
+ * intialize command processor.
+ *
+ * @param controller_ip
+ *  controller listen ip address.
+ *
+ * @param controller_port
+ *  controller listen port number.
+ *
+ * @ret_val 0 succeeded.
+ * @ret_val -1 failed.
+ */
+int
+spp_command_proc_init(const char *controller_ip, int controller_port);
+
+/**
+ * process command from controller.
+ */
+void
+spp_command_proc_do(void);
+
+#endif /* _COMMAND_PROC_H_ */
diff --git a/src/vf/spp_config.c b/src/vf/spp_config.c
index 1794e84..4ad4f87 100644
--- a/src/vf/spp_config.c
+++ b/src/vf/spp_config.c
@@ -104,8 +104,8 @@ config_init_data(struct spp_config_area *config)
  * IFの情報からIF種別とIF番号を取得する
  * ("ring0" -> 種別:"ring"、番号:0)
  */
-static int
-config_get_if_info(const char *port, enum port_type *if_type, int *if_no)
+int
+spp_config_get_if_info(const char *port, enum port_type *if_type, int *if_no)
 {
 	enum port_type type = UNDEF;
 	const char *no_str = NULL;
@@ -150,8 +150,8 @@ config_get_if_info(const char *port, enum port_type *if_type, int *if_no)
 /*
  * MAC addressを文字列から数値へ変換
  */
-static int64_t
-config_change_mac_str_to_int64(const char *mac)
+int64_t
+spp_config_change_mac_str_to_int64(const char *mac)
 {
 	int64_t ret_mac = 0;
 	int64_t token_val = 0;
@@ -270,7 +270,7 @@ config_load_classifier_table(const json_t *obj,
 		}
 
 		/* MACアドレス数値変換 */
-		int64_t ret_mac64 = config_change_mac_str_to_int64(
+		int64_t ret_mac64 = spp_config_change_mac_str_to_int64(
 				tmp_table->mac_addr_str);
 		if (unlikely(ret_mac64 == -1)) {
 			RTE_LOG(ERR, APP,
@@ -291,7 +291,7 @@ config_load_classifier_table(const json_t *obj,
 		}
 
 		/* IF種別とIF番号に分割 */
-		int ret_if = config_get_if_info(if_str, &tmp_table->port.if_type,
+		int ret_if = spp_config_get_if_info(if_str, &tmp_table->port.if_type,
 				&tmp_table->port.if_no);
 		if (unlikely(ret_if != 0)) {
 			RTE_LOG(ERR, APP,
@@ -385,7 +385,7 @@ config_set_rx_port(enum spp_core_type type, json_t *obj,
 			strcpy(if_str, json_string_value(elements_obj));
 
 			/* IF種別とIF番号に分割 */
-			int ret_if = config_get_if_info(if_str, &tmp_rx_port->if_type,
+			int ret_if = spp_config_get_if_info(if_str, &tmp_rx_port->if_type,
 					&tmp_rx_port->if_no);
 			if (unlikely(ret_if != 0)) {
 				RTE_LOG(ERR, APP,
@@ -407,7 +407,7 @@ config_set_rx_port(enum spp_core_type type, json_t *obj,
 		}
 
 		/* IF種別とIF番号に分割 */
-		int ret_if = config_get_if_info(if_str, &tmp_rx_port->if_type,
+		int ret_if = spp_config_get_if_info(if_str, &tmp_rx_port->if_type,
 				&tmp_rx_port->if_no);
 		if (unlikely(ret_if != 0)) {
 			RTE_LOG(ERR, APP,
@@ -444,7 +444,7 @@ config_set_tx_port(enum spp_core_type type, json_t *obj,
 		}
 
 		/* IF種別とIF番号に分割 */
-		int ret_if = config_get_if_info(if_str, &tmp_tx_port->if_type,
+		int ret_if = spp_config_get_if_info(if_str, &tmp_tx_port->if_type,
 				&tmp_tx_port->if_no);
 		if (unlikely(ret_if != 0)) {
 			RTE_LOG(ERR, APP,
@@ -520,7 +520,7 @@ config_set_tx_port(enum spp_core_type type, json_t *obj,
 				strcpy(if_str, json_string_value(elements_obj));
 
 				/* IF種別とIF番号に分割 */
-				int ret_if = config_get_if_info(if_str, &tmp_tx_port->if_type,
+				int ret_if = spp_config_get_if_info(if_str, &tmp_tx_port->if_type,
 						&tmp_tx_port->if_no);
 				if (unlikely(ret_if != 0)) {
 					RTE_LOG(ERR, APP,
diff --git a/src/vf/spp_config.h b/src/vf/spp_config.h
index 24ddd32..37414cf 100644
--- a/src/vf/spp_config.h
+++ b/src/vf/spp_config.h
@@ -81,6 +81,21 @@ struct spp_config_area {
 };
 
 /*
+ * Change mac address string to int64
+ * OK : int64 that store mac address
+ * NG : -1
+ */
+int64_t spp_config_change_mac_str_to_int64(const char *mac);
+
+/*
+ * Extract if-type/if-number from port string
+ *
+ * OK : 0
+ * NG : -1
+ */
+int spp_config_get_if_info(const char *port, enum port_type *if_type, int *if_no);
+
+/*
  * Load config file
  * OK : 0
  * NG : -1
-- 
1.9.1

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

* [spp] [PATCH 10/57] spp_vf: add command acceptance calling
  2017-12-26  1:54 ` Yasufumi Ogawa
                     ` (8 preceding siblings ...)
  2017-12-28  4:55   ` [spp] [PATCH 09/57] spp_vf: add functions of command acceptance x-fn-spp
@ 2017-12-28  4:55   ` x-fn-spp
  2017-12-28  4:55   ` [spp] [PATCH 11/57] spp_vf: fix compiler warning in command_proc.c x-fn-spp
                     ` (46 subsequent siblings)
  56 siblings, 0 replies; 97+ messages in thread
From: x-fn-spp @ 2017-12-28  4:55 UTC (permalink / raw)
  To: spp

From: Hiroyuki Nakamura <nakamura.hioryuki@po.ntt-tx.co.jp>

spp_vf supports command for modifying classifier table.
* Add functions for command acceptance.

Signed-off-by: Kentaro Watanabe <watanabe.kentaro.z01@as.ntt-tx.co.jp>
Signed-off-by: Yasufum Ogawa <ogawa.yasufumi@lab.ntt.co.jp>
---
 src/vf/spp_vf.c | 17 ++++++++++++++---
 1 file changed, 14 insertions(+), 3 deletions(-)

diff --git a/src/vf/spp_vf.c b/src/vf/spp_vf.c
index 4fb25a4..805c582 100644
--- a/src/vf/spp_vf.c
+++ b/src/vf/spp_vf.c
@@ -10,6 +10,7 @@
 #include "ringlatencystats.h"
 #include "classifier_mac.h"
 #include "spp_forward.h"
+#include "command_proc.h"
 
 /* define */
 #define SPP_CORE_STATUS_CHECK_MAX 5
@@ -910,6 +911,14 @@ ut_main(int argc, char *argv[])
 		}
 
 		/* 他機能部初期化 */
+		/* コマンド機能部初期化 */
+		int ret_command_init = spp_command_proc_init(
+				g_startup_param.server_ip,
+				g_startup_param.server_port);
+		if (unlikely(ret_command_init != 0)) {
+			break;
+		}
+
 #ifdef SPP_RINGLATENCYSTATS_ENABLE /* RING滞留時間 */
 		int ret_ringlatency = spp_ringlatencystats_init(
 				SPP_RING_LATENCY_STATS_SAMPLING_INTERVAL, g_if_info.num_ring);
@@ -950,8 +959,10 @@ ut_main(int argc, char *argv[])
 #else
 		{
 #endif
-			/* コマンド受付追加予定箇所           */
-			/* 戻り値等があれば、判定文も追加予定 */
+			/* コマンド受付 */
+			spp_command_proc_do();
+
+			/* CPUを占有しない様に1秒スリープ */
 			sleep(1);
 
 #ifdef SPP_RINGLATENCYSTATS_ENABLE /* RING滞留時間 */
@@ -1132,7 +1143,7 @@ spp_flush(void)
 
 		core_info = &g_core_info[core_cnt];
 		if (core_info->type == SPP_CONFIG_CLASSIFIER_MAC) {
-//			ret_classifier = spp_classifier_mac_update(core_info);
+			ret_classifier = spp_classifier_mac_update(core_info);
 			if (unlikely(ret_classifier < 0)) {
 				RTE_LOG(ERR, APP, "Flush error. ( component = classifier_mac)\n");
 				return SPP_RET_NG;
-- 
1.9.1

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

* [spp] [PATCH 11/57] spp_vf: fix compiler warning in command_proc.c
  2017-12-26  1:54 ` Yasufumi Ogawa
                     ` (9 preceding siblings ...)
  2017-12-28  4:55   ` [spp] [PATCH 10/57] spp_vf: add command acceptance calling x-fn-spp
@ 2017-12-28  4:55   ` x-fn-spp
  2017-12-28  4:55   ` [spp] [PATCH 12/57] " x-fn-spp
                     ` (45 subsequent siblings)
  56 siblings, 0 replies; 97+ messages in thread
From: x-fn-spp @ 2017-12-28  4:55 UTC (permalink / raw)
  To: spp

From: Hiroyuki Nakamura <nakamura.hioryuki@po.ntt-tx.co.jp>

* Add include header.
* Add variable declaration.
* Mark unused parameter.
* Add comment and log.

Signed-off-by: Daiki Yamashita <yamashita.daiki.z01@as.ntt-tx.co.jp>
Signed-off-by: Yasufum Ogawa <ogawa.yasufumi@lab.ntt.co.jp>
---
 src/vf/command_proc.c | 42 ++++++++++++++++++++++--------------------
 1 file changed, 22 insertions(+), 20 deletions(-)

diff --git a/src/vf/command_proc.c b/src/vf/command_proc.c
index f8d368f..7a5ed56 100644
--- a/src/vf/command_proc.c
+++ b/src/vf/command_proc.c
@@ -14,6 +14,7 @@
 
 #include "spp_vf.h"
 #include "spp_config.h"
+#include "command_proc.h"
 
 
 #define RTE_LOGTYPE_SPP_COMMAND_PROC RTE_LOGTYPE_USER1
@@ -279,6 +280,7 @@ struct command {
 /* request parameters */
 struct request {
 	int num_command;
+	int num_valid_command;
 	struct command commands[CMD_MAX_COMMANDS];
 };
 
@@ -315,9 +317,9 @@ struct json_value_decode_rule {
 
 /* definition helper that enum value decode procedure */
 #define DECODE_ENUM_VALUE(proc_name, enum_type, string_table)			\
-int										\
+static int									\
 decode_##proc_name##_value(void *output, const json_t *value_obj,		\
-		const struct json_value_decode_rule *rule)			\
+		__rte_unused const struct json_value_decode_rule *rule)		\
 {										\
 	int i;									\
 	enum_type type;								\
@@ -343,7 +345,7 @@ DECODE_ENUM_VALUE(classifier_type, enum classifier_type, CLASSIFILER_TYPE_STRING
 /* decode procedure for integer */
 static int
 decode_int_value(void *output, const json_t *value_obj,
-		const struct json_value_decode_rule *rule)
+		__rte_unused const struct json_value_decode_rule *rule)
 {
 	int val = json_integer_value(value_obj);
 	memcpy(output, &val, sizeof(int));
@@ -354,7 +356,7 @@ decode_int_value(void *output, const json_t *value_obj,
 /* decode procedure for string */
 static int
 decode_string_value(void *output, const json_t *value_obj,
-		const struct json_value_decode_rule *rule)
+		__rte_unused const struct json_value_decode_rule *rule)
 {
 	const char* str_val = json_string_value(value_obj);
 #if 0
@@ -373,7 +375,7 @@ decode_string_value(void *output, const json_t *value_obj,
 /* decode procedure for spp_config_port_info */
 static int
 decode_port_value(void *output, const json_t *value_obj,
-		const struct json_value_decode_rule *rule)
+		__rte_unused const struct json_value_decode_rule *rule)
 {
 	int ret = -1;
 	struct spp_config_port_info *port = (struct spp_config_port_info *)output;
@@ -477,7 +479,7 @@ const struct json_value_decode_rule DECODERULE_CLASSIFIER_TABLE_COMMAND[] = {
 /*  */
 static int
 decode_command_object(void* output, const json_t *parent_obj,
-		const struct json_value_decode_rule *rule)
+		__rte_unused const struct json_value_decode_rule *rule)
 {
 	int ret = -1;
 	struct command *command = (struct command *)output;
@@ -530,23 +532,23 @@ const struct json_value_decode_rule DECODERULE_REQUEST[] = {
 
 /*  */
 static int
-decode_request(struct request *request, json_t **top_obj, const char *request_str, size_t request_str_len)
+decode_request(struct request *request, const char *request_str, size_t request_str_len)
 {
 	int ret = -1;
-	int i;
+	json_t *top_obj;
 	json_error_t json_error;
 
 	/* parse json string */
-	*top_obj = json_loadb(request_str, request_str_len, 0, &json_error);
+	top_obj = json_loadb(request_str, request_str_len, 0, &json_error);
 	if (unlikely(*top_obj == NULL)) {
 		RTE_LOG(ERR, SPP_COMMAND_PROC, "Cannot parse command request. "
-				"error=%s\n", 
-				json_error.text);
+				"error=%s, request_str=%.*s\n", 
+				json_error.text, request_str_len, request_str);
 		return -1;
 	}
 
 	/* decode request object */
-	ret = decode_json_object(request, *top_obj, DECODERULE_REQUEST);
+	ret = decode_json_object(request, top_obj, DECODERULE_REQUEST);
 	if (unlikely(ret != 0)) {
 		// TODO:エラー
 		return -1;
@@ -593,24 +595,24 @@ process_request(const char *request_str, size_t request_str_len)
 	int i;
 
 	struct request request;
-	json_t *top_obj;
+
+	RTE_LOG(DEBUG, SPP_COMMAND_PROC, "Receive command request. "
+			"request_str=%.*s\n", request_str_len, request_str);
 
 	memset(&request, 0, sizeof(struct request));
 
-	ret = decode_request(&request, &top_obj, request_str, request_str_len);
+	ret = decode_request(&request, request_str, request_str_len);
 	if (unlikely(ret != 0))
 		return -1;
 
 	for (i = 0; i < request.num_command ; ++i) {
 		ret = execute_command(request.commands + i);
 	}
-}
-
-
-////////////////////////////////////////////////////////////////////////////////
 
+	return 0;
+}
 
-/*  */
+/* initialize command processor. */
 int
 spp_command_proc_init(const char *controller_ip, int controller_port)
 {
@@ -620,7 +622,7 @@ spp_command_proc_init(const char *controller_ip, int controller_port)
 	return 0;
 }
 
-/*  */
+/* process command from controller. */
 void
 spp_command_proc_do(void)
 {
-- 
1.9.1

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

* [spp] [PATCH 12/57] spp_vf: fix compiler warning in command_proc.c
  2017-12-26  1:54 ` Yasufumi Ogawa
                     ` (10 preceding siblings ...)
  2017-12-28  4:55   ` [spp] [PATCH 11/57] spp_vf: fix compiler warning in command_proc.c x-fn-spp
@ 2017-12-28  4:55   ` x-fn-spp
  2017-12-28  4:55   ` [spp] [PATCH 13/57] spp_vf: refactor command acceptance/decode x-fn-spp
                     ` (44 subsequent siblings)
  56 siblings, 0 replies; 97+ messages in thread
From: x-fn-spp @ 2017-12-28  4:55 UTC (permalink / raw)
  To: spp

From: Hiroyuki Nakamura <nakamura.hioryuki@po.ntt-tx.co.jp>

* Fix type unmatch.
* Refactor log.

Signed-off-by: Daiki Yamashita <yamashita.daiki.z01@as.ntt-tx.co.jp>
Signed-off-by: Yasufum Ogawa <ogawa.yasufumi@lab.ntt.co.jp>
---
 src/vf/command_proc.c | 10 ++++++----
 1 file changed, 6 insertions(+), 4 deletions(-)

diff --git a/src/vf/command_proc.c b/src/vf/command_proc.c
index 7a5ed56..d203857 100644
--- a/src/vf/command_proc.c
+++ b/src/vf/command_proc.c
@@ -540,17 +540,19 @@ decode_request(struct request *request, const char *request_str, size_t request_
 
 	/* parse json string */
 	top_obj = json_loadb(request_str, request_str_len, 0, &json_error);
-	if (unlikely(*top_obj == NULL)) {
+	if (unlikely(top_obj == NULL)) {
 		RTE_LOG(ERR, SPP_COMMAND_PROC, "Cannot parse command request. "
 				"error=%s, request_str=%.*s\n", 
-				json_error.text, request_str_len, request_str);
+				json_error.text, (int)request_str_len, request_str);
 		return -1;
 	}
 
 	/* decode request object */
 	ret = decode_json_object(request, top_obj, DECODERULE_REQUEST);
 	if (unlikely(ret != 0)) {
-		// TODO:エラー
+		RTE_LOG(ERR, SPP_COMMAND_PROC, "Cannot decode command request. "
+				"ret=%d, request_str=%.*s\n", 
+				ret, (int)request_str_len, request_str);
 		return -1;
 	}
 
@@ -597,7 +599,7 @@ process_request(const char *request_str, size_t request_str_len)
 	struct request request;
 
 	RTE_LOG(DEBUG, SPP_COMMAND_PROC, "Receive command request. "
-			"request_str=%.*s\n", request_str_len, request_str);
+			"request_str=%.*s\n", (int)request_str_len, request_str);
 
 	memset(&request, 0, sizeof(struct request));
 
-- 
1.9.1

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

* [spp] [PATCH 13/57] spp_vf: refactor command acceptance/decode
  2017-12-26  1:54 ` Yasufumi Ogawa
                     ` (11 preceding siblings ...)
  2017-12-28  4:55   ` [spp] [PATCH 12/57] " x-fn-spp
@ 2017-12-28  4:55   ` x-fn-spp
  2017-12-28  4:55   ` [spp] [PATCH 14/57] spp_vf: fix return value overwrite problem x-fn-spp
                     ` (43 subsequent siblings)
  56 siblings, 0 replies; 97+ messages in thread
From: x-fn-spp @ 2017-12-28  4:55 UTC (permalink / raw)
  To: spp

From: Hiroyuki Nakamura <nakamura.hioryuki@po.ntt-tx.co.jp>

* Add/Refactor comment and log.
* Add error handling.
* Add strict check(MAC address, iface string).
* Refactor json->internal-structure converting.

Signed-off-by: Daiki Yamashita <yamashita.daiki.z01@as.ntt-tx.co.jp>
Signed-off-by: Yasufum Ogawa <ogawa.yasufumi@lab.ntt.co.jp>
---
 src/vf/command_proc.c | 300 +++++++++++++++++++++++++++++++++++---------------
 1 file changed, 210 insertions(+), 90 deletions(-)

diff --git a/src/vf/command_proc.c b/src/vf/command_proc.c
index d203857..d8e7fd1 100644
--- a/src/vf/command_proc.c
+++ b/src/vf/command_proc.c
@@ -16,19 +16,25 @@
 #include "spp_config.h"
 #include "command_proc.h"
 
-
 #define RTE_LOGTYPE_SPP_COMMAND_PROC RTE_LOGTYPE_USER1
 
 
-////////////////////////////////////////////////////////////////////////////////
-
+/*******************************************************************************
+ *
+ * operate connection with controller
+ *
+ ******************************************************************************/
 
+/* receive message buffer size */
 #define MESSAGE_BUFFER_BLOCK_SIZE 512
 
+/* controller's ip address */
 static char g_controller_ip[128] = "";
+
+/* controller's port number */
 static int g_controller_port = 0;
 
-/*  */
+/* allocate message buffer */
 inline char*
 msgbuf_allocate(size_t capacity)
 {
@@ -41,7 +47,7 @@ msgbuf_allocate(size_t capacity)
 	return buf + sizeof(size_t);
 }
 
-/*  */
+/* free message buffer */
 inline void
 msgbuf_free(char* msgbuf)
 {
@@ -49,14 +55,14 @@ msgbuf_free(char* msgbuf)
 		free(msgbuf - sizeof(size_t));
 }
 
-/*  */
+/* get message buffer capacity */
 inline size_t
 msgbuf_get_capacity(const char *msgbuf)
 {
 	return *((const size_t *)(msgbuf - sizeof(size_t)));
 }
 
-/*  */
+/* re-allocate message buffer */
 inline char*
 msgbuf_reallocate(char *msgbuf, size_t required_len)
 {
@@ -76,7 +82,7 @@ msgbuf_reallocate(char *msgbuf, size_t required_len)
 	return new_msgbuf;
 }
 
-/*  */
+/* append message to buffer */
 inline char*
 msgbuf_append(char *msgbuf, const char *append, size_t append_len)
 {
@@ -96,7 +102,7 @@ msgbuf_append(char *msgbuf, const char *append, size_t append_len)
 	return new_msgbuf;
 }
 
-/*  */
+/* remove message from front */
 inline char*
 msgbuf_remove_front(char *msgbuf, size_t remove_len)
 {
@@ -111,7 +117,7 @@ msgbuf_remove_front(char *msgbuf, size_t remove_len)
 	return memmove(msgbuf, msgbuf + remove_len, new_len + 1);
 }
 
-/*  */
+/* connect to controller */
 static int
 connect_to_controller(int *sock)
 {
@@ -122,7 +128,9 @@ connect_to_controller(int *sock)
 	if (likely(*sock >=0))
 		return 0;
 
+	/* create socket */
 	if (*sock < 0) {
+		RTE_LOG(INFO, SPP_COMMAND_PROC, "Creating socket...\n");
 		*sock = socket(AF_INET, SOCK_STREAM, 0);
 		if (*sock < 0) {
 			RTE_LOG(ERR, SPP_COMMAND_PROC, 
@@ -136,6 +144,8 @@ connect_to_controller(int *sock)
 		controller_addr.sin_port = htons(g_controller_port);
 	}
 
+	/* connect to */
+	RTE_LOG(INFO, SPP_COMMAND_PROC, "Trying to connect ... socket=%d\n", *sock);
 	ret = connect(*sock, (struct sockaddr *)&controller_addr,
 			sizeof(controller_addr));
 	if (ret < 0) {
@@ -144,15 +154,18 @@ connect_to_controller(int *sock)
 		return -1;
 	}
 
+	RTE_LOG(INFO, SPP_COMMAND_PROC, "Connected\n");
+
+	/* set non-blocking */
 	sock_flg = fcntl(*sock, F_GETFL, 0);
 	fcntl(*sock, F_SETFL, sock_flg | O_NONBLOCK);
 
 	return 0;
 }
 
-/*  */
+/* receive message */
 static int
-receive_request(int *sock, char **msgbuf)
+receive_message(int *sock, char **msgbuf)
 {
 	int ret = -1;
 	int n_rx = 0;
@@ -162,16 +175,23 @@ receive_request(int *sock, char **msgbuf)
 	size_t rx_buf_sz = MESSAGE_BUFFER_BLOCK_SIZE;
 
 	ret = recv(*sock, rx_buf, rx_buf_sz, 0);
+	RTE_LOG(DEBUG, SPP_COMMAND_PROC, "Receive message. count=%d\n", ret);
 	if (ret <= 0) {
 		if (ret == 0) {
-
-		} else {
-			if (errno != EAGAIN && errno != EWOULDBLOCK) {
-				RTE_LOG(ERR, SPP_COMMAND_PROC,
-						"Cannot receive from socket. errno=%d\n", errno);
-			}
+			RTE_LOG(INFO, SPP_COMMAND_PROC,
+					"Controller has performed an shutdown.");
+		} else if (errno == EAGAIN || errno == EWOULDBLOCK) {
+			/* no receive message */
 			return 0;
+		} else {
+			RTE_LOG(ERR, SPP_COMMAND_PROC,
+					"Receive failure. errno=%d\n", errno);
 		}
+
+		RTE_LOG(INFO, SPP_COMMAND_PROC, "Assume Server closed connection\n");
+		close(*sock);
+		*sock = -1;
+		return -1;
 	}
 
 	n_rx = ret;
@@ -186,14 +206,27 @@ receive_request(int *sock, char **msgbuf)
 	return n_rx;
 }
 
-/*  */
+/* send message */
 static int
-send_response(void)
+send_message(int *sock, const char* message, size_t message_len)
 {
+	int ret = -1;
+
+	ret = send(*sock, message, message_len, 0);
+	if (unlikely(ret == -1)) {
+		RTE_LOG(ERR, SPP_COMMAND_PROC, "Send failure. ret=%d\n", ret);
+		return -1;
+	}
+
 	return 0;
 }
 
-////////////////////////////////////////////////////////////////////////////////
+
+/*******************************************************************************
+ *
+ * process command request(json string)
+ *
+ ******************************************************************************/
 
 #define CMD_MAX_COMMANDS 32
 
@@ -201,9 +234,21 @@ send_response(void)
 
 #define CMD_CLASSIFIER_TABLE_VALUE_BUFSZ 62
 
+#define CMD_UNUSE "unuse"
+
 #define component_type spp_core_type
 
-/* command type */
+/* decode error code */
+enum decode_error_code {
+	DERR_BAD_FORMAT = 1,
+	DERR_UNKNOWN_COMMAND,
+	DERR_NO_PARAM,
+	DERR_BAD_TYPE,
+	DERR_BAD_VALUE,
+};
+
+/* command type
+	do it same as the order of COMMAND_TYPE_STRINGS */
 enum command_type {
 	CMDTYPE_ADD,
 	CMDTYPE_COMPONENT,
@@ -215,7 +260,8 @@ enum command_type {
 	CMDTYPE_PROCESS,
 };
 
-/* command type string list */
+/* command type string list
+	do it same as the order of enum command_type */
 static const char *COMMAND_TYPE_STRINGS[] = {
 	"add",
 	"component",
@@ -227,20 +273,19 @@ static const char *COMMAND_TYPE_STRINGS[] = {
 	/* termination */ "",
 };
 
-/* classifier type */
-enum classifier_type {
-	CLASSIFIERTYPE_MAC,	
-};
-
-/* classifier type string list */
+/* classifier type string list
+	do it same as the order of enum spp_classifier_type (spp_vf.h) */
 static const char *CLASSIFILER_TYPE_STRINGS[] = {
+	"none",
 	"mac",
 
 	/* termination */ "",
 };
 
+#if 0 /* not supported */
 /* "add" command parameters */
 struct add_command {
+	int num_port;
 	struct spp_config_port_info ports[RTE_MAX_ETHPORTS];
 };
 
@@ -248,32 +293,36 @@ struct add_command {
 struct component_command {
 	enum component_type type;
 	unsigned int core_id;
+	int num_rx_port;
+	int num_tx_port;
 	struct spp_config_port_info rx_ports[RTE_MAX_ETHPORTS];
 	struct spp_config_port_info tx_ports[RTE_MAX_ETHPORTS];
 };
+#endif
 
 /* "classifier_table" command specific parameters */
 struct classifier_table_command {
-	enum classifier_type type;
+	enum spp_classifier_type type;
 	char value[CMD_CLASSIFIER_TABLE_VALUE_BUFSZ];
 	struct spp_config_port_info port;
 };
 
-#if 0
 /* "flush" command specific parameters */
 struct flush_command {
 	/* nothing specific */
 };
-#endif
 
 /* command parameters */
 struct command {
 	enum command_type type;
 
 	union {
+#if 0 /* not supported */
 		struct add_command add;
 		struct component_command component;
+#endif
 		struct classifier_table_command classifier_table;
+		struct flush_command flush;
 	} spec;
 };
 
@@ -296,16 +345,13 @@ struct json_value_decode_rule {
 	json_type json_type;
 	size_t offset;
 	json_value_decode_proc decode_proc;
-#if 0
-	union {
-		size_t buf_sz;
-	} spec;
 
-	json_type sub_json_type;
-	const struct json_value_decode_rule *sub_rules;
-#endif
-	size_t sub_offset;
-	size_t sub_offset_num;
+	struct {
+		json_type json_type;
+		size_t element_sz;
+		size_t offset_num;
+		size_t offset_num_valid;
+	} array;
 };
 
 /* get output address for decoded json value */
@@ -340,8 +386,9 @@ decode_##proc_name##_value(void *output, const json_t *value_obj,		\
 DECODE_ENUM_VALUE(command_type, enum command_type, COMMAND_TYPE_STRINGS)
 
 /* enum value decode procedure for "classifier_type" */
-DECODE_ENUM_VALUE(classifier_type, enum classifier_type, CLASSIFILER_TYPE_STRINGS)
+DECODE_ENUM_VALUE(classifier_type, enum spp_classifier_type, CLASSIFILER_TYPE_STRINGS)
 
+#if 0 /* not supported */
 /* decode procedure for integer */
 static int
 decode_int_value(void *output, const json_t *value_obj,
@@ -359,14 +406,27 @@ decode_string_value(void *output, const json_t *value_obj,
 		__rte_unused const struct json_value_decode_rule *rule)
 {
 	const char* str_val = json_string_value(value_obj);
-#if 0
-	size_t len = strlen(str_val);
-	if (unlikely(len >= rule->spec.buf_sz)) {
-		RTE_LOG(ERR, SPP_COMMAND_PROC, "Invalid json value. "
-				"name=%s\n", rule->name);
-		return -1;
-	}
+	strcpy(output, str_val);
+
+	return 0;
+}
 #endif
+
+/* decode procedure for mac address string */
+static int
+decode_mac_addr_str_value(void *output, const json_t *value_obj,
+		__rte_unused const struct json_value_decode_rule *rule)
+{
+	int ret = -1;
+	const char* str_val = json_string_value(value_obj);
+
+	ret = spp_config_change_mac_str_to_int64(str_val);
+	if (unlikely(ret == -1)) {
+		RTE_LOG(ERR, SPP_COMMAND_PROC, "Bad mac address string. val=%s\n",
+				str_val);
+		return DERR_BAD_VALUE;
+	}
+
 	strcpy(output, str_val);
 
 	return 0;
@@ -378,13 +438,20 @@ decode_port_value(void *output, const json_t *value_obj,
 		__rte_unused const struct json_value_decode_rule *rule)
 {
 	int ret = -1;
+	const char* str_val = json_string_value(value_obj);
 	struct spp_config_port_info *port = (struct spp_config_port_info *)output;
 
-	const char* str_val = json_string_value(value_obj);
+	if (strcmp(str_val, CMD_UNUSE) == 0) {
+		port->if_type = UNDEF;
+		port->if_no = 0;
+		return 0;
+	}
 
 	ret = spp_config_get_if_info(str_val, &port->if_type, &port->if_no);
-	if (unlikely(ret != 0))
-		return -1;
+	if (unlikely(ret != 0)) {
+		RTE_LOG(ERR, SPP_COMMAND_PROC, "Bad port. val=%s\n", str_val);
+		return DERR_BAD_VALUE;
+	}
 
 	return 0;
 }
@@ -405,25 +472,56 @@ decode_json_object(void *output, const json_t *parent_obj,
 	for (i = 0; unlikely(! IS_END_OF_DECODE_RULE(&rules[i])); ++ i) {
 		rule = rules + 1;
 
+		RTE_LOG(DEBUG, SPP_COMMAND_PROC, "get one object. name=%s\n",
+				rule->name);
+
 		value_obj = json_object_get(parent_obj, rule->name);
-		if (unlikely(value_obj == NULL) || 
-				unlikely(json_typeof(value_obj) != rule->json_type)) {
-			RTE_LOG(ERR, SPP_COMMAND_PROC, "Invalid json value. "
+		if (unlikely(value_obj == NULL)) {
+			RTE_LOG(ERR, SPP_COMMAND_PROC, "No parameter. "
 					"name=%s\n", rule->name);
-			return -1;
+			return DERR_NO_PARAM;
+		} else if (unlikely(json_typeof(value_obj) != rule->json_type)) {
+			RTE_LOG(ERR, SPP_COMMAND_PROC, "Bad value type. "
+					"name=%s\n", rule->name);
+			return DERR_BAD_TYPE;
 		}
 
 		switch (rule->json_type) {
 		case JSON_ARRAY:
+			RTE_LOG(DEBUG, SPP_COMMAND_PROC, "Decode array. num=%lu\n",
+					json_array_size(value_obj));
+
+			*(int *)((char *)output + rule->array.offset_num) = 
+					(int)json_array_size(value_obj);
+
 			json_array_foreach(value_obj, n, obj) {
-				sub_output = DR_GET_OUTPUT(output, rule) + (rule->sub_offset * i);
+				RTE_LOG(DEBUG, SPP_COMMAND_PROC, "Decode array element. "
+						"index=%d\n", i);
+				
+				if (unlikely(json_typeof(obj) != rule->array.json_type)) {
+					RTE_LOG(ERR, SPP_COMMAND_PROC, "Bad value type. "
+							"name=%s, index=%d\n", rule->name, i);
+					return DERR_BAD_TYPE;
+				}
+
+				sub_output = DR_GET_OUTPUT(output, rule) + 
+						(rule->array.element_sz * i);
 				ret = (*rule->decode_proc)(sub_output, obj, rule);
+				if (unlikely(ret != 0)) {
+					RTE_LOG(ERR, SPP_COMMAND_PROC, "Bad value. "
+							"name=%s, index=%d\n", rule->name, i);
+					return ret;
+				}
 			}
-			*(int *)((char *)output + rule->sub_offset_num) = n;
 			break;
 		default:
 			sub_output = DR_GET_OUTPUT(output, rule);
 			ret = (*rule->decode_proc)(sub_output, value_obj, rule);
+			if (unlikely(ret != 0)) {
+				RTE_LOG(ERR, SPP_COMMAND_PROC, "Bad value. "
+						"name=%s\n", rule->name);
+				return ret;
+			}
 			break;
 		}
 	}
@@ -431,7 +529,7 @@ decode_json_object(void *output, const json_t *parent_obj,
 	return 0;
 }
 
-/*  */
+/* decode rule for command-base */
 const struct json_value_decode_rule DECODERULE_COMMAND_BASE[] = {
 	{
 		.name = "command",
@@ -442,20 +540,24 @@ const struct json_value_decode_rule DECODERULE_COMMAND_BASE[] = {
 	END_OF_DECODE_RULE
 };
 
-/*  */
+#if 0 /* not supported */
+/* decode rule for add-command-spec */
 const struct json_value_decode_rule DECODERULE_ADD_COMMAND[] = {
 	{
 		.name = "ports",
 		.json_type = JSON_ARRAY,
 		.offset = offsetof(struct add_command, ports),
 		.decode_proc = decode_port_value,
-//		.sub_json_type = JSON_STRING,
-		.sub_offset = sizeof(struct spp_config_port_info),
+
+		.array.element_sz = sizeof(struct spp_config_port_info),
+		.array.json_type = JSON_STRING,
+		.array.offset_num = offsetof(struct add_command, num_port),
 	},
 	END_OF_DECODE_RULE
 };
+#endif
 
-/*  */
+/* decode rule for classifier-table-command-spec */
 const struct json_value_decode_rule DECODERULE_CLASSIFIER_TABLE_COMMAND[] = {
 	{
 		.name = "type",
@@ -466,7 +568,7 @@ const struct json_value_decode_rule DECODERULE_CLASSIFIER_TABLE_COMMAND[] = {
 		.name = "value",
 		.json_type = JSON_STRING,
 		.offset = offsetof(struct classifier_table_command, value),
-		.decode_proc = decode_string_value,
+		.decode_proc = decode_mac_addr_str_value,
 	},{
 		.name = "port",
 		.json_type = JSON_STRING,
@@ -476,7 +578,7 @@ const struct json_value_decode_rule DECODERULE_CLASSIFIER_TABLE_COMMAND[] = {
 	END_OF_DECODE_RULE
 };
 
-/*  */
+/* decode procedure for command */
 static int
 decode_command_object(void* output, const json_t *parent_obj,
 		__rte_unused const struct json_value_decode_rule *rule)
@@ -485,52 +587,58 @@ decode_command_object(void* output, const json_t *parent_obj,
 	struct command *command = (struct command *)output;
 	const struct json_value_decode_rule *spec_rules = NULL;
 
-	/* decode command base */
+	/* decode command-base */
 	ret = decode_json_object(command, parent_obj, DECODERULE_COMMAND_BASE);
 	if (unlikely(ret != 0)) {
-		// TODO:コマンドがデコード失敗
-		return -1;
+		RTE_LOG(ERR, SPP_COMMAND_PROC, "Bad command. ret=%d\n", ret);
+		return ret;
 	}
 
-	/* decode command specific */
+	/* decode command-specific */
 	switch (command->type) {
 		case CMDTYPE_CLASSIFIER_TABLE:
 			spec_rules = DECODERULE_CLASSIFIER_TABLE_COMMAND;
 			break;
 
 		case CMDTYPE_FLUSH:
+			/* nothing specific */
 			break;
 
 		default:
-			break;
+			/* unknown command */
+			RTE_LOG(ERR, SPP_COMMAND_PROC, "Unknown command. type=%d\n",
+					command->type);
+			return DERR_UNKNOWN_COMMAND;
 	}
 
 	if (likely(spec_rules != NULL)) {
 		ret = decode_json_object(&command->spec, parent_obj, spec_rules);
 		if (unlikely(ret != 0)) {
-			// TODO:コマンドがデコード失敗
-			return -1;
+			RTE_LOG(ERR, SPP_COMMAND_PROC, "Bad command. ret=%d\n", ret);
+			return ret;
 		}
 	}
 
 	return 0;
 }
 
-/*  */
+/* decode rule for command request */
 const struct json_value_decode_rule DECODERULE_REQUEST[] = {
 	{
 		.name = "commands",
 		.json_type = JSON_ARRAY,
 		.offset = offsetof(struct request, commands),
 		.decode_proc = decode_command_object,
-//		.sub_json_type = JSON_OBJECT,
-		.sub_offset = sizeof(struct command),
-		.sub_offset_num = offsetof(struct request, num_command),
+
+		.array.element_sz = sizeof(struct command),
+		.array.json_type = JSON_OBJECT,
+		.array.offset_num = offsetof(struct request, num_command),
+		.array.offset_num_valid = offsetof(struct request, num_valid_command),
 	},
 	END_OF_DECODE_RULE
 };
 
-/*  */
+/* decode request from no-null-terminated string */
 static int
 decode_request(struct request *request, const char *request_str, size_t request_str_len)
 {
@@ -544,7 +652,7 @@ decode_request(struct request *request, const char *request_str, size_t request_
 		RTE_LOG(ERR, SPP_COMMAND_PROC, "Cannot parse command request. "
 				"error=%s, request_str=%.*s\n", 
 				json_error.text, (int)request_str_len, request_str);
-		return -1;
+		return DERR_BAD_FORMAT;
 	}
 
 	/* decode request object */
@@ -553,13 +661,13 @@ decode_request(struct request *request, const char *request_str, size_t request_
 		RTE_LOG(ERR, SPP_COMMAND_PROC, "Cannot decode command request. "
 				"ret=%d, request_str=%.*s\n", 
 				ret, (int)request_str_len, request_str);
-		return -1;
+		return ret;
 	}
 
 	return 0;
 }
 
-/*  */
+/* execute one command */
 static int
 execute_command(const struct command *command)
 {
@@ -567,29 +675,33 @@ execute_command(const struct command *command)
 
 	switch (command->type) {
 	case CMDTYPE_CLASSIFIER_TABLE:
+		RTE_LOG(DEBUG, SPP_COMMAND_PROC, "Execute classifier_table command.");
 		ret = spp_update_classifier_table(
-				SPP_CLASSIFIER_TYPE_MAC,
-//				command->spec.classifier_table.type,
+				command->spec.classifier_table.type,
 				command->spec.classifier_table.value,
 				&command->spec.classifier_table.port);
 		break;
 
 	case CMDTYPE_FLUSH:
+		RTE_LOG(DEBUG, SPP_COMMAND_PROC, "Execute flush command.");
 		ret = spp_flush();
 		break;
 
 	case CMDTYPE_PROCESS:
+		RTE_LOG(DEBUG, SPP_COMMAND_PROC, "Execute process command.");
+		ret = spp_get_process_id();
 		break;
 
 	default:
+		RTE_LOG(ERR, SPP_COMMAND_PROC, "Unknown command. type=%d\n", command->type);
 		ret = 0;
 		break;
 	}
 
-	return 0;
+	return ret;
 }
 
-/*  */
+/* process command request from no-null-terminated string */
 static int
 process_request(const char *request_str, size_t request_str_len)
 {
@@ -597,20 +709,28 @@ process_request(const char *request_str, size_t request_str_len)
 	int i;
 
 	struct request request;
+	memset(&request, 0, sizeof(struct request));
 
-	RTE_LOG(DEBUG, SPP_COMMAND_PROC, "Receive command request. "
+	RTE_LOG(DEBUG, SPP_COMMAND_PROC, "Start command request processing. "
 			"request_str=%.*s\n", (int)request_str_len, request_str);
 
-	memset(&request, 0, sizeof(struct request));
-
 	ret = decode_request(&request, request_str, request_str_len);
-	if (unlikely(ret != 0))
-		return -1;
+	if (unlikely(ret != 0)) {
+		RTE_LOG(DEBUG, SPP_COMMAND_PROC, "Failed to process command request. "
+		"ret=%d\n", ret);
+		return ret;
+	}
+
+	RTE_LOG(DEBUG, SPP_COMMAND_PROC, "Decoded command request. "
+			"num_command=%d, num_valid_command=%d\n",
+			request.num_command, request.num_valid_command);
 
 	for (i = 0; i < request.num_command ; ++i) {
 		ret = execute_command(request.commands + i);
 	}
 
+	RTE_LOG(DEBUG, SPP_COMMAND_PROC, "Succeeded to process command request.\n");
+
 	return 0;
 }
 
@@ -645,7 +765,7 @@ spp_command_proc_do(void)
 	if (unlikely(ret != 0))
 		return;
 
-	ret = receive_request(&sock, &msgbuf);
+	ret = receive_message(&sock, &msgbuf);
 	if (likely(ret == 0)) {
 		return;
 	}
-- 
1.9.1

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

* [spp] [PATCH 14/57] spp_vf: fix return value overwrite problem
  2017-12-26  1:54 ` Yasufumi Ogawa
                     ` (12 preceding siblings ...)
  2017-12-28  4:55   ` [spp] [PATCH 13/57] spp_vf: refactor command acceptance/decode x-fn-spp
@ 2017-12-28  4:55   ` x-fn-spp
  2017-12-28  4:55   ` [spp] [PATCH 15/57] spp_vf: initialize message buffer x-fn-spp
                     ` (42 subsequent siblings)
  56 siblings, 0 replies; 97+ messages in thread
From: x-fn-spp @ 2017-12-28  4:55 UTC (permalink / raw)
  To: spp

From: Hiroyuki Nakamura <nakamura.hioryuki@po.ntt-tx.co.jp>

Add new variable for saving the return value of receive_message()
to avoid overwrite problem.

Signed-off-by: Kentaro Watanabe <watanabe.kentaro.z01@as.ntt-tx.co.jp>
Signed-off-by: Yasufum Ogawa <ogawa.yasufumi@lab.ntt.co.jp>
---
 src/vf/command_proc.c | 10 +++++++---
 1 file changed, 7 insertions(+), 3 deletions(-)

diff --git a/src/vf/command_proc.c b/src/vf/command_proc.c
index d8e7fd1..3ec4f5b 100644
--- a/src/vf/command_proc.c
+++ b/src/vf/command_proc.c
@@ -749,6 +749,7 @@ void
 spp_command_proc_do(void)
 {
 	int ret = -1;
+	int msg_ret = -1;
 	int i;
 
 	static int sock = -1;
@@ -765,12 +766,12 @@ spp_command_proc_do(void)
 	if (unlikely(ret != 0))
 		return;
 
-	ret = receive_message(&sock, &msgbuf);
-	if (likely(ret == 0)) {
+	msg_ret = receive_message(&sock, &msgbuf);
+	if (likely(msg_ret == 0)) {
 		return;
 	}
 
-	for (i = 0; i < ret; ++i) {
+	for (i = 0; i < msg_ret; ++i) {
 		switch (*(msgbuf + msg_len + i)) {
 		case '{':
 			++lb_cnt;
@@ -785,9 +786,12 @@ spp_command_proc_do(void)
 			ret = process_request(msgbuf, msg_len);
 
 			msgbuf_remove_front(msgbuf, msg_len);
+			msg_ret = 0;
 			msg_len = 0;
 			rb_cnt = 0;
 			lb_cnt = 0;
 		}
 	}
+
+	msg_len = msg_len + msg_ret;
 }
-- 
1.9.1

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

* [spp] [PATCH 15/57] spp_vf: initialize message buffer
  2017-12-26  1:54 ` Yasufumi Ogawa
                     ` (13 preceding siblings ...)
  2017-12-28  4:55   ` [spp] [PATCH 14/57] spp_vf: fix return value overwrite problem x-fn-spp
@ 2017-12-28  4:55   ` x-fn-spp
  2017-12-28  4:55   ` [spp] [PATCH 16/57] spp_vf: add const keyword to parameter x-fn-spp
                     ` (41 subsequent siblings)
  56 siblings, 0 replies; 97+ messages in thread
From: x-fn-spp @ 2017-12-28  4:55 UTC (permalink / raw)
  To: spp

From: Hiroyuki Nakamura <nakamura.hioryuki@po.ntt-tx.co.jp>

Clear the message buffer by character '\0'.

Signed-off-by: Kentaro Watanabe <watanabe.kentaro.z01@as.ntt-tx.co.jp>
Signed-off-by: Yasufum Ogawa <ogawa.yasufumi@lab.ntt.co.jp>
---
 src/vf/command_proc.c | 1 +
 1 file changed, 1 insertion(+)

diff --git a/src/vf/command_proc.c b/src/vf/command_proc.c
index 3ec4f5b..6ff817f 100644
--- a/src/vf/command_proc.c
+++ b/src/vf/command_proc.c
@@ -42,6 +42,7 @@ msgbuf_allocate(size_t capacity)
 	if (unlikely(buf == NULL))
 		return NULL;
 
+	memset(buf, 0x00, capacity + sizeof(size_t));
 	*((size_t *)buf) = capacity;
 
 	return buf + sizeof(size_t);
-- 
1.9.1

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

* [spp] [PATCH 16/57] spp_vf: add const keyword to parameter
  2017-12-26  1:54 ` Yasufumi Ogawa
                     ` (14 preceding siblings ...)
  2017-12-28  4:55   ` [spp] [PATCH 15/57] spp_vf: initialize message buffer x-fn-spp
@ 2017-12-28  4:55   ` x-fn-spp
  2017-12-28  4:55   ` [spp] [PATCH 17/57] spp_vf: fix wrong comparison operator x-fn-spp
                     ` (40 subsequent siblings)
  56 siblings, 0 replies; 97+ messages in thread
From: x-fn-spp @ 2017-12-28  4:55 UTC (permalink / raw)
  To: spp

From: Hiroyuki Nakamura <nakamura.hioryuki@po.ntt-tx.co.jp>

spp_vf supports command for modifying classifier table.
* Misc. modifications.

* Add const keyword to parameter.

Signed-off-by: Kentaro Watanabe <watanabe.kentaro.z01@as.ntt-tx.co.jp>
Signed-off-by: Yasufum Ogawa <ogawa.yasufumi@lab.ntt.co.jp>
---
 src/vf/spp_vf.c | 2 +-
 src/vf/spp_vf.h | 2 +-
 2 files changed, 2 insertions(+), 2 deletions(-)

diff --git a/src/vf/spp_vf.c b/src/vf/spp_vf.c
index 805c582..45ab6c6 100644
--- a/src/vf/spp_vf.c
+++ b/src/vf/spp_vf.c
@@ -1039,7 +1039,7 @@ int
 spp_update_classifier_table(
 		enum spp_classifier_type type,
 		const char *data,
-		struct spp_config_port_info *port)
+		const struct spp_config_port_info *port)
 {
 	enum port_type if_type = UNDEF;
         int if_no = 0;
diff --git a/src/vf/spp_vf.h b/src/vf/spp_vf.h
index f9707d7..4ca4568 100644
--- a/src/vf/spp_vf.h
+++ b/src/vf/spp_vf.h
@@ -73,7 +73,7 @@ int spp_get_process_id(void);
  *    : SPP_RET_NOT_ADD_PORT(-3)
  *    : SPP_RET_USED_PORT(-4)
  */
-int spp_update_classifier_table(enum spp_classifier_type type, const char *data, struct spp_config_port_info *port);
+int spp_update_classifier_table(enum spp_classifier_type type, const char *data, const struct spp_config_port_info *port);
 
 /*
  * Flush SPP component
-- 
1.9.1

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

* [spp] [PATCH 17/57] spp_vf: fix wrong comparison operator
  2017-12-26  1:54 ` Yasufumi Ogawa
                     ` (15 preceding siblings ...)
  2017-12-28  4:55   ` [spp] [PATCH 16/57] spp_vf: add const keyword to parameter x-fn-spp
@ 2017-12-28  4:55   ` x-fn-spp
  2017-12-28  4:55   ` [spp] [PATCH 18/57] spp_vf: fix wrong variable to be assigned x-fn-spp
                     ` (39 subsequent siblings)
  56 siblings, 0 replies; 97+ messages in thread
From: x-fn-spp @ 2017-12-28  4:55 UTC (permalink / raw)
  To: spp

From: Hiroyuki Nakamura <nakamura.hioryuki@po.ntt-tx.co.jp>

Signed-off-by: Kentaro Watanabe <watanabe.kentaro.z01@as.ntt-tx.co.jp>
Signed-off-by: Yasufum Ogawa <ogawa.yasufumi@lab.ntt.co.jp>
---
 src/vf/command_proc.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/src/vf/command_proc.c b/src/vf/command_proc.c
index 6ff817f..1de43f8 100644
--- a/src/vf/command_proc.c
+++ b/src/vf/command_proc.c
@@ -768,7 +768,7 @@ spp_command_proc_do(void)
 		return;
 
 	msg_ret = receive_message(&sock, &msgbuf);
-	if (likely(msg_ret == 0)) {
+	if (likely(msg_ret <= 0)) {
 		return;
 	}
 
-- 
1.9.1

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

* [spp] [PATCH 18/57] spp_vf: fix wrong variable to be assigned
  2017-12-26  1:54 ` Yasufumi Ogawa
                     ` (16 preceding siblings ...)
  2017-12-28  4:55   ` [spp] [PATCH 17/57] spp_vf: fix wrong comparison operator x-fn-spp
@ 2017-12-28  4:55   ` x-fn-spp
  2017-12-28  4:55   ` [spp] [PATCH 19/57] spp_vf: refactor parsing server ip address x-fn-spp
                     ` (38 subsequent siblings)
  56 siblings, 0 replies; 97+ messages in thread
From: x-fn-spp @ 2017-12-28  4:55 UTC (permalink / raw)
  To: spp

From: Hiroyuki Nakamura <nakamura.hioryuki@po.ntt-tx.co.jp>

Signed-off-by: Kentaro Watanabe <watanabe.kentaro.z01@as.ntt-tx.co.jp>
Signed-off-by: Yasufum Ogawa <ogawa.yasufumi@lab.ntt.co.jp>
---
 src/vf/spp_vf.c | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/src/vf/spp_vf.c b/src/vf/spp_vf.c
index 45ab6c6..208dd30 100644
--- a/src/vf/spp_vf.c
+++ b/src/vf/spp_vf.c
@@ -524,7 +524,7 @@ set_form_proc_info(struct spp_config_area *config)
 			}
 
 			/* IF情報からCORE情報を変更する場合用に設定 */
-			patch_info->rx_core_no = core_cnt;
+			patch_info->rx_core_no = core_func->core_no;
 			patch_info->rx_core    = &core_info->rx_ports[rx_start + rx_cnt];
 		}
 
@@ -549,7 +549,7 @@ set_form_proc_info(struct spp_config_area *config)
 			}
 
 			/* IF情報からCORE情報を変更する場合用に設定 */
-			patch_info->tx_core_no = core_cnt;
+			patch_info->tx_core_no = core_func->core_no;
 			patch_info->tx_core    = &core_info->tx_ports[tx_start + tx_cnt];
 		}
 	}
-- 
1.9.1

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

* [spp] [PATCH 19/57] spp_vf: refactor parsing server ip address
  2017-12-26  1:54 ` Yasufumi Ogawa
                     ` (17 preceding siblings ...)
  2017-12-28  4:55   ` [spp] [PATCH 18/57] spp_vf: fix wrong variable to be assigned x-fn-spp
@ 2017-12-28  4:55   ` x-fn-spp
  2017-12-28  4:55   ` [spp] [PATCH 20/57] spp_vf: fix error in command decode x-fn-spp
                     ` (37 subsequent siblings)
  56 siblings, 0 replies; 97+ messages in thread
From: x-fn-spp @ 2017-12-28  4:55 UTC (permalink / raw)
  To: spp

From: Hiroyuki Nakamura <nakamura.hioryuki@po.ntt-tx.co.jp>

The following two changes are made in parse_app_server()
in order to get server IP address.
* Check the number of characters in IP address string.
* Add terminator '\0' to IP address string.

Signed-off-by: Kentaro Watanabe <watanabe.kentaro.z01@as.ntt-tx.co.jp>
Signed-off-by: Yasufum Ogawa <ogawa.yasufumi@lab.ntt.co.jp>
---
 src/vf/spp_vf.c | 6 +++++-
 1 file changed, 5 insertions(+), 1 deletion(-)

diff --git a/src/vf/spp_vf.c b/src/vf/spp_vf.c
index 7bb1ac0..e5dc1c9 100644
--- a/src/vf/spp_vf.c
+++ b/src/vf/spp_vf.c
@@ -329,16 +329,20 @@ static int
 parse_app_server(const char *server_str, char *server_ip, int *server_port)
 {
 	const char delim[2] = ":";
-	int pos = 0;
+	unsigned int pos = 0;
 	int port = 0;
 	char *endptr = NULL;
 
 	pos = strcspn(server_str, delim);
+	if (pos >= strlen(server_str))
+		return -1;
+
 	port = strtol(&server_str[pos+1], &endptr, 0);
 	if (unlikely(&server_str[pos+1] == endptr) || unlikely(*endptr != '\0'))
 		return -1;
 
 	memcpy(server_ip, server_str, pos);
+	server_ip[pos] = '\0';
 	*server_port = port;
 	RTE_LOG(DEBUG, APP, "Set server ip   = %s\n", server_ip);
 	RTE_LOG(DEBUG, APP, "Set server port = %d\n", *server_port);
-- 
1.9.1

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

* [spp] [PATCH 20/57] spp_vf: fix error in command decode
  2017-12-26  1:54 ` Yasufumi Ogawa
                     ` (18 preceding siblings ...)
  2017-12-28  4:55   ` [spp] [PATCH 19/57] spp_vf: refactor parsing server ip address x-fn-spp
@ 2017-12-28  4:55   ` x-fn-spp
  2017-12-28  4:55   ` [spp] [PATCH 21/57] spp_vf: fix comparison operator in spp_vf.c x-fn-spp
                     ` (36 subsequent siblings)
  56 siblings, 0 replies; 97+ messages in thread
From: x-fn-spp @ 2017-12-28  4:55 UTC (permalink / raw)
  To: spp

From: Hiroyuki Nakamura <nakamura.hioryuki@po.ntt-tx.co.jp>

Fix wrong counter variable to be used.

Signed-off-by: Kentaro Watanabe <watanabe.kentaro.z01@as.ntt-tx.co.jp>
Signed-off-by: Yasufum Ogawa <ogawa.yasufumi@lab.ntt.co.jp>
---
 src/vf/command_proc.c | 10 +++++-----
 1 file changed, 5 insertions(+), 5 deletions(-)

diff --git a/src/vf/command_proc.c b/src/vf/command_proc.c
index 1de43f8..bec762e 100644
--- a/src/vf/command_proc.c
+++ b/src/vf/command_proc.c
@@ -471,7 +471,7 @@ decode_json_object(void *output, const json_t *parent_obj,
 	void *sub_output;
 
 	for (i = 0; unlikely(! IS_END_OF_DECODE_RULE(&rules[i])); ++ i) {
-		rule = rules + 1;
+		rule = rules + i;
 
 		RTE_LOG(DEBUG, SPP_COMMAND_PROC, "get one object. name=%s\n",
 				rule->name);
@@ -497,20 +497,20 @@ decode_json_object(void *output, const json_t *parent_obj,
 
 			json_array_foreach(value_obj, n, obj) {
 				RTE_LOG(DEBUG, SPP_COMMAND_PROC, "Decode array element. "
-						"index=%d\n", i);
+						"index=%d\n", n);
 				
 				if (unlikely(json_typeof(obj) != rule->array.json_type)) {
 					RTE_LOG(ERR, SPP_COMMAND_PROC, "Bad value type. "
-							"name=%s, index=%d\n", rule->name, i);
+							"name=%s, index=%d\n", rule->name, n);
 					return DERR_BAD_TYPE;
 				}
 
 				sub_output = DR_GET_OUTPUT(output, rule) + 
-						(rule->array.element_sz * i);
+						(rule->array.element_sz * n);
 				ret = (*rule->decode_proc)(sub_output, obj, rule);
 				if (unlikely(ret != 0)) {
 					RTE_LOG(ERR, SPP_COMMAND_PROC, "Bad value. "
-							"name=%s, index=%d\n", rule->name, i);
+							"name=%s, index=%d\n", rule->name, n);
 					return ret;
 				}
 			}
-- 
1.9.1

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

* [spp] [PATCH 21/57] spp_vf: fix comparison operator in spp_vf.c
  2017-12-26  1:54 ` Yasufumi Ogawa
                     ` (19 preceding siblings ...)
  2017-12-28  4:55   ` [spp] [PATCH 20/57] spp_vf: fix error in command decode x-fn-spp
@ 2017-12-28  4:55   ` x-fn-spp
  2017-12-28  4:55   ` [spp] [PATCH 22/57] spp_vf: check upper limit to the number of process x-fn-spp
                     ` (35 subsequent siblings)
  56 siblings, 0 replies; 97+ messages in thread
From: x-fn-spp @ 2017-12-28  4:55 UTC (permalink / raw)
  To: spp

From: Hiroyuki Nakamura <nakamura.hioryuki@po.ntt-tx.co.jp>

Signed-off-by: Kentaro Watanabe <watanabe.kentaro.z01@as.ntt-tx.co.jp>
Signed-off-by: Yasufum Ogawa <ogawa.yasufumi@lab.ntt.co.jp>
---
 src/vf/spp_vf.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/src/vf/spp_vf.c b/src/vf/spp_vf.c
index 208dd30..7bb1ac0 100644
--- a/src/vf/spp_vf.c
+++ b/src/vf/spp_vf.c
@@ -1103,7 +1103,7 @@ spp_update_classifier_table(
 				return SPP_RET_NG;
 			}
 
-			if (unlikely(patch_info->use_flg != 0)) {
+			if (unlikely(patch_info->use_flg == 0)) {
 				RTE_LOG(ERR, APP, "Port not added. ( port = %d:%d )\n", port->if_type, port->if_no);
 				return SPP_RET_NOT_ADD_PORT;
 			}
-- 
1.9.1

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

* [spp] [PATCH 22/57] spp_vf: check upper limit to the number of process
  2017-12-26  1:54 ` Yasufumi Ogawa
                     ` (20 preceding siblings ...)
  2017-12-28  4:55   ` [spp] [PATCH 21/57] spp_vf: fix comparison operator in spp_vf.c x-fn-spp
@ 2017-12-28  4:55   ` x-fn-spp
  2017-12-28  4:55   ` [spp] [PATCH 23/57] spp_vf: display usage message x-fn-spp
                     ` (34 subsequent siblings)
  56 siblings, 0 replies; 97+ messages in thread
From: x-fn-spp @ 2017-12-28  4:55 UTC (permalink / raw)
  To: spp

From: Hiroyuki Nakamura <nakamura.hioryuki@po.ntt-tx.co.jp>

Add upper limit check of the number of process.

Signed-off-by: Kentaro Watanabe <watanabe.kentaro.z01@as.ntt-tx.co.jp>
Signed-off-by: Yasufum Ogawa <ogawa.yasufumi@lab.ntt.co.jp>
---
 src/vf/spp_vf.c | 3 +++
 1 file changed, 3 insertions(+)

diff --git a/src/vf/spp_vf.c b/src/vf/spp_vf.c
index e5dc1c9..6c6b832 100644
--- a/src/vf/spp_vf.c
+++ b/src/vf/spp_vf.c
@@ -317,6 +317,9 @@ parse_app_process_id(const char *process_id_str, int *process_id)
 	if (unlikely(process_id_str == endptr) || unlikely(*endptr != '\0'))
 		return -1;
 
+	if (id >= SPP_PROCESS_MAX)
+		return -1;
+
 	*process_id = id;
 	RTE_LOG(DEBUG, APP, "Set process id = %d\n", *process_id);
 	return 0;
-- 
1.9.1

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

* [spp] [PATCH 23/57] spp_vf: display usage message
  2017-12-26  1:54 ` Yasufumi Ogawa
                     ` (21 preceding siblings ...)
  2017-12-28  4:55   ` [spp] [PATCH 22/57] spp_vf: check upper limit to the number of process x-fn-spp
@ 2017-12-28  4:55   ` x-fn-spp
  2017-12-28  4:55   ` [spp] [PATCH 24/57] spp_vf: split command processing source file x-fn-spp
                     ` (33 subsequent siblings)
  56 siblings, 0 replies; 97+ messages in thread
From: x-fn-spp @ 2017-12-28  4:55 UTC (permalink / raw)
  To: spp

From: Hiroyuki Nakamura <nakamura.hioryuki@po.ntt-tx.co.jp>

* When there is no required startup parameter,
  usage message will displayed.

Signed-off-by: Kentaro Watanabe <watanabe.kentaro.z01@as.ntt-tx.co.jp>
Signed-off-by: Yasufum Ogawa <ogawa.yasufumi@lab.ntt.co.jp>
---
 src/vf/spp_vf.c | 9 +++++++++
 1 file changed, 9 insertions(+)

diff --git a/src/vf/spp_vf.c b/src/vf/spp_vf.c
index 6c6b832..1eaaac9 100644
--- a/src/vf/spp_vf.c
+++ b/src/vf/spp_vf.c
@@ -359,6 +359,8 @@ static int
 parse_app_args(int argc, char *argv[])
 {
 	int cnt;
+	int proc_flg = 0;
+	int server_flg = 0;
 	int option_index, opt;
 	const int argcopt = argc;
 	char *argvopt[argcopt];
@@ -392,6 +394,7 @@ parse_app_args(int argc, char *argv[])
 				usage(progname);
 				return -1;
 			}
+			proc_flg = 1;
 			break;
 		case 's':
 			if (parse_app_server(optarg, g_startup_param.server_ip,
@@ -399,6 +402,7 @@ parse_app_args(int argc, char *argv[])
 				usage(progname);
 				return -1;
 			}
+			server_flg = 1;
 			break;
 		default:
 			usage(progname);
@@ -407,6 +411,11 @@ parse_app_args(int argc, char *argv[])
 		}
 	}
 
+	/* Check mandatory parameters */
+	if ((proc_flg == 0) || (server_flg == 0)) {
+		usage(progname);
+		return -1;
+	}
 	RTE_LOG(INFO, APP, "application arguments value. (process id = %d, config = %s, server = %s:%d)\n",
 			g_startup_param.process_id,
 			config_file_path,
-- 
1.9.1

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

* [spp] [PATCH 24/57] spp_vf: split command processing source file
  2017-12-26  1:54 ` Yasufumi Ogawa
                     ` (22 preceding siblings ...)
  2017-12-28  4:55   ` [spp] [PATCH 23/57] spp_vf: display usage message x-fn-spp
@ 2017-12-28  4:55   ` x-fn-spp
  2017-12-28  4:55   ` [spp] [PATCH 25/57] spp_vf: add new log and line break x-fn-spp
                     ` (32 subsequent siblings)
  56 siblings, 0 replies; 97+ messages in thread
From: x-fn-spp @ 2017-12-28  4:55 UTC (permalink / raw)
  To: spp

From: Hiroyuki Nakamura <nakamura.hioryuki@po.ntt-tx.co.jp>

* For better maintainability,
  split 1 source file into 3 files(acceptance, decode, and utility).

Signed-off-by: Daiki Yamashita <yamashita.daiki.z01@as.ntt-tx.co.jp>
Signed-off-by: Yasufum Ogawa <ogawa.yasufumi@lab.ntt.co.jp>
---
 src/vf/Makefile        |   2 +-
 src/vf/command_conn.c  | 136 ++++++++
 src/vf/command_conn.h  |  63 ++++
 src/vf/command_dec.c   | 433 +++++++++++++++++++++++++
 src/vf/command_dec.h   | 110 +++++++
 src/vf/command_proc.c  | 866 ++++++++++++++-----------------------------------
 src/vf/string_buffer.c |  90 +++++
 src/vf/string_buffer.h |  16 +
 8 files changed, 1097 insertions(+), 619 deletions(-)
 create mode 100644 src/vf/command_conn.c
 create mode 100644 src/vf/command_conn.h
 create mode 100644 src/vf/command_dec.c
 create mode 100644 src/vf/command_dec.h
 create mode 100644 src/vf/string_buffer.c
 create mode 100644 src/vf/string_buffer.h

diff --git a/src/vf/Makefile b/src/vf/Makefile
index 19617f6..1284733 100644
--- a/src/vf/Makefile
+++ b/src/vf/Makefile
@@ -40,7 +40,7 @@ include $(RTE_SDK)/mk/rte.vars.mk
 APP = spp_vf
 
 # all source are stored in SRCS-y
-SRCS-y := spp_vf.c spp_config.c classifier_mac.c spp_forward.c command_proc.c ringlatencystats.c ../shared/common.c
+SRCS-y := spp_vf.c spp_config.c classifier_mac.c spp_forward.c string_buffer.c command_conn.c command_dec.c command_proc.c ringlatencystats.c ../shared/common.c
 
 CFLAGS += $(WERROR_FLAGS) -O3
 CFLAGS += -I$(SRCDIR)/../shared
diff --git a/src/vf/command_conn.c b/src/vf/command_conn.c
new file mode 100644
index 0000000..edd4d4c
--- /dev/null
+++ b/src/vf/command_conn.c
@@ -0,0 +1,136 @@
+#include <unistd.h>
+#include <string.h>
+#include <fcntl.h>
+#include <errno.h>
+#include <arpa/inet.h>
+
+#include <rte_log.h>
+#include <rte_branch_prediction.h>
+
+#include "string_buffer.h"
+#include "command_conn.h"
+
+#define RTE_LOGTYPE_SPP_COMMAND_PROC RTE_LOGTYPE_USER1
+
+/* one receive message size */
+#define MESSAGE_BUFFER_BLOCK_SIZE 2048
+
+/* controller's ip address */
+static char g_controller_ip[128] = "";
+
+/* controller's port number */
+static int g_controller_port = 0;
+
+/* initialize command connection */
+int
+spp_command_conn_init(const char *controller_ip, int controller_port)
+{
+	strcpy(g_controller_ip, controller_ip);
+	g_controller_port = controller_port;
+
+	return 0;
+}
+
+/* connect to controller */
+int
+spp_connect_to_controller(int *sock)
+{
+	static struct sockaddr_in controller_addr;
+	int ret = -1;
+	int sock_flg = 0;
+
+	if (likely(*sock >=0))
+		return 0;
+
+	/* create socket */
+	if (*sock < 0) {
+		RTE_LOG(INFO, SPP_COMMAND_PROC, "Creating socket...\n");
+		*sock = socket(AF_INET, SOCK_STREAM, 0);
+		if (*sock < 0) {
+			RTE_LOG(ERR, SPP_COMMAND_PROC, 
+					"Cannot create tcp socket. errno=%d\n", errno);
+			return -1;
+		}
+
+		memset(&controller_addr, 0, sizeof(controller_addr));
+		controller_addr.sin_family = AF_INET;
+		controller_addr.sin_addr.s_addr = inet_addr(g_controller_ip);
+		controller_addr.sin_port = htons(g_controller_port);
+	}
+
+	/* connect to */
+	RTE_LOG(INFO, SPP_COMMAND_PROC, "Trying to connect ... socket=%d\n", *sock);
+	ret = connect(*sock, (struct sockaddr *)&controller_addr,
+			sizeof(controller_addr));
+	if (ret < 0) {
+		RTE_LOG(ERR, SPP_COMMAND_PROC,
+				"Cannot connect to controller. errno=%d\n", errno);
+		return -1;
+	}
+
+	RTE_LOG(INFO, SPP_COMMAND_PROC, "Connected\n");
+
+	/* set non-blocking */
+	sock_flg = fcntl(*sock, F_GETFL, 0);
+	fcntl(*sock, F_SETFL, sock_flg | O_NONBLOCK);
+
+	return 0;
+}
+
+/* receive message */
+int
+spp_receive_message(int *sock, char **strbuf)
+{
+	int ret = -1;
+	int n_rx = 0;
+	char *new_strbuf = NULL;
+
+	char rx_buf[MESSAGE_BUFFER_BLOCK_SIZE];
+	size_t rx_buf_sz = MESSAGE_BUFFER_BLOCK_SIZE;
+
+	ret = recv(*sock, rx_buf, rx_buf_sz, 0);
+	RTE_LOG(DEBUG, SPP_COMMAND_PROC, "Receive message. count=%d\n", ret);
+	if (ret <= 0) {
+		if (ret == 0) {
+			RTE_LOG(INFO, SPP_COMMAND_PROC,
+					"Controller has performed an shutdown.");
+		} else if (errno == EAGAIN || errno == EWOULDBLOCK) {
+			/* no receive message */
+			return 0;
+		} else {
+			RTE_LOG(ERR, SPP_COMMAND_PROC,
+					"Receive failure. errno=%d\n", errno);
+		}
+
+		RTE_LOG(INFO, SPP_COMMAND_PROC, "Assume Server closed connection\n");
+		close(*sock);
+		*sock = -1;
+		return -1;
+	}
+
+	n_rx = ret;
+
+	new_strbuf = spp_strbuf_append(*strbuf, rx_buf, n_rx);
+	if (unlikely(new_strbuf == NULL)) {
+		return -1;
+	}
+
+	*strbuf = new_strbuf;
+
+	return n_rx;
+}
+
+/* send message */
+int
+spp_send_message(int *sock, const char* message, size_t message_len)
+{
+	int ret = -1;
+
+	ret = send(*sock, message, message_len, 0);
+	if (unlikely(ret == -1)) {
+		RTE_LOG(ERR, SPP_COMMAND_PROC, "Send failure. ret=%d\n", ret);
+		return -1;
+	}
+
+	return 0;
+}
diff --git a/src/vf/command_conn.h b/src/vf/command_conn.h
new file mode 100644
index 0000000..0136d75
--- /dev/null
+++ b/src/vf/command_conn.h
@@ -0,0 +1,63 @@
+#ifndef _COMMAND_CONN_H_
+#define _COMMAND_CONN_H_
+
+/**
+ * intialize command connection.
+ *
+ * @param controller_ip
+ *  controller listen ip address.
+ *
+ * @param controller_port
+ *  controller listen port number.
+ *
+ * @ret_val 0 succeeded.
+ * @ret_val -1 failed.
+ */
+int spp_command_conn_init(const char *controller_ip, int controller_port);
+
+/**
+ * connect to controller.
+ *
+ * @note bocking.
+ *
+ * @param sock
+ *  socket that connect to controller.
+ *
+ * @ret_val 0 succeeded.
+ * @ret_val -1 failed.
+ */
+int spp_connect_to_controller(int *sock);
+
+/**
+ * receive message.
+ *
+ * @note non-blocking.
+ *
+ * @param sock
+ *  socket that read data.
+ *
+ * @ret_val 0 succeeded.
+ * @ret_val -1 failed.
+ */
+int spp_receive_message(int *sock, char **msgbuf);
+
+/**
+ * send message.
+ *
+ * @note non-blocking.
+ *
+ * @param sock
+ *  socket that write data.
+ *
+ * @param message
+ *  send data.
+ *
+ * @param message_len
+ *  send data length.
+ *
+ * @ret_val 0 succeeded.
+ * @ret_val -1 failed.
+ */
+int spp_send_message(int *sock, const char* message, size_t message_len);
+
+#endif /* _COMMAND_CONN_H_ */
diff --git a/src/vf/command_dec.c b/src/vf/command_dec.c
new file mode 100644
index 0000000..85f935b
--- /dev/null
+++ b/src/vf/command_dec.c
@@ -0,0 +1,433 @@
+#include <unistd.h>
+#include <string.h>
+
+#include <rte_log.h>
+#include <rte_branch_prediction.h>
+
+#include <jansson.h>
+
+#include "spp_vf.h"
+#include "spp_config.h"
+#include "command_dec.h"
+
+#define RTE_LOGTYPE_SPP_COMMAND_PROC RTE_LOGTYPE_USER1
+
+/* command type string list
+	do it same as the order of enum command_type */
+static const char *COMMAND_TYPE_STRINGS[] = {
+#if 0 /* not supported yet */
+	"add",
+	"component",
+#endif
+	"classifier_table",
+	"flush",
+#if 0 /* not supported yet */
+	"forward",
+	"stop",
+#endif
+	"process",
+
+	/* termination */ "",
+};
+
+/* classifier type string list
+	do it same as the order of enum spp_classifier_type (spp_vf.h) */
+static const char *CLASSIFILER_TYPE_STRINGS[] = {
+	"none",
+	"mac",
+
+	/* termination */ "",
+};
+
+/* forward declaration */
+struct json_value_decode_rule;
+
+/* definition of decode procedure function */
+typedef int (*json_value_decode_proc)(
+		void *, 
+		const json_t *, 
+		const struct json_value_decode_rule *, 
+		struct spp_command_decode_error *);
+
+/* rule definition that decode json object to c-struct */
+struct json_value_decode_rule {
+	char name[SPP_CMD_NAME_BUFSZ];
+	json_type json_type;
+	size_t offset;
+	json_value_decode_proc decode_proc;
+
+	struct {
+		json_type json_type;
+		size_t element_sz;
+		size_t offset_num;
+		size_t offset_num_valid;
+	} array;
+};
+
+/* get output address for decoded json value */
+#define DR_GET_OUTPUT(output_base, rule__) ((char *)output_base + rule__->offset)
+
+/* set decode error */
+inline int
+set_decode_error(struct spp_command_decode_error *error,
+		int error_code,
+		const struct json_value_decode_rule *error_rule)
+{
+	error->code = error_code;
+
+	if (likely(error_rule != NULL))
+		strcpy(error->value_name, error_rule->name);
+
+	return error->code;
+}
+
+/* set decode error */
+inline int
+set_string_value_decode_error(struct spp_command_decode_error *error,
+		const char* value,
+		const struct json_value_decode_rule *error_rule)
+{
+	strcpy(error->value, value);
+	return set_decode_error(error, SPP_CMD_DERR_BAD_VALUE, error_rule);
+}
+
+/* helper */
+#define END_OF_DECODE_RULE {.name = ""},
+#define IS_END_OF_DECODE_RULE(rule) ((rule)->name[0] == '\0')
+
+/* definition helper that enum value decode procedure */
+#define DECODE_ENUM_VALUE(proc_name, enum_type, string_table)			\
+static int									\
+decode_##proc_name##_value(void *output, const json_t *value_obj,		\
+		const struct json_value_decode_rule *rule,			\
+		struct spp_command_decode_error *error)				\
+{										\
+	int i;									\
+	enum_type type;								\
+	const char *str_val = json_string_value(value_obj);			\
+										\
+	for (i = 0; string_table[i][0] != '\0'; ++i) {				\
+		if (unlikely(strcmp(str_val, string_table[i]) == 0)) {		\
+			type = i;						\
+			memcpy(output, &type, sizeof(enum_type));		\
+			return 0;						\
+		}								\
+	}									\
+										\
+	return set_string_value_decode_error(error, str_val, rule);		\
+}										\
+
+/* enum value decode procedure for "command_type" */
+DECODE_ENUM_VALUE(command_type, enum spp_command_type, COMMAND_TYPE_STRINGS)
+
+/* enum value decode procedure for "classifier_type" */
+DECODE_ENUM_VALUE(classifier_type, enum spp_classifier_type, CLASSIFILER_TYPE_STRINGS)
+
+#if 0 /* not supported yet */
+/* decode procedure for integer */
+static int
+decode_int_value(void *output, const json_t *value_obj,
+		__rte_unused const struct json_value_decode_rule *rule,
+		__rte_unused struct spp_command_decode_error *error)
+{
+	int val = json_integer_value(value_obj);
+	memcpy(output, &val, sizeof(int));
+
+	return 0;
+}
+
+/* decode procedure for string */
+static int
+decode_string_value(void *output, const json_t *value_obj,
+		__rte_unused const struct json_value_decode_rule *rule,
+		__rte_unused struct spp_command_decode_error *error)
+{
+	const char* str_val = json_string_value(value_obj);
+	strcpy(output, str_val);
+
+	return 0;
+}
+#endif
+
+/* decode procedure for mac address string */
+static int
+decode_mac_addr_str_value(void *output, const json_t *value_obj,
+		const struct json_value_decode_rule *rule,
+		struct spp_command_decode_error *error)
+{
+	int ret = -1;
+	const char* str_val = json_string_value(value_obj);
+
+	ret = spp_config_change_mac_str_to_int64(str_val);
+	if (unlikely(ret == -1)) {
+		RTE_LOG(ERR, SPP_COMMAND_PROC, "Bad mac address string. val=%s\n",
+				str_val);
+		return set_string_value_decode_error(error, str_val, rule);
+	}
+
+	strcpy(output, str_val);
+
+	return 0;
+}
+
+/* decode procedure for spp_config_port_info */
+static int
+decode_port_value(void *output, const json_t *value_obj,
+		const struct json_value_decode_rule *rule,
+		struct spp_command_decode_error *error)
+{
+	int ret = -1;
+	const char* str_val = json_string_value(value_obj);
+	struct spp_config_port_info *port = (struct spp_config_port_info *)output;
+
+	if (strcmp(str_val, SPP_CMD_UNUSE) == 0) {
+		port->if_type = UNDEF;
+		port->if_no = 0;
+		return 0;
+	}
+
+	ret = spp_config_get_if_info(str_val, &port->if_type, &port->if_no);
+	if (unlikely(ret != 0)) {
+		RTE_LOG(ERR, SPP_COMMAND_PROC, "Bad port. val=%s\n", str_val);
+		return set_string_value_decode_error(error, str_val, rule);
+	}
+
+	return 0;
+}
+
+/* decode json object */
+static int
+decode_json_object(void *output, const json_t *parent_obj,
+		const struct json_value_decode_rule *rules,
+		struct spp_command_decode_error *error)
+{
+	int ret = -1;
+	int i, n;
+	json_t *obj;
+	json_t *value_obj;
+	const struct json_value_decode_rule *rule;
+
+	void *sub_output;
+
+	for (i = 0; unlikely(! IS_END_OF_DECODE_RULE(&rules[i])); ++ i) {
+		rule = rules + i;
+
+		RTE_LOG(DEBUG, SPP_COMMAND_PROC, "Get one object. name=%s\n",
+				rule->name);
+
+		value_obj = json_object_get(parent_obj, rule->name);
+		if (unlikely(value_obj == NULL)) {
+			RTE_LOG(ERR, SPP_COMMAND_PROC, "No parameter. "
+					"name=%s\n", rule->name);
+			return set_decode_error(error, SPP_CMD_DERR_NO_PARAM, rule);
+		} else if (unlikely(json_typeof(value_obj) != rule->json_type)) {
+			RTE_LOG(ERR, SPP_COMMAND_PROC, "Bad value type. "
+					"name=%s\n", rule->name);
+			return set_decode_error(error, SPP_CMD_DERR_BAD_TYPE, rule);
+		}
+
+		switch (rule->json_type) {
+		case JSON_ARRAY:
+			RTE_LOG(DEBUG, SPP_COMMAND_PROC, "Decode array. num=%lu\n",
+					json_array_size(value_obj));
+
+			*(int *)((char *)output + rule->array.offset_num) = 
+					(int)json_array_size(value_obj);
+
+			json_array_foreach(value_obj, n, obj) {
+				RTE_LOG(DEBUG, SPP_COMMAND_PROC, "Decode array element. "
+						"index=%d\n", n);
+				
+				if (unlikely(json_typeof(obj) != rule->array.json_type)) {
+					RTE_LOG(ERR, SPP_COMMAND_PROC, "Bad value type. "
+							"name=%s, index=%d\n", rule->name, n);
+					return set_decode_error(error, SPP_CMD_DERR_BAD_TYPE, rule);
+				}
+
+				sub_output = DR_GET_OUTPUT(output, rule) + 
+						(rule->array.element_sz * n);
+				ret = (*rule->decode_proc)(sub_output, obj, rule, error);
+				if (unlikely(ret != 0)) {
+					RTE_LOG(ERR, SPP_COMMAND_PROC, "Bad value. "
+							"name=%s, index=%d\n", rule->name, n);
+					/* decode error is set in decode function */
+					return ret;
+				}
+
+				*(int *)((char *)output +
+						rule->array.offset_num_valid) = n + 1;
+			}
+			break;
+		default:
+			sub_output = DR_GET_OUTPUT(output, rule);
+			ret = (*rule->decode_proc)(sub_output, value_obj, rule, error);
+			if (unlikely(ret != 0)) {
+				RTE_LOG(ERR, SPP_COMMAND_PROC, "Bad value. "
+						"name=%s\n", rule->name);
+				/* decode error is set in decode function */
+				return ret;
+			}
+			break;
+		}
+	}
+
+	return 0;
+}
+
+/* decode rule for command-base */
+const struct json_value_decode_rule DECODERULE_COMMAND_BASE[] = {
+	{
+		.name = "command",
+		.json_type = JSON_STRING,
+		.offset = offsetof(struct spp_command, type),
+		.decode_proc = decode_command_type_value,
+	},
+	END_OF_DECODE_RULE
+};
+
+#if 0 /* not supported yet */
+/* decode rule for add-command-spec */
+const struct json_value_decode_rule DECODERULE_ADD_COMMAND[] = {
+	{
+		.name = "ports",
+		.json_type = JSON_ARRAY,
+		.offset = offsetof(struct spp_command_add, ports),
+		.decode_proc = decode_port_value,
+
+		.array.element_sz = sizeof(struct spp_config_port_info),
+		.array.json_type = JSON_STRING,
+		.array.offset_num = offsetof(struct spp_command_add, num_port),
+	},
+	END_OF_DECODE_RULE
+};
+#endif
+
+/* decode rule for classifier-table-command-spec */
+const struct json_value_decode_rule DECODERULE_CLASSIFIER_TABLE_COMMAND[] = {
+	{
+		.name = "type",
+		.json_type = JSON_STRING,
+		.offset = offsetof(struct spp_command_classifier_table, type),
+		.decode_proc = decode_classifier_type_value,
+	},{
+		.name = "value",
+		.json_type = JSON_STRING,
+		.offset = offsetof(struct spp_command_classifier_table, value),
+		.decode_proc = decode_mac_addr_str_value,
+	},{
+		.name = "port",
+		.json_type = JSON_STRING,
+		.offset = offsetof(struct spp_command_classifier_table, port),
+		.decode_proc = decode_port_value,
+	},
+	END_OF_DECODE_RULE
+};
+
+/* decode procedure for command */
+static int
+decode_command_object(void* output, const json_t *parent_obj,
+		__rte_unused const struct json_value_decode_rule *rule,
+		struct spp_command_decode_error *error)
+{
+	int ret = -1;
+	struct spp_command *command = (struct spp_command *)output;
+	const struct json_value_decode_rule *spec_rules = NULL;
+
+	/* decode command-base */
+	ret = decode_json_object(command, parent_obj, DECODERULE_COMMAND_BASE, error);
+	if (unlikely(ret != 0)) {
+		RTE_LOG(ERR, SPP_COMMAND_PROC, "Bad command. ret=%d\n", ret);
+		/* decode error is set in decode_json_object function */
+		return ret;
+	}
+
+	/* decode command-specific */
+	switch (command->type) {
+		case SPP_CMDTYPE_CLASSIFIER_TABLE:
+			spec_rules = DECODERULE_CLASSIFIER_TABLE_COMMAND;
+			break;
+
+		case SPP_CMDTYPE_FLUSH:
+			/* nothing specific */
+			break;
+
+		default:
+			/* unknown command */
+			RTE_LOG(ERR, SPP_COMMAND_PROC, "Unknown command. type=%d\n",
+					command->type);
+			return set_decode_error(error, SPP_CMD_DERR_UNKNOWN_COMMAND, rule);
+	}
+
+	if (likely(spec_rules != NULL)) {
+		ret = decode_json_object(&command->spec, parent_obj, spec_rules, error);
+		if (unlikely(ret != 0)) {
+			RTE_LOG(ERR, SPP_COMMAND_PROC, "Bad command. ret=%d\n", ret);
+			/* decode error is set in decode_json_object function */
+			return ret;
+		}
+	}
+
+	return 0;
+}
+
+/* decode rule for command request */
+const struct json_value_decode_rule DECODERULE_REQUEST[] = {
+	{
+		.name = "commands",
+		.json_type = JSON_ARRAY,
+		.offset = offsetof(struct spp_command_request, commands),
+		.decode_proc = decode_command_object,
+
+		.array.element_sz = sizeof(struct spp_command),
+		.array.json_type = JSON_OBJECT,
+		.array.offset_num = offsetof(struct spp_command_request, num_command),
+		.array.offset_num_valid = offsetof(struct spp_command_request, num_valid_command),
+	},
+	END_OF_DECODE_RULE
+};
+
+/* decode request from no-null-terminated string */
+int
+spp_command_decode_request(struct spp_command_request *request, const char *request_str,
+		size_t request_str_len, struct spp_command_decode_error *error)
+{
+	int ret = -1;
+	int i;
+	json_t *top_obj;
+	json_error_t json_error;
+
+	/* parse json string */
+	top_obj = json_loadb(request_str, request_str_len, 0, &json_error);
+	if (unlikely(top_obj == NULL)) {
+		RTE_LOG(ERR, SPP_COMMAND_PROC, "Cannot parse command request. "
+				"error=%s, request_str=%.*s\n", 
+				json_error.text, (int)request_str_len, request_str);
+		return set_decode_error(error, SPP_CMD_DERR_BAD_FORMAT, NULL);
+	}
+
+	/* decode request object */
+	ret = decode_json_object(request, top_obj, DECODERULE_REQUEST, error);
+	if (unlikely(ret != 0)) {
+		RTE_LOG(ERR, SPP_COMMAND_PROC, "Cannot decode command request. "
+				"ret=%d, request_str=%.*s\n", 
+				ret, (int)request_str_len, request_str);
+		/* decode error is set in decode_json_object function */
+	}
+
+	/* free json object */
+	json_decref(top_obj);
+
+	/* check getter command */
+	for (i = 0; i < request->num_valid_command; ++i) {
+		switch (request->commands[i].type) {
+		case SPP_CMDTYPE_PROCESS:
+			request->is_requested_process = 1;
+			break;
+		default:
+			/* nothing to do */
+			break;
+		}
+	}
+
+	return ret;
+}
diff --git a/src/vf/command_dec.h b/src/vf/command_dec.h
new file mode 100644
index 0000000..25e1ea0
--- /dev/null
+++ b/src/vf/command_dec.h
@@ -0,0 +1,110 @@
+#ifndef _COMMAND_DEC_H_
+#define _COMMAND_DEC_H_
+
+/* max number of command per request */
+#define SPP_CMD_MAX_COMMANDS 32
+
+/* command name string buffer size (include null char) */
+#define SPP_CMD_NAME_BUFSZ  32
+
+/* command value string buffer size (include null char) */
+#define SPP_CMD_VALUE_BUFSZ 128
+
+/* string that specify unused */
+#define SPP_CMD_UNUSE "unuse"
+
+/* component type */
+#define spp_component_type spp_core_type
+
+/* decode error code */
+enum spp_command_decode_error_code {
+	/* not use 0, in general 0 is ok */
+	SPP_CMD_DERR_BAD_FORMAT = 1,
+	SPP_CMD_DERR_UNKNOWN_COMMAND,
+	SPP_CMD_DERR_NO_PARAM,
+	SPP_CMD_DERR_BAD_TYPE,
+	SPP_CMD_DERR_BAD_VALUE,
+};
+
+/* command type
+	do it same as the order of COMMAND_TYPE_STRINGS */
+enum spp_command_type {
+#if 0 /* not supported yet yet */
+	SPP_CMDTYPE_ADD,
+	SPP_CMDTYPE_COMPONENT,
+#endif
+	SPP_CMDTYPE_CLASSIFIER_TABLE,
+	SPP_CMDTYPE_FLUSH,
+#if 0 /* not supported yet */
+	SPP_CMDTYPE_FORWARD,
+	SPP_CMDTYPE_STOP,
+#endif
+	SPP_CMDTYPE_PROCESS,
+};
+
+#if 0 /* not supported yet */
+/* "add" command parameters */
+struct spp_command_add {
+	int num_port;
+	struct spp_config_port_info ports[RTE_MAX_ETHPORTS];
+};
+
+/* "component" command specific parameters */
+struct spp_command_component {
+	enum spp_component_type type;
+	unsigned int core_id;
+	int num_rx_port;
+	int num_tx_port;
+	struct spp_config_port_info rx_ports[RTE_MAX_ETHPORTS];
+	struct spp_config_port_info tx_ports[RTE_MAX_ETHPORTS];
+};
+#endif
+
+/* "classifier_table" command specific parameters */
+struct spp_command_classifier_table {
+	enum spp_classifier_type type;
+	char value[SPP_CMD_VALUE_BUFSZ];
+	struct spp_config_port_info port;
+};
+
+/* "flush" command specific parameters */
+struct spp_command_flush {
+	/* nothing specific */
+};
+
+/* command parameters */
+struct spp_command {
+	enum spp_command_type type;
+
+	union {
+#if 0 /* not supported yet */
+		struct spp_command_add add;
+		struct spp_command_component component;
+#endif
+		struct spp_command_classifier_table classifier_table;
+		struct spp_command_flush flush;
+	} spec;
+};
+
+/* request parameters */
+struct spp_command_request {
+	int num_command;
+	int num_valid_command;
+	struct spp_command commands[SPP_CMD_MAX_COMMANDS];
+
+	int is_requested_process;
+};
+
+/* decode error information */
+struct spp_command_decode_error {
+	int code;
+	char value_name[SPP_CMD_NAME_BUFSZ];
+	char value[SPP_CMD_VALUE_BUFSZ];
+};
+
+/* decode request from no-null-terminated string */
+int spp_command_decode_request(struct spp_command_request *request,
+		const char *request_str, size_t request_str_len,
+		struct spp_command_decode_error *error);
+
+#endif /* _COMMAND_DEC_H_ */
diff --git a/src/vf/command_proc.c b/src/vf/command_proc.c
index bec762e..097483c 100644
--- a/src/vf/command_proc.c
+++ b/src/vf/command_proc.c
@@ -1,12 +1,6 @@
 #include <unistd.h>
-#include <sys/types.h>
-#include <stdio.h>
 #include <string.h>
-#include <fcntl.h>
-#include <errno.h>
-#include <arpa/inet.h>
 
-#include <rte_common.h>
 #include <rte_log.h>
 #include <rte_branch_prediction.h>
 
@@ -14,723 +8,362 @@
 
 #include "spp_vf.h"
 #include "spp_config.h"
+#include "string_buffer.h"
+#include "command_conn.h"
+#include "command_dec.h"
 #include "command_proc.h"
 
 #define RTE_LOGTYPE_SPP_COMMAND_PROC RTE_LOGTYPE_USER1
 
+/* request message initial size */
+#define MESSAGE_BUFFER_BLOCK_SIZE 2048
 
-/*******************************************************************************
- *
- * operate connection with controller
- *
- ******************************************************************************/
-
-/* receive message buffer size */
-#define MESSAGE_BUFFER_BLOCK_SIZE 512
-
-/* controller's ip address */
-static char g_controller_ip[128] = "";
+/* command execution result code */
+enum command_result_code {
+	CRES_SUCCESS = 0,
+	CRES_FAILURE,
+	CRES_INVALID,
+};
 
-/* controller's port number */
-static int g_controller_port = 0;
+/* command execution result information */
+struct command_result {
+	int code;
+};
 
-/* allocate message buffer */
-inline char*
-msgbuf_allocate(size_t capacity)
+/* execute one command */
+static int
+execute_command(const struct spp_command *command)
 {
-	char* buf = (char *)malloc(capacity + sizeof(size_t));
-	if (unlikely(buf == NULL))
-		return NULL;
+	int ret = 0;
 
-	memset(buf, 0x00, capacity + sizeof(size_t));
-	*((size_t *)buf) = capacity;
+	switch (command->type) {
+	case SPP_CMDTYPE_CLASSIFIER_TABLE:
+		RTE_LOG(DEBUG, SPP_COMMAND_PROC, "Execute classifier_table command.");
+		ret = spp_update_classifier_table(
+				command->spec.classifier_table.type,
+				command->spec.classifier_table.value,
+				&command->spec.classifier_table.port);
+		break;
 
-	return buf + sizeof(size_t);
-}
+	case SPP_CMDTYPE_FLUSH:
+		RTE_LOG(DEBUG, SPP_COMMAND_PROC, "Execute flush command.");
+		ret = spp_flush();
+		break;
 
-/* free message buffer */
-inline void
-msgbuf_free(char* msgbuf)
-{
-	if (likely(msgbuf != NULL))
-		free(msgbuf - sizeof(size_t));
-}
+	case SPP_CMDTYPE_PROCESS:
+		RTE_LOG(DEBUG, SPP_COMMAND_PROC, "Process command is requested.");
+		/* nothing to do here */
+		break;
 
-/* get message buffer capacity */
-inline size_t
-msgbuf_get_capacity(const char *msgbuf)
-{
-	return *((const size_t *)(msgbuf - sizeof(size_t)));
+	default:
+		RTE_LOG(ERR, SPP_COMMAND_PROC, "Unknown command. type=%d\n", command->type);
+		/* nothing to do here */
+		break;
+	}
+
+	return ret;
 }
 
-/* re-allocate message buffer */
-inline char*
-msgbuf_reallocate(char *msgbuf, size_t required_len)
+/* make decode error message for response */
+static const char *
+make_decode_error_message(const struct spp_command_decode_error *decode_error, char *message)
 {
-	size_t new_cap = msgbuf_get_capacity(msgbuf) * 2;
-	char *new_msgbuf = NULL;
+	switch (decode_error->code) {
+	case SPP_CMD_DERR_BAD_FORMAT:
+		sprintf(message, "bad message format");
+		break;
 
-	while (unlikely(new_cap <= required_len))
-		new_cap *= 2;
+	case SPP_CMD_DERR_UNKNOWN_COMMAND:
+		sprintf(message, "unknown command(%s)", decode_error->value);
+		break;
 
-	new_msgbuf = msgbuf_allocate(new_cap);
-	if (unlikely(new_msgbuf == NULL))
-		return NULL;
+	case SPP_CMD_DERR_NO_PARAM:
+		sprintf(message, "not enough parameter(%s)", decode_error->value_name);
+		break;
 
-	strcpy(new_msgbuf, msgbuf);
-	msgbuf_free(msgbuf);
+	case SPP_CMD_DERR_BAD_TYPE:
+		sprintf(message, "bad value type(%s)", decode_error->value_name);
+		break;
 
-	return new_msgbuf;
-}
+	case SPP_CMD_DERR_BAD_VALUE:
+		sprintf(message, "bad value(%s)", decode_error->value_name);
+		break;
 
-/* append message to buffer */
-inline char*
-msgbuf_append(char *msgbuf, const char *append, size_t append_len)
-{
-	size_t cap = msgbuf_get_capacity(msgbuf);
-	size_t len = strlen(msgbuf);
-	char *new_msgbuf = msgbuf;
-
-	if (unlikely(len + append_len >= cap)) {
-		new_msgbuf = msgbuf_reallocate(msgbuf, len + append_len);
-		if (unlikely(new_msgbuf == NULL))
-			return NULL;
+	default:
+		sprintf(message, "error occur");
+		break;
 	}
 
-	memcpy(new_msgbuf + len, append, append_len);
-	*(new_msgbuf + len + append_len) = '\0';
-
-	return new_msgbuf;
+	return message;
 }
 
-/* remove message from front */
-inline char*
-msgbuf_remove_front(char *msgbuf, size_t remove_len)
+/* create error result object form decode error information */
+inline json_t *
+create_result_object(const char* res_str)
 {
-	size_t len = strlen(msgbuf);
-	size_t new_len = len - remove_len;
-
-	if (likely(new_len == 0)) {
-		*msgbuf = '\0';
-		return msgbuf;
-	}
+	return json_pack("{ss}", "result", res_str);
+}
 
-	return memmove(msgbuf, msgbuf + remove_len, new_len + 1);
+/* create error result object form decode error information */
+inline json_t *
+create_error_result_object(const char* err_msg)
+{
+	return json_pack("{sss{ss}}", "result", "error", "error_details", 
+			"message", err_msg);
 }
 
-/* connect to controller */
+/*  */
 static int
-connect_to_controller(int *sock)
+append_response_decode_results_object(json_t *parent_obj,
+		const struct spp_command_request *request,
+		const struct spp_command_decode_error *decode_error)
 {
-	static struct sockaddr_in controller_addr;
 	int ret = -1;
-	int sock_flg = 0;
-
-	if (likely(*sock >=0))
-		return 0;
-
-	/* create socket */
-	if (*sock < 0) {
-		RTE_LOG(INFO, SPP_COMMAND_PROC, "Creating socket...\n");
-		*sock = socket(AF_INET, SOCK_STREAM, 0);
-		if (*sock < 0) {
-			RTE_LOG(ERR, SPP_COMMAND_PROC, 
-					"Cannot create tcp socket. errno=%d\n", errno);
+	int i;
+	json_t *results_obj;
+	char err_msg[128];
+
+	results_obj = json_array();
+	if (unlikely(results_obj == NULL))
+		return -1;
+
+	if (unlikely(decode_error->code == SPP_CMD_DERR_BAD_FORMAT)) {
+		/* create & append bad message format result */
+		ret = json_array_append_new(results_obj,
+				create_error_result_object(
+				make_decode_error_message(decode_error, err_msg)));
+		if (unlikely(ret != 0)) {
+			json_decref(results_obj);
 			return -1;
 		}
+	} else {
+		/* create & append results */
+		for (i = 0; i < request->num_command; ++i) {
+			ret = json_array_append_new(results_obj, create_result_object("invalid"));
+			if (unlikely(ret != 0)) {
+				json_decref(results_obj);
+				return -1;
+			}
+		}
 
-		memset(&controller_addr, 0, sizeof(controller_addr));
-		controller_addr.sin_family = AF_INET;
-		controller_addr.sin_addr.s_addr = inet_addr(g_controller_ip);
-		controller_addr.sin_port = htons(g_controller_port);
+		/* create & rewrite error result */
+		if (unlikely(request->num_command != request->num_valid_command)) {
+			ret = json_array_set_new(results_obj,
+					request->num_valid_command,
+					create_error_result_object(
+					make_decode_error_message(decode_error, err_msg)));
+			if (unlikely(ret != 0)) {
+				json_decref(results_obj);
+				return -1;
+			}
+		}
 	}
 
-	/* connect to */
-	RTE_LOG(INFO, SPP_COMMAND_PROC, "Trying to connect ... socket=%d\n", *sock);
-	ret = connect(*sock, (struct sockaddr *)&controller_addr,
-			sizeof(controller_addr));
-	if (ret < 0) {
-		RTE_LOG(ERR, SPP_COMMAND_PROC,
-				"Cannot connect to controller. errno=%d\n", errno);
+	/* set results object in parent object */
+	ret = json_object_set_new(parent_obj, "results", results_obj);
+	if (unlikely(ret != 0))
 		return -1;
-	}
-
-	RTE_LOG(INFO, SPP_COMMAND_PROC, "Connected\n");
-
-	/* set non-blocking */
-	sock_flg = fcntl(*sock, F_GETFL, 0);
-	fcntl(*sock, F_SETFL, sock_flg | O_NONBLOCK);
 
 	return 0;
 }
 
-/* receive message */
+/*  */
 static int
-receive_message(int *sock, char **msgbuf)
+append_response_command_results_object(json_t *parent_obj,
+		const struct spp_command_request *request,
+		const struct command_result *results)
 {
 	int ret = -1;
-	int n_rx = 0;
-	char *new_msgbuf = NULL;
-
-	char rx_buf[MESSAGE_BUFFER_BLOCK_SIZE];
-	size_t rx_buf_sz = MESSAGE_BUFFER_BLOCK_SIZE;
-
-	ret = recv(*sock, rx_buf, rx_buf_sz, 0);
-	RTE_LOG(DEBUG, SPP_COMMAND_PROC, "Receive message. count=%d\n", ret);
-	if (ret <= 0) {
-		if (ret == 0) {
-			RTE_LOG(INFO, SPP_COMMAND_PROC,
-					"Controller has performed an shutdown.");
-		} else if (errno == EAGAIN || errno == EWOULDBLOCK) {
-			/* no receive message */
-			return 0;
-		} else {
-			RTE_LOG(ERR, SPP_COMMAND_PROC,
-					"Receive failure. errno=%d\n", errno);
-		}
+	int i;
+	json_t *results_obj, *res_obj;
 
-		RTE_LOG(INFO, SPP_COMMAND_PROC, "Assume Server closed connection\n");
-		close(*sock);
-		*sock = -1;
+	results_obj = json_array();
+	if (unlikely(results_obj == NULL))
 		return -1;
-	}
 
-	n_rx = ret;
+	/* create & append results */
+	for (i = 0; i < request->num_command; ++i) {
+		switch (results[i].code) {
+		case CRES_SUCCESS:
+			res_obj = create_result_object("success");
+			break;
+		case CRES_FAILURE:
+			res_obj = create_error_result_object("error occur");
+			break;
+		case CRES_INVALID: /* FALLTHROUGH */
+		default:
+			res_obj = create_result_object("invalid");
+			break;
+		}
 
-	new_msgbuf = msgbuf_append(*msgbuf, rx_buf, n_rx);
-	if (unlikely(new_msgbuf == NULL)) {
-		return -1;
+		ret = json_array_append_new(results_obj, res_obj);
+		if (unlikely(ret != 0)) {
+			json_decref(results_obj);
+			return -1;
+		}
 	}
 
-	*msgbuf = new_msgbuf;
-
-	return n_rx;
-}
-
-/* send message */
-static int
-send_message(int *sock, const char* message, size_t message_len)
-{
-	int ret = -1;
-
-	ret = send(*sock, message, message_len, 0);
-	if (unlikely(ret == -1)) {
-		RTE_LOG(ERR, SPP_COMMAND_PROC, "Send failure. ret=%d\n", ret);
+	/* set results object in parent object */
+	ret = json_object_set_new(parent_obj, "results", results_obj);
+	if (unlikely(ret != 0))
 		return -1;
-	}
 
 	return 0;
 }
 
-
-/*******************************************************************************
- *
- * process command request(json string)
- *
- ******************************************************************************/
-
-#define CMD_MAX_COMMANDS 32
-
-#define CMD_NAME_BUFSZ 32
-
-#define CMD_CLASSIFIER_TABLE_VALUE_BUFSZ 62
-
-#define CMD_UNUSE "unuse"
-
-#define component_type spp_core_type
-
-/* decode error code */
-enum decode_error_code {
-	DERR_BAD_FORMAT = 1,
-	DERR_UNKNOWN_COMMAND,
-	DERR_NO_PARAM,
-	DERR_BAD_TYPE,
-	DERR_BAD_VALUE,
-};
-
-/* command type
-	do it same as the order of COMMAND_TYPE_STRINGS */
-enum command_type {
-	CMDTYPE_ADD,
-	CMDTYPE_COMPONENT,
-	CMDTYPE_CLASSIFIER_TABLE,
-	CMDTYPE_FLUSH,
-	CMDTYPE_FORWARD,
-	CMDTYPE_STOP,
-
-	CMDTYPE_PROCESS,
-};
-
-/* command type string list
-	do it same as the order of enum command_type */
-static const char *COMMAND_TYPE_STRINGS[] = {
-	"add",
-	"component",
-	"classifier_table",
-	"flush",
-	"forward",
-	"stop",
-
-	/* termination */ "",
-};
-
-/* classifier type string list
-	do it same as the order of enum spp_classifier_type (spp_vf.h) */
-static const char *CLASSIFILER_TYPE_STRINGS[] = {
-	"none",
-	"mac",
-
-	/* termination */ "",
-};
-
-#if 0 /* not supported */
-/* "add" command parameters */
-struct add_command {
-	int num_port;
-	struct spp_config_port_info ports[RTE_MAX_ETHPORTS];
-};
-
-/* "component" command specific parameters */
-struct component_command {
-	enum component_type type;
-	unsigned int core_id;
-	int num_rx_port;
-	int num_tx_port;
-	struct spp_config_port_info rx_ports[RTE_MAX_ETHPORTS];
-	struct spp_config_port_info tx_ports[RTE_MAX_ETHPORTS];
-};
-#endif
-
-/* "classifier_table" command specific parameters */
-struct classifier_table_command {
-	enum spp_classifier_type type;
-	char value[CMD_CLASSIFIER_TABLE_VALUE_BUFSZ];
-	struct spp_config_port_info port;
-};
-
-/* "flush" command specific parameters */
-struct flush_command {
-	/* nothing specific */
-};
-
-/* command parameters */
-struct command {
-	enum command_type type;
-
-	union {
-#if 0 /* not supported */
-		struct add_command add;
-		struct component_command component;
-#endif
-		struct classifier_table_command classifier_table;
-		struct flush_command flush;
-	} spec;
-};
-
-/* request parameters */
-struct request {
-	int num_command;
-	int num_valid_command;
-	struct command commands[CMD_MAX_COMMANDS];
-};
-
-/* forward declaration */
-struct json_value_decode_rule;
-
-/* definition of decode procedure function */
-typedef int (*json_value_decode_proc)(void *, const json_t *, const struct json_value_decode_rule *);
-
-/* rule definition that decode json object to c-struct */
-struct json_value_decode_rule {
-	char name[CMD_NAME_BUFSZ];
-	json_type json_type;
-	size_t offset;
-	json_value_decode_proc decode_proc;
-
-	struct {
-		json_type json_type;
-		size_t element_sz;
-		size_t offset_num;
-		size_t offset_num_valid;
-	} array;
-};
-
-/* get output address for decoded json value */
-#define DR_GET_OUTPUT(output_base, rule__) ((char *)output_base + rule__->offset)
-
-/* helper */
-#define END_OF_DECODE_RULE {.name = ""},
-#define IS_END_OF_DECODE_RULE(rule) ((rule)->name[0] == '\0')
-
-/* definition helper that enum value decode procedure */
-#define DECODE_ENUM_VALUE(proc_name, enum_type, string_table)			\
-static int									\
-decode_##proc_name##_value(void *output, const json_t *value_obj,		\
-		__rte_unused const struct json_value_decode_rule *rule)		\
-{										\
-	int i;									\
-	enum_type type;								\
-	const char *str_val = json_string_value(value_obj);			\
-										\
-	for (i = 0; string_table[i][0] != '\0'; ++i) {				\
-		if (unlikely(strcmp(str_val, string_table[i]) == 0)) {		\
-			type = i;						\
-			memcpy(output, &type, sizeof(enum_type));		\
-			return 0;						\
-		}								\
-	}									\
-										\
-	return -1;								\
-}										\
-
-/* enum value decode procedure for "command_type" */
-DECODE_ENUM_VALUE(command_type, enum command_type, COMMAND_TYPE_STRINGS)
-
-/* enum value decode procedure for "classifier_type" */
-DECODE_ENUM_VALUE(classifier_type, enum spp_classifier_type, CLASSIFILER_TYPE_STRINGS)
-
-#if 0 /* not supported */
-/* decode procedure for integer */
+/* append process value to specified json object */
 static int
-decode_int_value(void *output, const json_t *value_obj,
-		__rte_unused const struct json_value_decode_rule *rule)
-{
-	int val = json_integer_value(value_obj);
-	memcpy(output, &val, sizeof(int));
-
-	return 0;
-}
-
-/* decode procedure for string */
-static int
-decode_string_value(void *output, const json_t *value_obj,
-		__rte_unused const struct json_value_decode_rule *rule)
-{
-	const char* str_val = json_string_value(value_obj);
-	strcpy(output, str_val);
-
-	return 0;
-}
-#endif
-
-/* decode procedure for mac address string */
-static int
-decode_mac_addr_str_value(void *output, const json_t *value_obj,
-		__rte_unused const struct json_value_decode_rule *rule)
+append_response_process_value(json_t *parent_obj)
 {
 	int ret = -1;
-	const char* str_val = json_string_value(value_obj);
+	json_t *proc_obj;
 
-	ret = spp_config_change_mac_str_to_int64(str_val);
-	if (unlikely(ret == -1)) {
-		RTE_LOG(ERR, SPP_COMMAND_PROC, "Bad mac address string. val=%s\n",
-				str_val);
-		return DERR_BAD_VALUE;
-	}
+	proc_obj = json_integer(spp_get_process_id());
+	if (unlikely(proc_obj == NULL))
+		return -1;
 
-	strcpy(output, str_val);
+	ret = json_object_set_new(parent_obj, "process", proc_obj);
+	if (unlikely(ret != 0))
+		return -1;
 
 	return 0;
 }
 
-/* decode procedure for spp_config_port_info */
-static int
-decode_port_value(void *output, const json_t *value_obj,
-		__rte_unused const struct json_value_decode_rule *rule)
+/* send response for decode error */
+static void
+send_decode_error_response(int *sock, const struct spp_command_request *request,
+		const struct spp_command_decode_error *decode_error)
 {
 	int ret = -1;
-	const char* str_val = json_string_value(value_obj);
-	struct spp_config_port_info *port = (struct spp_config_port_info *)output;
+	char *msg;
+	json_t *top_obj;
 
-	if (strcmp(str_val, CMD_UNUSE) == 0) {
-		port->if_type = UNDEF;
-		port->if_no = 0;
-		return 0;
+	top_obj = json_object();
+	if (unlikely(top_obj == NULL)) {
+		RTE_LOG(ERR, SPP_COMMAND_PROC, "Failed to make decode error response.");
+		return;
 	}
 
-	ret = spp_config_get_if_info(str_val, &port->if_type, &port->if_no);
+	/* create & append result array */
+	ret = append_response_decode_results_object(top_obj, request, decode_error);
 	if (unlikely(ret != 0)) {
-		RTE_LOG(ERR, SPP_COMMAND_PROC, "Bad port. val=%s\n", str_val);
-		return DERR_BAD_VALUE;
-	}
-
-	return 0;
-}
-
-/* decode json object */
-static int
-decode_json_object(void *output, const json_t *parent_obj,
-		const struct json_value_decode_rule *rules)
-{
-	int ret = -1;
-	int i, n;
-	json_t *obj;
-	json_t *value_obj;
-	const struct json_value_decode_rule *rule;
-
-	void *sub_output;
-
-	for (i = 0; unlikely(! IS_END_OF_DECODE_RULE(&rules[i])); ++ i) {
-		rule = rules + i;
-
-		RTE_LOG(DEBUG, SPP_COMMAND_PROC, "get one object. name=%s\n",
-				rule->name);
-
-		value_obj = json_object_get(parent_obj, rule->name);
-		if (unlikely(value_obj == NULL)) {
-			RTE_LOG(ERR, SPP_COMMAND_PROC, "No parameter. "
-					"name=%s\n", rule->name);
-			return DERR_NO_PARAM;
-		} else if (unlikely(json_typeof(value_obj) != rule->json_type)) {
-			RTE_LOG(ERR, SPP_COMMAND_PROC, "Bad value type. "
-					"name=%s\n", rule->name);
-			return DERR_BAD_TYPE;
-		}
-
-		switch (rule->json_type) {
-		case JSON_ARRAY:
-			RTE_LOG(DEBUG, SPP_COMMAND_PROC, "Decode array. num=%lu\n",
-					json_array_size(value_obj));
-
-			*(int *)((char *)output + rule->array.offset_num) = 
-					(int)json_array_size(value_obj);
-
-			json_array_foreach(value_obj, n, obj) {
-				RTE_LOG(DEBUG, SPP_COMMAND_PROC, "Decode array element. "
-						"index=%d\n", n);
-				
-				if (unlikely(json_typeof(obj) != rule->array.json_type)) {
-					RTE_LOG(ERR, SPP_COMMAND_PROC, "Bad value type. "
-							"name=%s, index=%d\n", rule->name, n);
-					return DERR_BAD_TYPE;
-				}
-
-				sub_output = DR_GET_OUTPUT(output, rule) + 
-						(rule->array.element_sz * n);
-				ret = (*rule->decode_proc)(sub_output, obj, rule);
-				if (unlikely(ret != 0)) {
-					RTE_LOG(ERR, SPP_COMMAND_PROC, "Bad value. "
-							"name=%s, index=%d\n", rule->name, n);
-					return ret;
-				}
-			}
-			break;
-		default:
-			sub_output = DR_GET_OUTPUT(output, rule);
-			ret = (*rule->decode_proc)(sub_output, value_obj, rule);
-			if (unlikely(ret != 0)) {
-				RTE_LOG(ERR, SPP_COMMAND_PROC, "Bad value. "
-						"name=%s\n", rule->name);
-				return ret;
-			}
-			break;
-		}
+		RTE_LOG(ERR, SPP_COMMAND_PROC, "Failed to make decode error response.");
+		json_decref(top_obj);
+		return;
 	}
 
-	return 0;
-}
-
-/* decode rule for command-base */
-const struct json_value_decode_rule DECODERULE_COMMAND_BASE[] = {
-	{
-		.name = "command",
-		.json_type = JSON_STRING,
-		.offset = offsetof(struct command, type),
-		.decode_proc = decode_command_type_value,
-	},
-	END_OF_DECODE_RULE
-};
+	/* serialize */
+	msg = json_dumps(top_obj, JSON_INDENT(2));
+	json_decref(top_obj);
 
-#if 0 /* not supported */
-/* decode rule for add-command-spec */
-const struct json_value_decode_rule DECODERULE_ADD_COMMAND[] = {
-	{
-		.name = "ports",
-		.json_type = JSON_ARRAY,
-		.offset = offsetof(struct add_command, ports),
-		.decode_proc = decode_port_value,
-
-		.array.element_sz = sizeof(struct spp_config_port_info),
-		.array.json_type = JSON_STRING,
-		.array.offset_num = offsetof(struct add_command, num_port),
-	},
-	END_OF_DECODE_RULE
-};
-#endif
-
-/* decode rule for classifier-table-command-spec */
-const struct json_value_decode_rule DECODERULE_CLASSIFIER_TABLE_COMMAND[] = {
-	{
-		.name = "type",
-		.json_type = JSON_STRING,
-		.offset = offsetof(struct classifier_table_command, type),
-		.decode_proc = decode_classifier_type_value,
-	},{
-		.name = "value",
-		.json_type = JSON_STRING,
-		.offset = offsetof(struct classifier_table_command, value),
-		.decode_proc = decode_mac_addr_str_value,
-	},{
-		.name = "port",
-		.json_type = JSON_STRING,
-		.offset = offsetof(struct classifier_table_command, port),
-		.decode_proc = decode_port_value,
-	},
-	END_OF_DECODE_RULE
-};
-
-/* decode procedure for command */
-static int
-decode_command_object(void* output, const json_t *parent_obj,
-		__rte_unused const struct json_value_decode_rule *rule)
-{
-	int ret = -1;
-	struct command *command = (struct command *)output;
-	const struct json_value_decode_rule *spec_rules = NULL;
-
-	/* decode command-base */
-	ret = decode_json_object(command, parent_obj, DECODERULE_COMMAND_BASE);
+	/* send response to requester */
+	ret = spp_send_message(sock, msg, strlen(msg));
 	if (unlikely(ret != 0)) {
-		RTE_LOG(ERR, SPP_COMMAND_PROC, "Bad command. ret=%d\n", ret);
-		return ret;
-	}
-
-	/* decode command-specific */
-	switch (command->type) {
-		case CMDTYPE_CLASSIFIER_TABLE:
-			spec_rules = DECODERULE_CLASSIFIER_TABLE_COMMAND;
-			break;
-
-		case CMDTYPE_FLUSH:
-			/* nothing specific */
-			break;
-
-		default:
-			/* unknown command */
-			RTE_LOG(ERR, SPP_COMMAND_PROC, "Unknown command. type=%d\n",
-					command->type);
-			return DERR_UNKNOWN_COMMAND;
-	}
-
-	if (likely(spec_rules != NULL)) {
-		ret = decode_json_object(&command->spec, parent_obj, spec_rules);
-		if (unlikely(ret != 0)) {
-			RTE_LOG(ERR, SPP_COMMAND_PROC, "Bad command. ret=%d\n", ret);
-			return ret;
-		}
+		RTE_LOG(ERR, SPP_COMMAND_PROC, "Failed to send decode error response.");
+		/* not return */
 	}
 
-	return 0;
+	free(msg);
 }
 
-/* decode rule for command request */
-const struct json_value_decode_rule DECODERULE_REQUEST[] = {
-	{
-		.name = "commands",
-		.json_type = JSON_ARRAY,
-		.offset = offsetof(struct request, commands),
-		.decode_proc = decode_command_object,
-
-		.array.element_sz = sizeof(struct command),
-		.array.json_type = JSON_OBJECT,
-		.array.offset_num = offsetof(struct request, num_command),
-		.array.offset_num_valid = offsetof(struct request, num_valid_command),
-	},
-	END_OF_DECODE_RULE
-};
-
-/* decode request from no-null-terminated string */
-static int
-decode_request(struct request *request, const char *request_str, size_t request_str_len)
+/* send response for command execution result */
+static void
+send_command_result_response(int *sock, const struct spp_command_request *request,
+		const struct command_result *command_results)
 {
 	int ret = -1;
+	char *msg;
 	json_t *top_obj;
-	json_error_t json_error;
 
-	/* parse json string */
-	top_obj = json_loadb(request_str, request_str_len, 0, &json_error);
+	top_obj = json_object();
 	if (unlikely(top_obj == NULL)) {
-		RTE_LOG(ERR, SPP_COMMAND_PROC, "Cannot parse command request. "
-				"error=%s, request_str=%.*s\n", 
-				json_error.text, (int)request_str_len, request_str);
-		return DERR_BAD_FORMAT;
+		RTE_LOG(ERR, SPP_COMMAND_PROC, "Failed to make command result response.");
+		return;
 	}
 
-	/* decode request object */
-	ret = decode_json_object(request, top_obj, DECODERULE_REQUEST);
+	/* create & append result array */
+	ret = append_response_command_results_object(top_obj, request, command_results);
 	if (unlikely(ret != 0)) {
-		RTE_LOG(ERR, SPP_COMMAND_PROC, "Cannot decode command request. "
-				"ret=%d, request_str=%.*s\n", 
-				ret, (int)request_str_len, request_str);
-		return ret;
+		RTE_LOG(ERR, SPP_COMMAND_PROC, "Failed to make command result response.");
+		json_decref(top_obj);
+		return;
 	}
 
-	return 0;
-}
-
-/* execute one command */
-static int
-execute_command(const struct command *command)
-{
-	int ret = -1;
-
-	switch (command->type) {
-	case CMDTYPE_CLASSIFIER_TABLE:
-		RTE_LOG(DEBUG, SPP_COMMAND_PROC, "Execute classifier_table command.");
-		ret = spp_update_classifier_table(
-				command->spec.classifier_table.type,
-				command->spec.classifier_table.value,
-				&command->spec.classifier_table.port);
-		break;
-
-	case CMDTYPE_FLUSH:
-		RTE_LOG(DEBUG, SPP_COMMAND_PROC, "Execute flush command.");
-		ret = spp_flush();
-		break;
+	/* append process information value */
+	if (request->is_requested_process) {
+		ret = append_response_process_value(top_obj);
+		if (unlikely(ret != 0)) {
+			RTE_LOG(ERR, SPP_COMMAND_PROC, "Failed to make command result response.");
+			json_decref(top_obj);
+			return;
+		}
+	}
 
-	case CMDTYPE_PROCESS:
-		RTE_LOG(DEBUG, SPP_COMMAND_PROC, "Execute process command.");
-		ret = spp_get_process_id();
-		break;
+	/* serialize */
+	msg = json_dumps(top_obj, JSON_INDENT(2));
+	json_decref(top_obj);
 
-	default:
-		RTE_LOG(ERR, SPP_COMMAND_PROC, "Unknown command. type=%d\n", command->type);
-		ret = 0;
-		break;
+	/* send response to requester */
+	ret = spp_send_message(sock, msg, strlen(msg));
+	if (unlikely(ret != 0)) {
+		RTE_LOG(ERR, SPP_COMMAND_PROC, "Failed to send decode error response.");
+		/* not return */
 	}
 
-	return ret;
+	free(msg);
 }
 
 /* process command request from no-null-terminated string */
 static int
-process_request(const char *request_str, size_t request_str_len)
+process_request(int *sock, const char *request_str, size_t request_str_len)
 {
 	int ret = -1;
 	int i;
 
-	struct request request;
-	memset(&request, 0, sizeof(struct request));
+	struct spp_command_request request;
+	struct spp_command_decode_error decode_error;
+	struct command_result command_results[SPP_CMD_MAX_COMMANDS];
 
-	RTE_LOG(DEBUG, SPP_COMMAND_PROC, "Start command request processing. "
+	memset(&request, 0, sizeof(struct spp_command_request));
+	memset(&decode_error, 0, sizeof(struct spp_command_decode_error));
+	memset(command_results, 0, sizeof(command_results));
+
+	RTE_LOG(INFO, SPP_COMMAND_PROC, "Start command request processing. "
 			"request_str=%.*s\n", (int)request_str_len, request_str);
 
-	ret = decode_request(&request, request_str, request_str_len);
+	/* decode request message */
+	ret = spp_command_decode_request(
+			&request, request_str, request_str_len, &decode_error);
 	if (unlikely(ret != 0)) {
-		RTE_LOG(DEBUG, SPP_COMMAND_PROC, "Failed to process command request. "
-		"ret=%d\n", ret);
+		/* send error response */
+		send_decode_error_response(sock, &request, &decode_error);
+		RTE_LOG(INFO, SPP_COMMAND_PROC, "End command request processing.\n");
 		return ret;
 	}
 
-	RTE_LOG(DEBUG, SPP_COMMAND_PROC, "Decoded command request. "
+	RTE_LOG(INFO, SPP_COMMAND_PROC, "Command request is valid. "
 			"num_command=%d, num_valid_command=%d\n",
 			request.num_command, request.num_valid_command);
 
+	/* execute commands */
 	for (i = 0; i < request.num_command ; ++i) {
 		ret = execute_command(request.commands + i);
+		if (unlikely(ret != 0)) {
+			command_results[i].code = CRES_FAILURE;
+
+			/* not execute remaining commands */
+			for (++i; i < request.num_command ; ++i)
+				command_results[i].code = CRES_INVALID;
+			break;
+		}
+
+		command_results[i].code = CRES_SUCCESS;
 	}
 
-	RTE_LOG(DEBUG, SPP_COMMAND_PROC, "Succeeded to process command request.\n");
+	/* send response */
+	send_command_result_response(sock, &request, command_results);
+
+	RTE_LOG(INFO, SPP_COMMAND_PROC, "End command request processing.\n");
 
 	return 0;
 }
@@ -739,10 +372,7 @@ process_request(const char *request_str, size_t request_str_len)
 int
 spp_command_proc_init(const char *controller_ip, int controller_port)
 {
-	strcpy(g_controller_ip, controller_ip);
-	g_controller_port = controller_port;
-
-	return 0;
+	return spp_command_conn_init(controller_ip, controller_port);
 }
 
 /* process command from controller. */
@@ -761,13 +391,13 @@ spp_command_proc_do(void)
 	static size_t lb_cnt = 0;
 
 	if (unlikely(msgbuf == NULL))
-		msgbuf = msgbuf_allocate(MESSAGE_BUFFER_BLOCK_SIZE);
+		msgbuf = spp_strbuf_allocate(MESSAGE_BUFFER_BLOCK_SIZE);
 
-	ret = connect_to_controller(&sock);
+	ret = spp_connect_to_controller(&sock);
 	if (unlikely(ret != 0))
 		return;
 
-	msg_ret = receive_message(&sock, &msgbuf);
+	msg_ret = spp_receive_message(&sock, &msgbuf);
 	if (likely(msg_ret <= 0)) {
 		return;
 	}
@@ -784,9 +414,9 @@ spp_command_proc_do(void)
 
 		if (likely(lb_cnt != 0) && unlikely(rb_cnt == lb_cnt)) {
 			msg_len += (i + 1);
-			ret = process_request(msgbuf, msg_len);
+			ret = process_request(&sock, msgbuf, msg_len);
 
-			msgbuf_remove_front(msgbuf, msg_len);
+			spp_strbuf_remove_front(msgbuf, msg_len);
 			msg_ret = 0;
 			msg_len = 0;
 			rb_cnt = 0;
diff --git a/src/vf/string_buffer.c b/src/vf/string_buffer.c
new file mode 100644
index 0000000..535d050
--- /dev/null
+++ b/src/vf/string_buffer.c
@@ -0,0 +1,90 @@
+#include <stdlib.h>
+#include <string.h>
+
+#include <rte_branch_prediction.h>
+
+#include "string_buffer.h"
+
+/* get message buffer capacity */
+inline size_t
+strbuf_get_capacity(const char *strbuf)
+{
+	return *((const size_t *)(strbuf - sizeof(size_t)));
+}
+
+/* re-allocate message buffer */
+inline char*
+strbuf_reallocate(char *strbuf, size_t required_len)
+{
+	size_t new_cap = strbuf_get_capacity(strbuf) * 2;
+	char *new_strbuf = NULL;
+
+	while (unlikely(new_cap <= required_len))
+		new_cap *= 2;
+
+	new_strbuf = spp_strbuf_allocate(new_cap);
+	if (unlikely(new_strbuf == NULL))
+		return NULL;
+
+	strcpy(new_strbuf, strbuf);
+	spp_strbuf_free(strbuf);
+
+	return new_strbuf;
+}
+
+/* allocate message buffer */
+char*
+spp_strbuf_allocate(size_t capacity)
+{
+	char* buf = (char *)malloc(capacity + sizeof(size_t));
+	if (unlikely(buf == NULL))
+		return NULL;
+
+	memset(buf, 0x00, capacity + sizeof(size_t));
+	*((size_t *)buf) = capacity;
+
+	return buf + sizeof(size_t);
+}
+
+/* free message buffer */
+void
+spp_strbuf_free(char* strbuf)
+{
+	if (likely(strbuf != NULL))
+		free(strbuf - sizeof(size_t));
+}
+
+/* append message to buffer */
+char*
+spp_strbuf_append(char *strbuf, const char *append, size_t append_len)
+{
+	size_t cap = strbuf_get_capacity(strbuf);
+	size_t len = strlen(strbuf);
+	char *new_strbuf = strbuf;
+
+	if (unlikely(len + append_len >= cap)) {
+		new_strbuf = strbuf_reallocate(strbuf, len + append_len);
+		if (unlikely(new_strbuf == NULL))
+			return NULL;
+	}
+
+	memcpy(new_strbuf + len, append, append_len);
+	*(new_strbuf + len + append_len) = '\0';
+
+	return new_strbuf;
+}
+
+/* remove message from front */
+char*
+spp_strbuf_remove_front(char *strbuf, size_t remove_len)
+{
+	size_t len = strlen(strbuf);
+	size_t new_len = len - remove_len;
+
+	if (likely(new_len == 0)) {
+		*strbuf = '\0';
+		return strbuf;
+	}
+
+	return memmove(strbuf, strbuf + remove_len, new_len + 1);
+}
diff --git a/src/vf/string_buffer.h b/src/vf/string_buffer.h
new file mode 100644
index 0000000..adc52ef
--- /dev/null
+++ b/src/vf/string_buffer.h
@@ -0,0 +1,16 @@
+#ifndef _STRING_BUFFER_H_
+#define _STRING_BUFFER_H_
+
+/* allocate message buffer */
+char* spp_strbuf_allocate(size_t capacity);
+
+/* free message buffer */
+void spp_strbuf_free(char* strbuf);
+
+/* append message to buffer */
+char* spp_strbuf_append(char *strbuf, const char *append, size_t append_len);
+
+/* remove message from front */
+char* spp_strbuf_remove_front(char *strbuf, size_t remove_len);
+
+#endif /* _STRING_BUFFER_H_ */
-- 
1.9.1

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

* [spp] [PATCH 25/57] spp_vf: add new log and line break
  2017-12-26  1:54 ` Yasufumi Ogawa
                     ` (23 preceding siblings ...)
  2017-12-28  4:55   ` [spp] [PATCH 24/57] spp_vf: split command processing source file x-fn-spp
@ 2017-12-28  4:55   ` x-fn-spp
  2017-12-28  4:55   ` [spp] [PATCH 26/57] spp_vf: support get-process-id command x-fn-spp
                     ` (31 subsequent siblings)
  56 siblings, 0 replies; 97+ messages in thread
From: x-fn-spp @ 2017-12-28  4:55 UTC (permalink / raw)
  To: spp

From: Hiroyuki Nakamura <nakamura.hioryuki@po.ntt-tx.co.jp>

* Add new log of command response for better understanding.

Signed-off-by: Daiki Yamashita <yamashita.daiki.z01@as.ntt-tx.co.jp>
Signed-off-by: Yasufum Ogawa <ogawa.yasufumi@lab.ntt.co.jp>
---
 src/vf/command_conn.c |  2 +-
 src/vf/command_proc.c | 10 ++++++++--
 2 files changed, 9 insertions(+), 3 deletions(-)

diff --git a/src/vf/command_conn.c b/src/vf/command_conn.c
index edd4d4c..7da4eec 100644
--- a/src/vf/command_conn.c
+++ b/src/vf/command_conn.c
@@ -89,7 +89,6 @@ spp_receive_message(int *sock, char **strbuf)
 	size_t rx_buf_sz = MESSAGE_BUFFER_BLOCK_SIZE;
 
 	ret = recv(*sock, rx_buf, rx_buf_sz, 0);
-	RTE_LOG(DEBUG, SPP_COMMAND_PROC, "Receive message. count=%d\n", ret);
 	if (ret <= 0) {
 		if (ret == 0) {
 			RTE_LOG(INFO, SPP_COMMAND_PROC,
@@ -108,6 +107,7 @@ spp_receive_message(int *sock, char **strbuf)
 		return -1;
 	}
 
+	RTE_LOG(DEBUG, SPP_COMMAND_PROC, "Receive message. count=%d\n", ret);
 	n_rx = ret;
 
 	new_strbuf = spp_strbuf_append(*strbuf, rx_buf, n_rx);
diff --git a/src/vf/command_proc.c b/src/vf/command_proc.c
index 097483c..cda72be 100644
--- a/src/vf/command_proc.c
+++ b/src/vf/command_proc.c
@@ -256,6 +256,9 @@ send_decode_error_response(int *sock, const struct spp_command_request *request,
 	msg = json_dumps(top_obj, JSON_INDENT(2));
 	json_decref(top_obj);
 
+	RTE_LOG(INFO, SPP_COMMAND_PROC, "Make command response (decode error). "
+			"response_str=\n%s\n", msg);
+
 	/* send response to requester */
 	ret = spp_send_message(sock, msg, strlen(msg));
 	if (unlikely(ret != 0)) {
@@ -303,10 +306,13 @@ send_command_result_response(int *sock, const struct spp_command_request *reques
 	msg = json_dumps(top_obj, JSON_INDENT(2));
 	json_decref(top_obj);
 
+	RTE_LOG(INFO, SPP_COMMAND_PROC, "Make command response (command result). "
+			"response_str=\n%s\n", msg);
+
 	/* send response to requester */
 	ret = spp_send_message(sock, msg, strlen(msg));
 	if (unlikely(ret != 0)) {
-		RTE_LOG(ERR, SPP_COMMAND_PROC, "Failed to send decode error response.");
+		RTE_LOG(ERR, SPP_COMMAND_PROC, "Failed to send command result response.");
 		/* not return */
 	}
 
@@ -329,7 +335,7 @@ process_request(int *sock, const char *request_str, size_t request_str_len)
 	memset(command_results, 0, sizeof(command_results));
 
 	RTE_LOG(INFO, SPP_COMMAND_PROC, "Start command request processing. "
-			"request_str=%.*s\n", (int)request_str_len, request_str);
+			"request_str=\n%.*s\n", (int)request_str_len, request_str);
 
 	/* decode request message */
 	ret = spp_command_decode_request(
-- 
1.9.1

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

* [spp] [PATCH 26/57] spp_vf: support get-process-id command
  2017-12-26  1:54 ` Yasufumi Ogawa
                     ` (24 preceding siblings ...)
  2017-12-28  4:55   ` [spp] [PATCH 25/57] spp_vf: add new log and line break x-fn-spp
@ 2017-12-28  4:55   ` x-fn-spp
  2017-12-28  4:55   ` [spp] [PATCH 27/57] spp_vf: update socket creation procedure x-fn-spp
                     ` (30 subsequent siblings)
  56 siblings, 0 replies; 97+ messages in thread
From: x-fn-spp @ 2017-12-28  4:55 UTC (permalink / raw)
  To: spp

From: Hiroyuki Nakamura <nakamura.hioryuki@po.ntt-tx.co.jp>

The get-process-id command was missed in the command type check,
and it was processed as an unrecognized command.

Signed-off-by: Daiki Yamashita <yamashita.daiki.z01@as.ntt-tx.co.jp>
Signed-off-by: Yasufum Ogawa <ogawa.yasufumi@lab.ntt.co.jp>
---
 src/vf/command_dec.c | 9 ++-------
 1 file changed, 2 insertions(+), 7 deletions(-)

diff --git a/src/vf/command_dec.c b/src/vf/command_dec.c
index 85f935b..d3ff27a 100644
--- a/src/vf/command_dec.c
+++ b/src/vf/command_dec.c
@@ -347,15 +347,10 @@ decode_command_object(void* output, const json_t *parent_obj,
 			spec_rules = DECODERULE_CLASSIFIER_TABLE_COMMAND;
 			break;
 
-		case SPP_CMDTYPE_FLUSH:
+		default:
 			/* nothing specific */
+			/* (unknown command is already checked) */
 			break;
-
-		default:
-			/* unknown command */
-			RTE_LOG(ERR, SPP_COMMAND_PROC, "Unknown command. type=%d\n",
-					command->type);
-			return set_decode_error(error, SPP_CMD_DERR_UNKNOWN_COMMAND, rule);
 	}
 
 	if (likely(spec_rules != NULL)) {
-- 
1.9.1

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

* [spp] [PATCH 27/57] spp_vf: update socket creation procedure
  2017-12-26  1:54 ` Yasufumi Ogawa
                     ` (25 preceding siblings ...)
  2017-12-28  4:55   ` [spp] [PATCH 26/57] spp_vf: support get-process-id command x-fn-spp
@ 2017-12-28  4:55   ` x-fn-spp
  2017-12-28  4:55   ` [spp] [PATCH 28/57] spp_vf: change log level and add line break x-fn-spp
                     ` (29 subsequent siblings)
  56 siblings, 0 replies; 97+ messages in thread
From: x-fn-spp @ 2017-12-28  4:55 UTC (permalink / raw)
  To: spp

From: Hiroyuki Nakamura <nakamura.hioryuki@po.ntt-tx.co.jp>

Update socket socket creation procedure as follows:
* Stop recreating socket spontaneously on failure so the caller can
  decide corresponding action.
* Add socket closing procedure when error occurred.
* Add comments.

Signed-off-by: Daiki Yamashita <yamashita.daiki.z01@as.ntt-tx.co.jp>
Signed-off-by: Yasufum Ogawa <ogawa.yasufumi@lab.ntt.co.jp>
---
 src/vf/command_conn.c  | 26 ++++++++++++++------------
 src/vf/command_proc.c  |  8 ++++----
 src/vf/string_buffer.h | 48 ++++++++++++++++++++++++++++++++++++++++++++----
 3 files changed, 62 insertions(+), 20 deletions(-)

diff --git a/src/vf/command_conn.c b/src/vf/command_conn.c
index edd4d4c..4ac61a2 100644
--- a/src/vf/command_conn.c
+++ b/src/vf/command_conn.c
@@ -43,21 +43,19 @@ spp_connect_to_controller(int *sock)
 		return 0;
 
 	/* create socket */
+	RTE_LOG(INFO, SPP_COMMAND_PROC, "Creating socket...\n");
+	*sock = socket(AF_INET, SOCK_STREAM, 0);
 	if (*sock < 0) {
-		RTE_LOG(INFO, SPP_COMMAND_PROC, "Creating socket...\n");
-		*sock = socket(AF_INET, SOCK_STREAM, 0);
-		if (*sock < 0) {
-			RTE_LOG(ERR, SPP_COMMAND_PROC, 
-					"Cannot create tcp socket. errno=%d\n", errno);
-			return -1;
-		}
-
-		memset(&controller_addr, 0, sizeof(controller_addr));
-		controller_addr.sin_family = AF_INET;
-		controller_addr.sin_addr.s_addr = inet_addr(g_controller_ip);
-		controller_addr.sin_port = htons(g_controller_port);
+		RTE_LOG(ERR, SPP_COMMAND_PROC, 
+				"Cannot create tcp socket. errno=%d\n", errno);
+		return -1;
 	}
 
+	memset(&controller_addr, 0, sizeof(controller_addr));
+	controller_addr.sin_family = AF_INET;
+	controller_addr.sin_addr.s_addr = inet_addr(g_controller_ip);
+	controller_addr.sin_port = htons(g_controller_port);
+
 	/* connect to */
 	RTE_LOG(INFO, SPP_COMMAND_PROC, "Trying to connect ... socket=%d\n", *sock);
 	ret = connect(*sock, (struct sockaddr *)&controller_addr,
@@ -65,6 +63,8 @@ spp_connect_to_controller(int *sock)
 	if (ret < 0) {
 		RTE_LOG(ERR, SPP_COMMAND_PROC,
 				"Cannot connect to controller. errno=%d\n", errno);
+		close(*sock);
+		*sock = -1;
 		return -1;
 	}
 
@@ -129,6 +129,8 @@ spp_send_message(int *sock, const char* message, size_t message_len)
 	ret = send(*sock, message, message_len, 0);
 	if (unlikely(ret == -1)) {
 		RTE_LOG(ERR, SPP_COMMAND_PROC, "Send failure. ret=%d\n", ret);
+		close(*sock);
+		*sock = -1;
 		return -1;
 	}
 
diff --git a/src/vf/command_proc.c b/src/vf/command_proc.c
index 097483c..10e209c 100644
--- a/src/vf/command_proc.c
+++ b/src/vf/command_proc.c
@@ -16,7 +16,7 @@
 #define RTE_LOGTYPE_SPP_COMMAND_PROC RTE_LOGTYPE_USER1
 
 /* request message initial size */
-#define MESSAGE_BUFFER_BLOCK_SIZE 2048
+#define CMD_REQ_BUF_INIT_SIZE 2048
 
 /* command execution result code */
 enum command_result_code {
@@ -112,7 +112,7 @@ create_error_result_object(const char* err_msg)
 			"message", err_msg);
 }
 
-/*  */
+/* append decode result array object to specified object */
 static int
 append_response_decode_results_object(json_t *parent_obj,
 		const struct spp_command_request *request,
@@ -167,7 +167,7 @@ append_response_decode_results_object(json_t *parent_obj,
 	return 0;
 }
 
-/*  */
+/* append command execution result array object to specified object */
 static int
 append_response_command_results_object(json_t *parent_obj,
 		const struct spp_command_request *request,
@@ -391,7 +391,7 @@ spp_command_proc_do(void)
 	static size_t lb_cnt = 0;
 
 	if (unlikely(msgbuf == NULL))
-		msgbuf = spp_strbuf_allocate(MESSAGE_BUFFER_BLOCK_SIZE);
+		msgbuf = spp_strbuf_allocate(CMD_REQ_BUF_INIT_SIZE);
 
 	ret = spp_connect_to_controller(&sock);
 	if (unlikely(ret != 0))
diff --git a/src/vf/string_buffer.h b/src/vf/string_buffer.h
index adc52ef..9879b9d 100644
--- a/src/vf/string_buffer.h
+++ b/src/vf/string_buffer.h
@@ -1,16 +1,56 @@
 #ifndef _STRING_BUFFER_H_
 #define _STRING_BUFFER_H_
 
-/* allocate message buffer */
+/**
+ * allocate string buffer from heap memory.
+ *
+ * @attention allocated memory must free by spp_strbuf_free function.
+ *
+ * @param capacity
+ *  initial buffer size (include null char).
+ *
+ * @retval not-NULL pointer to the allocated memory. 
+ * @retval NULL     error.
+ */
 char* spp_strbuf_allocate(size_t capacity);
 
-/* free message buffer */
+/**
+ * free string buffer.
+ *
+ * @param strbuf
+ *  spp_strbuf_allocate/spp_strbuf_append return value.
+ */
 void spp_strbuf_free(char* strbuf);
 
-/* append message to buffer */
+/**
+ * append string to buffer.
+ *
+ * @param strbuf
+ *  destination string buffer.
+ *  spp_strbuf_allocate/spp_strbuf_append return value.
+ *
+ * @param append
+ *  string to append. normal c-string.
+ *
+ * @param append_len
+ *  length of append string.
+ *
+ * @return if the capacity is enough, the 1st parameter "strbuf", 
+ *         if it is insufficient, a new pointer to the allocated memory.
+ *         in that case, old strbuf is freed in the function.
+ */
 char* spp_strbuf_append(char *strbuf, const char *append, size_t append_len);
 
-/* remove message from front */
+/**
+ * remove string from front.
+ *
+ * @param strbuf
+ *  target string buffer.
+ *  spp_strbuf_allocate/spp_strbuf_append return value.
+ *
+ * @param remove_len
+ *  length of remove.
+ */
 char* spp_strbuf_remove_front(char *strbuf, size_t remove_len);
 
 #endif /* _STRING_BUFFER_H_ */
-- 
1.9.1

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

* [spp] [PATCH 28/57] spp_vf: change log level and add line break
  2017-12-26  1:54 ` Yasufumi Ogawa
                     ` (26 preceding siblings ...)
  2017-12-28  4:55   ` [spp] [PATCH 27/57] spp_vf: update socket creation procedure x-fn-spp
@ 2017-12-28  4:55   ` x-fn-spp
  2017-12-28  4:55   ` [spp] [PATCH 29/57] spp_vf: replace unsupported jansson api x-fn-spp
                     ` (28 subsequent siblings)
  56 siblings, 0 replies; 97+ messages in thread
From: x-fn-spp @ 2017-12-28  4:55 UTC (permalink / raw)
  To: spp

From: Hiroyuki Nakamura <nakamura.hioryuki@po.ntt-tx.co.jp>

* Change log level and add line break.
* Refactoring

Signed-off-by: Daiki Yamashita <yamashita.daiki.z01@as.ntt-tx.co.jp>
Signed-off-by: Yasufum Ogawa <ogawa.yasufumi@lab.ntt.co.jp>
---
 src/vf/classifier_mac.c | 10 +++++-----
 src/vf/command_proc.c   |  6 +++---
 2 files changed, 8 insertions(+), 8 deletions(-)

diff --git a/src/vf/classifier_mac.c b/src/vf/classifier_mac.c
index 0852938..cc4af2b 100644
--- a/src/vf/classifier_mac.c
+++ b/src/vf/classifier_mac.c
@@ -109,12 +109,12 @@ init_classifier_table(struct rte_hash **classifier_table,
 		}
 
 		rte_memcpy(&eth_addr, &core_info->tx_ports[i].mac_addr, ETHER_ADDR_LEN);
+		ether_format_addr(mac_addr_str, sizeof(mac_addr_str), &eth_addr);
 
 		/* add entry to classifier mac table */
 		ret = rte_hash_add_key_data(*classifier_table,
 				(void*)&eth_addr, (void*)(long)i);
 		if (unlikely(ret < 0)) {
-			ether_format_addr(mac_addr_str, sizeof(mac_addr_str), &eth_addr);
 			RTE_LOG(ERR, SPP_CLASSIFIER_MAC,
 					"Cannot add entry to classifier mac table. "
 					"ret=%d, mac_addr=%s\n", ret, mac_addr_str);
@@ -123,7 +123,7 @@ init_classifier_table(struct rte_hash **classifier_table,
 			return -1;
 		}
 
-		RTE_LOG(DEBUG, SPP_CLASSIFIER_MAC, "Add entry to classifier mac table. "
+		RTE_LOG(INFO, SPP_CLASSIFIER_MAC, "Add entry to classifier mac table. "
 				"mac_addr=%s, if_type=%d, if_no=%d, dpdk_port=%d\n",
 				mac_addr_str, 
 				core_info->tx_ports[i].if_type, 
@@ -299,7 +299,7 @@ change_update_index(struct classifier_mac_mng_info *classifier_mng_info, unsigne
 	if (unlikely(classifier_mng_info->ref_index == 
 			classifier_mng_info->upd_index)) {
 		RTE_LOG(DEBUG, SPP_CLASSIFIER_MAC,
-				"Core[%u] Change update index.", lcore_id);
+				"Core[%u] Change update index.\n", lcore_id);
 		classifier_mng_info->upd_index = 
 				(classifier_mng_info->upd_index + 1) % 
 				NUM_CLASSIFIER_MAC_INFO;
@@ -320,7 +320,7 @@ spp_classifier_mac_update(struct spp_core_info *core_info)
 			classifier_mng_info->info + classifier_mng_info->upd_index;
 
 	RTE_LOG(INFO, SPP_CLASSIFIER_MAC,
-			"Core[%u] Start update component.", lcore_id);
+			"Core[%u] Start update component.\n", lcore_id);
 
 	/* initialize update side classifier table */
 	ret = init_classifier_table(&classifier_info->classifier_table, core_info);
@@ -338,7 +338,7 @@ spp_classifier_mac_update(struct spp_core_info *core_info)
 		rte_delay_us_block(CHANGE_UPDATE_INDEX_WAIT_INTERVAL);
 
 	RTE_LOG(INFO, SPP_CLASSIFIER_MAC,
-			"Core[%u] Complete update component.", lcore_id);
+			"Core[%u] Complete update component.\n", lcore_id);
 
 	return 0;
 }
diff --git a/src/vf/command_proc.c b/src/vf/command_proc.c
index cda72be..81bb625 100644
--- a/src/vf/command_proc.c
+++ b/src/vf/command_proc.c
@@ -38,7 +38,7 @@ execute_command(const struct spp_command *command)
 
 	switch (command->type) {
 	case SPP_CMDTYPE_CLASSIFIER_TABLE:
-		RTE_LOG(DEBUG, SPP_COMMAND_PROC, "Execute classifier_table command.");
+		RTE_LOG(INFO, SPP_COMMAND_PROC, "Execute classifier_table command.\n");
 		ret = spp_update_classifier_table(
 				command->spec.classifier_table.type,
 				command->spec.classifier_table.value,
@@ -46,12 +46,12 @@ execute_command(const struct spp_command *command)
 		break;
 
 	case SPP_CMDTYPE_FLUSH:
-		RTE_LOG(DEBUG, SPP_COMMAND_PROC, "Execute flush command.");
+		RTE_LOG(INFO, SPP_COMMAND_PROC, "Execute flush command.\n");
 		ret = spp_flush();
 		break;
 
 	case SPP_CMDTYPE_PROCESS:
-		RTE_LOG(DEBUG, SPP_COMMAND_PROC, "Process command is requested.");
+		RTE_LOG(INFO, SPP_COMMAND_PROC, "Execute process command.\n");
 		/* nothing to do here */
 		break;
 
-- 
1.9.1

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

* [spp] [PATCH 29/57] spp_vf: replace unsupported jansson api
  2017-12-26  1:54 ` Yasufumi Ogawa
                     ` (27 preceding siblings ...)
  2017-12-28  4:55   ` [spp] [PATCH 28/57] spp_vf: change log level and add line break x-fn-spp
@ 2017-12-28  4:55   ` x-fn-spp
  2017-12-28  4:55   ` [spp] [PATCH 30/57] spp_vf: change order of command result in json object x-fn-spp
                     ` (27 subsequent siblings)
  56 siblings, 0 replies; 97+ messages in thread
From: x-fn-spp @ 2017-12-28  4:55 UTC (permalink / raw)
  To: spp

From: Hiroyuki Nakamura <nakamura.hioryuki@po.ntt-tx.co.jp>

* Stop using the json_path_get function and replace it with our own
  spp_config_get_path_obj function.
* The json_path_get function is only available at branch of
  Jansson project, and it can not be provided in most of
  the pkgs(deb,rpm). This change made
  for build convenience.

Signed-off-by: Kentaro Watanabe <watanabe.kentaro.z01@as.ntt-tx.co.jp>
Signed-off-by: Yasufum Ogawa <ogawa.yasufumi@lab.ntt.co.jp>
---
 src/vf/spp_config.c | 68 ++++++++++++++++++++++++++++++++++++++++++++++-------
 src/vf/spp_config.h |  9 +++++++
 2 files changed, 68 insertions(+), 9 deletions(-)

diff --git a/src/vf/spp_config.c b/src/vf/spp_config.c
index 4ad4f87..6d8e380 100644
--- a/src/vf/spp_config.c
+++ b/src/vf/spp_config.c
@@ -25,13 +25,63 @@
 #define JSONPATH_TX_TABLE   "$.tx_port_table"
 
 /*
+ * Instead of json_path_get
+ */
+json_t *
+spp_config_get_path_obj(const json_t *json, const char *path)
+{
+	const json_t *obj, *array_obj;
+	json_t *new_obj = NULL;
+	char buf[SPP_CONFIG_PATH_LEN];
+	char *str, *token, *bracket, *endptr;
+	int index = 0;
+
+	if (unlikely(path[0] != '$') || unlikely(path[1] != '.') ||
+			unlikely(strlen(path) >= SPP_CONFIG_PATH_LEN))
+		return NULL;
+
+	strcpy(buf, path);
+	obj = json;
+	str = buf+1;
+	while(str != NULL) {
+		token = str+1;
+		str = strpbrk(token, ".");
+		if (str != NULL)
+			*str = '\0';
+
+		bracket = strpbrk(token, "[");
+		if (bracket != NULL)
+			*bracket = '\0';
+
+		new_obj = json_object_get(obj, token);
+		if (new_obj == NULL)
+			return NULL;
+
+		if (bracket != NULL) {
+			index = strtol(bracket+1, &endptr, 0);
+			if (unlikely(str == endptr) || unlikely(*endptr != ']'))
+				return NULL;
+
+			array_obj = new_obj;
+			new_obj = json_array_get(array_obj, index);
+			if (new_obj == NULL)
+				return NULL;
+		}
+
+		obj = new_obj;
+	}
+
+	return new_obj;
+}
+
+/*
  * Get integer data from config
  */
 static int
 config_get_int_value(const json_t *obj, const char *path, int *value)
 {
 	/* 指定パラメータのJsonオブジェクト取得 */
-	json_t *tmp_obj = json_path_get(obj, path);
+	json_t *tmp_obj = spp_config_get_path_obj(obj, path);
 	if (unlikely(tmp_obj == NULL)) {
 		/* 必須でないデータを取得する場合を考慮し、DEBUGログとする。 */
 		RTE_LOG(DEBUG, APP, "No parameter. (path = %s)\n", path);
@@ -58,7 +108,7 @@ static int
 config_get_str_value(const json_t *obj, const char *path, char *value)
 {
 	/* 指定パラメータのJsonオブジェクト取得 */
-	json_t *tmp_obj = json_path_get(obj, path);
+	json_t *tmp_obj = spp_config_get_path_obj(obj, path);
 	if (unlikely(tmp_obj == NULL)) {
 		RTE_LOG(DEBUG, APP, "No parameter. (path = %s)\n", path);
 		return -1;
@@ -204,7 +254,7 @@ config_load_classifier_table(const json_t *obj,
 		struct spp_config_classifier_table *classifier_table)
 {
 	/* classifier_table用オブジェクト取得 */
-	json_t *classifier_obj = json_path_get(obj, JSONPATH_CLASSIFIER_TABLE);
+	json_t *classifier_obj = spp_config_get_path_obj(obj, JSONPATH_CLASSIFIER_TABLE);
 	if (unlikely(classifier_obj == NULL)) {
 		RTE_LOG(INFO, APP, "No classifier table.\n");
 		return 0;
@@ -219,7 +269,7 @@ config_load_classifier_table(const json_t *obj,
 	}
 
 	/* table用オブジェクト取得 */
-	json_t *array_obj = json_path_get(classifier_obj, JSONPATH_TABLE);
+	json_t *array_obj = spp_config_get_path_obj(classifier_obj, JSONPATH_TABLE);
 	if (unlikely(!array_obj)) {
 		RTE_LOG(ERR, APP, "Json object get failed. (path = %s)\n",
 				JSONPATH_TABLE);
@@ -338,7 +388,7 @@ config_set_rx_port(enum spp_core_type type, json_t *obj,
 	if (type == SPP_CONFIG_MERGE) {
 		/* Merge */
 		/* 受信ポート用オブジェクト取得 */
-		json_t *array_obj = json_path_get(obj, JSONPATH_RX_PORT);
+		json_t *array_obj = spp_config_get_path_obj(obj, JSONPATH_RX_PORT);
 		if (unlikely(!array_obj)) {
 			RTE_LOG(ERR, APP, "Json object get failed. (path = %s, route = merge)\n",
 				JSONPATH_RX_PORT);
@@ -454,7 +504,7 @@ config_set_tx_port(enum spp_core_type type, json_t *obj,
 		}
 	} else {
 		/* Classifier */
-		json_t *table_obj = json_path_get(obj, JSONPATH_TX_TABLE);
+		json_t *table_obj = spp_config_get_path_obj(obj, JSONPATH_TX_TABLE);
 		if (unlikely(table_obj != NULL)) {
 			/* Classifier Tableから取得 */
 			functions->num_tx_port = classifier_table->num_table;
@@ -473,7 +523,7 @@ config_set_tx_port(enum spp_core_type type, json_t *obj,
 		{
 			/* tx_portパラメータより取得 */
 			/* 送信ポート用オブジェクト取得 */
-			json_t *array_obj = json_path_get(obj, JSONPATH_TX_PORT);
+			json_t *array_obj = spp_config_get_path_obj(obj, JSONPATH_TX_PORT);
 			if (unlikely(array_obj == NULL)) {
 				RTE_LOG(ERR, APP, "Json object get failed. (path = %s, route = classifier)\n",
 					JSONPATH_TX_PORT);
@@ -545,7 +595,7 @@ config_load_proc_info(const json_t *obj, int node_id, struct spp_config_area *co
 	struct spp_config_classifier_table *classifier_table = &config->classifier_table;
 
 	/* proc_table用オブジェクト取得 */
-	json_t *proc_table_obj = json_path_get(obj, JSONPATH_PROC_TABLE);
+	json_t *proc_table_obj = spp_config_get_path_obj(obj, JSONPATH_PROC_TABLE);
 	if (unlikely(proc_table_obj == NULL)) {
 		RTE_LOG(ERR, APP, "Json object get failed. (path = %s)\n",
 				JSONPATH_PROC_TABLE);
@@ -599,7 +649,7 @@ config_load_proc_info(const json_t *obj, int node_id, struct spp_config_area *co
 	}
 
 	/* functions用オブジェクト取得 */
-	json_t *array_obj = json_path_get(proc_obj, JSONPATH_FUNCTIONS);
+	json_t *array_obj = spp_config_get_path_obj(proc_obj, JSONPATH_FUNCTIONS);
 	if (unlikely(!array_obj)) {
 		RTE_LOG(ERR, APP, "Json object get failed. (path = %s)\n",
 				JSONPATH_FUNCTIONS);
diff --git a/src/vf/spp_config.h b/src/vf/spp_config.h
index 37414cf..7945807 100644
--- a/src/vf/spp_config.h
+++ b/src/vf/spp_config.h
@@ -1,6 +1,7 @@
 #ifndef __SPP_CONFIG_H__
 #define __SPP_CONFIG_H__
 
+#include <jansson.h>
 #include "common.h"
 
 #define SPP_CONFIG_FILE_PATH "/usr/local/etc/spp/spp.json"
@@ -12,6 +13,7 @@
 #define SPP_CONFIG_STR_LEN 32
 #define SPP_CONFIG_MAC_TABLE_MAX 16
 #define SPP_CONFIG_CORE_MAX 64
+#define SPP_CONFIG_PATH_LEN 1024
 
 /*
  * Process type for each CORE
@@ -81,6 +83,13 @@ struct spp_config_area {
 };
 
 /*
+ * Instead of json_path_get
+ * OK : Json object address
+ * NG : NULL
+ */
+json_t *spp_config_get_path_obj(const json_t *json, const char *path);
+
+/*
  * Change mac address string to int64
  * OK : int64 that store mac address
  * NG : -1
-- 
1.9.1

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

* [spp] [PATCH 30/57] spp_vf: change order of command result in json object
  2017-12-26  1:54 ` Yasufumi Ogawa
                     ` (28 preceding siblings ...)
  2017-12-28  4:55   ` [spp] [PATCH 29/57] spp_vf: replace unsupported jansson api x-fn-spp
@ 2017-12-28  4:55   ` x-fn-spp
  2017-12-28  4:55   ` [spp] [PATCH 31/57] spp_vf: use prediction keywords x-fn-spp
                     ` (26 subsequent siblings)
  56 siblings, 0 replies; 97+ messages in thread
From: x-fn-spp @ 2017-12-28  4:55 UTC (permalink / raw)
  To: spp

From: Hiroyuki Nakamura <nakamura.hioryuki@po.ntt-tx.co.jp>

* Change order of command result in json object (bug fix).

Signed-off-by: Daiki Yamashita <yamashita.daiki.z01@as.ntt-tx.co.jp>
Signed-off-by: Yasufum Ogawa <ogawa.yasufumi@lab.ntt.co.jp>
---
 src/vf/command_proc.c | 22 +++++++++++++++-------
 1 file changed, 15 insertions(+), 7 deletions(-)

diff --git a/src/vf/command_proc.c b/src/vf/command_proc.c
index 81bb625..291e3da 100644
--- a/src/vf/command_proc.c
+++ b/src/vf/command_proc.c
@@ -244,6 +244,10 @@ send_decode_error_response(int *sock, const struct spp_command_request *request,
 		return;
 	}
 
+	/* **
+	 * output order of object in string is inverse to addition order
+	 * **/
+
 	/* create & append result array */
 	ret = append_response_decode_results_object(top_obj, request, decode_error);
 	if (unlikely(ret != 0)) {
@@ -284,13 +288,9 @@ send_command_result_response(int *sock, const struct spp_command_request *reques
 		return;
 	}
 
-	/* create & append result array */
-	ret = append_response_command_results_object(top_obj, request, command_results);
-	if (unlikely(ret != 0)) {
-		RTE_LOG(ERR, SPP_COMMAND_PROC, "Failed to make command result response.");
-		json_decref(top_obj);
-		return;
-	}
+	/* **
+	 * output order of object in string is inverse to addition order
+	 * **/
 
 	/* append process information value */
 	if (request->is_requested_process) {
@@ -302,6 +302,14 @@ send_command_result_response(int *sock, const struct spp_command_request *reques
 		}
 	}
 
+	/* create & append result array */
+	ret = append_response_command_results_object(top_obj, request, command_results);
+	if (unlikely(ret != 0)) {
+		RTE_LOG(ERR, SPP_COMMAND_PROC, "Failed to make command result response.");
+		json_decref(top_obj);
+		return;
+	}
+
 	/* serialize */
 	msg = json_dumps(top_obj, JSON_INDENT(2));
 	json_decref(top_obj);
-- 
1.9.1

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

* [spp] [PATCH 31/57] spp_vf: use prediction keywords
  2017-12-26  1:54 ` Yasufumi Ogawa
                     ` (29 preceding siblings ...)
  2017-12-28  4:55   ` [spp] [PATCH 30/57] spp_vf: change order of command result in json object x-fn-spp
@ 2017-12-28  4:55   ` x-fn-spp
  2017-12-28  4:55   ` [spp] [PATCH 32/57] spp_vf: fix wrong comparison x-fn-spp
                     ` (25 subsequent siblings)
  56 siblings, 0 replies; 97+ messages in thread
From: x-fn-spp @ 2017-12-28  4:55 UTC (permalink / raw)
  To: spp

From: Hiroyuki Nakamura <nakamura.hioryuki@po.ntt-tx.co.jp>

* Add branch prediction keyword(likely/unlikely) according to DPDK
  coding style.
* Add and modify logging procedures.

Signed-off-by: Daiki Yamashita <yamashita.daiki.z01@as.ntt-tx.co.jp>
Signed-off-by: Yasufum Ogawa <ogawa.yasufumi@lab.ntt.co.jp>
---
 src/vf/command_conn.c | 17 ++++++++++-------
 src/vf/command_proc.c |  8 +++++++-
 2 files changed, 17 insertions(+), 8 deletions(-)

diff --git a/src/vf/command_conn.c b/src/vf/command_conn.c
index 98a7e27..ae60c4b 100644
--- a/src/vf/command_conn.c
+++ b/src/vf/command_conn.c
@@ -4,6 +4,7 @@
 #include <errno.h>
 #include <arpa/inet.h>
 
+#include <rte_common.h>
 #include <rte_log.h>
 #include <rte_branch_prediction.h>
 
@@ -45,7 +46,7 @@ spp_connect_to_controller(int *sock)
 	/* create socket */
 	RTE_LOG(INFO, SPP_COMMAND_PROC, "Creating socket...\n");
 	*sock = socket(AF_INET, SOCK_STREAM, 0);
-	if (*sock < 0) {
+	if (unlikely(*sock < 0)) {
 		RTE_LOG(ERR, SPP_COMMAND_PROC, 
 				"Cannot create tcp socket. errno=%d\n", errno);
 		return -1;
@@ -60,7 +61,7 @@ spp_connect_to_controller(int *sock)
 	RTE_LOG(INFO, SPP_COMMAND_PROC, "Trying to connect ... socket=%d\n", *sock);
 	ret = connect(*sock, (struct sockaddr *)&controller_addr,
 			sizeof(controller_addr));
-	if (ret < 0) {
+	if (unlikely(ret < 0)) {
 		RTE_LOG(ERR, SPP_COMMAND_PROC,
 				"Cannot connect to controller. errno=%d\n", errno);
 		close(*sock);
@@ -89,11 +90,11 @@ spp_receive_message(int *sock, char **strbuf)
 	size_t rx_buf_sz = MESSAGE_BUFFER_BLOCK_SIZE;
 
 	ret = recv(*sock, rx_buf, rx_buf_sz, 0);
-	if (ret <= 0) {
-		if (ret == 0) {
+	if (unlikely(ret <= 0)) {
+		if (likely(ret == 0)) {
 			RTE_LOG(INFO, SPP_COMMAND_PROC,
 					"Controller has performed an shutdown.");
-		} else if (errno == EAGAIN || errno == EWOULDBLOCK) {
+		} else if (likely(errno == EAGAIN || errno == EWOULDBLOCK)) {
 			/* no receive message */
 			return 0;
 		} else {
@@ -101,7 +102,7 @@ spp_receive_message(int *sock, char **strbuf)
 					"Receive failure. errno=%d\n", errno);
 		}
 
-		RTE_LOG(INFO, SPP_COMMAND_PROC, "Assume Server closed connection\n");
+		RTE_LOG(INFO, SPP_COMMAND_PROC, "Assume Server closed connection.\n");
 		close(*sock);
 		*sock = -1;
 		return -1;
@@ -112,7 +113,9 @@ spp_receive_message(int *sock, char **strbuf)
 
 	new_strbuf = spp_strbuf_append(*strbuf, rx_buf, n_rx);
 	if (unlikely(new_strbuf == NULL)) {
-		return -1;
+		RTE_LOG(ERR, SPP_COMMAND_PROC,
+				"Cannot allocate memory for receive data.\n");
+		rte_exit(-1, "Cannot allocate memory for receive data.\n");
 	}
 
 	*strbuf = new_strbuf;
diff --git a/src/vf/command_proc.c b/src/vf/command_proc.c
index f0a1e79..fafb007 100644
--- a/src/vf/command_proc.c
+++ b/src/vf/command_proc.c
@@ -404,8 +404,14 @@ spp_command_proc_do(void)
 	static size_t rb_cnt = 0;
 	static size_t lb_cnt = 0;
 
-	if (unlikely(msgbuf == NULL))
+	if (unlikely(msgbuf == NULL)) {
 		msgbuf = spp_strbuf_allocate(CMD_REQ_BUF_INIT_SIZE);
+		if (unlikely(msgbuf == NULL)) {
+			RTE_LOG(ERR, SPP_COMMAND_PROC,
+					"Cannot allocate memory for receive data(init).\n");
+			rte_exit(-1, "Cannot allocate memory for receive data(init).\n");
+		}
+	}
 
 	ret = spp_connect_to_controller(&sock);
 	if (unlikely(ret != 0))
-- 
1.9.1

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

* [spp] [PATCH 32/57] spp_vf: fix wrong comparison
  2017-12-26  1:54 ` Yasufumi Ogawa
                     ` (30 preceding siblings ...)
  2017-12-28  4:55   ` [spp] [PATCH 31/57] spp_vf: use prediction keywords x-fn-spp
@ 2017-12-28  4:55   ` x-fn-spp
  2017-12-28  4:55   ` [spp] [PATCH 33/57] spp_vf: update sending error status x-fn-spp
                     ` (24 subsequent siblings)
  56 siblings, 0 replies; 97+ messages in thread
From: x-fn-spp @ 2017-12-28  4:55 UTC (permalink / raw)
  To: spp

From: Hiroyuki Nakamura <nakamura.hioryuki@po.ntt-tx.co.jp>

* Fix variable to be compared.

Signed-off-by: Kentaro Watanabe <watanabe.kentaro.z01@as.ntt-tx.co.jp>
Signed-off-by: Yasufum Ogawa <ogawa.yasufumi@lab.ntt.co.jp>
---
 src/vf/spp_config.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/src/vf/spp_config.c b/src/vf/spp_config.c
index 6d8e380..8c82c13 100644
--- a/src/vf/spp_config.c
+++ b/src/vf/spp_config.c
@@ -59,7 +59,7 @@ spp_config_get_path_obj(const json_t *json, const char *path)
 
 		if (bracket != NULL) {
 			index = strtol(bracket+1, &endptr, 0);
-			if (unlikely(str == endptr) || unlikely(*endptr != ']'))
+			if (unlikely(bracket+1 == endptr) || unlikely(*endptr != ']'))
 				return NULL;
 
 			array_obj = new_obj;
-- 
1.9.1

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

* [spp] [PATCH 33/57] spp_vf: update sending error status
  2017-12-26  1:54 ` Yasufumi Ogawa
                     ` (31 preceding siblings ...)
  2017-12-28  4:55   ` [spp] [PATCH 32/57] spp_vf: fix wrong comparison x-fn-spp
@ 2017-12-28  4:55   ` x-fn-spp
  2017-12-28  4:55   ` [spp] [PATCH 34/57] spp_vf: modify conditional statement x-fn-spp
                     ` (23 subsequent siblings)
  56 siblings, 0 replies; 97+ messages in thread
From: x-fn-spp @ 2017-12-28  4:55 UTC (permalink / raw)
  To: spp

From: Hiroyuki Nakamura <nakamura.hioryuki@po.ntt-tx.co.jp>

Update status code to tell if sending error is temporary or fatal.

Signed-off-by: Daiki Yamashita <yamashita.daiki.z01@as.ntt-tx.co.jp>
Signed-off-by: Yasufum Ogawa <ogawa.yasufumi@lab.ntt.co.jp>
---
 src/vf/command_conn.c | 10 +++++-----
 src/vf/command_conn.h | 23 +++++++++++++++--------
 src/vf/command_proc.c | 14 +++++++++-----
 src/vf/command_proc.h |  9 ++++++---
 src/vf/spp_vf.c       | 11 ++++++++++-
 5 files changed, 45 insertions(+), 22 deletions(-)

diff --git a/src/vf/command_conn.c b/src/vf/command_conn.c
index ae60c4b..f3aa76f 100644
--- a/src/vf/command_conn.c
+++ b/src/vf/command_conn.c
@@ -49,7 +49,7 @@ spp_connect_to_controller(int *sock)
 	if (unlikely(*sock < 0)) {
 		RTE_LOG(ERR, SPP_COMMAND_PROC, 
 				"Cannot create tcp socket. errno=%d\n", errno);
-		return -1;
+		return SPP_CONNERR_TEMPORARY;
 	}
 
 	memset(&controller_addr, 0, sizeof(controller_addr));
@@ -66,7 +66,7 @@ spp_connect_to_controller(int *sock)
 				"Cannot connect to controller. errno=%d\n", errno);
 		close(*sock);
 		*sock = -1;
-		return -1;
+		return SPP_CONNERR_TEMPORARY;
 	}
 
 	RTE_LOG(INFO, SPP_COMMAND_PROC, "Connected\n");
@@ -105,7 +105,7 @@ spp_receive_message(int *sock, char **strbuf)
 		RTE_LOG(INFO, SPP_COMMAND_PROC, "Assume Server closed connection.\n");
 		close(*sock);
 		*sock = -1;
-		return -1;
+		return SPP_CONNERR_TEMPORARY;
 	}
 
 	RTE_LOG(DEBUG, SPP_COMMAND_PROC, "Receive message. count=%d\n", ret);
@@ -115,7 +115,7 @@ spp_receive_message(int *sock, char **strbuf)
 	if (unlikely(new_strbuf == NULL)) {
 		RTE_LOG(ERR, SPP_COMMAND_PROC,
 				"Cannot allocate memory for receive data.\n");
-		rte_exit(-1, "Cannot allocate memory for receive data.\n");
+		return SPP_CONNERR_FATAL;
 	}
 
 	*strbuf = new_strbuf;
@@ -134,7 +134,7 @@ spp_send_message(int *sock, const char* message, size_t message_len)
 		RTE_LOG(ERR, SPP_COMMAND_PROC, "Send failure. ret=%d\n", ret);
 		close(*sock);
 		*sock = -1;
-		return -1;
+		return SPP_CONNERR_TEMPORARY;
 	}
 
 	return 0;
diff --git a/src/vf/command_conn.h b/src/vf/command_conn.h
index 0136d75..932c647 100644
--- a/src/vf/command_conn.h
+++ b/src/vf/command_conn.h
@@ -1,6 +1,11 @@
 #ifndef _COMMAND_CONN_H_
 #define _COMMAND_CONN_H_
 
+/** result code - temporary error. please retry */
+#define SPP_CONNERR_TEMPORARY -1
+/** result code - fatal error occurred. should teminate process. */
+#define SPP_CONNERR_FATAL     -2
+
 /**
  * intialize command connection.
  *
@@ -10,8 +15,8 @@
  * @param controller_port
  *  controller listen port number.
  *
- * @ret_val 0 succeeded.
- * @ret_val -1 failed.
+ * @retval 0                     succeeded.
+ * @retval SPP_CONNERR_TEMPORARY temporary error. please retry.
  */
 int spp_command_conn_init(const char *controller_ip, int controller_port);
 
@@ -23,8 +28,8 @@ int spp_command_conn_init(const char *controller_ip, int controller_port);
  * @param sock
  *  socket that connect to controller.
  *
- * @ret_val 0 succeeded.
- * @ret_val -1 failed.
+ * @retval 0 succeeded.
+ * @retval -1 failed.
  */
 int spp_connect_to_controller(int *sock);
 
@@ -36,8 +41,10 @@ int spp_connect_to_controller(int *sock);
  * @param sock
  *  socket that read data.
  *
- * @ret_val 0 succeeded.
- * @ret_val -1 failed.
+ * @retval 0 <                   succeeded. number of bytes received.
+ * @retval 0                     no receive message.
+ * @retval SPP_CONNERR_TEMPORARY temporary error. please reconnect.
+ * @retval SPP_CONNERR_FATAL     fatal error occurred. should teminate process.
  */
 int spp_receive_message(int *sock, char **msgbuf);
 
@@ -55,8 +62,8 @@ int spp_receive_message(int *sock, char **msgbuf);
  * @param message_len
  *  send data length.
  *
- * @ret_val 0 succeeded.
- * @ret_val -1 failed.
+ * @retval 0                     succeeded.
+ * @retval SPP_CONNERR_TEMPORARY temporary error. please reconnect.
  */
 int spp_send_message(int *sock, const char* message, size_t message_len);
 
diff --git a/src/vf/command_proc.c b/src/vf/command_proc.c
index fafb007..c921b51 100644
--- a/src/vf/command_proc.c
+++ b/src/vf/command_proc.c
@@ -390,7 +390,7 @@ spp_command_proc_init(const char *controller_ip, int controller_port)
 }
 
 /* process command from controller. */
-void
+int
 spp_command_proc_do(void)
 {
 	int ret = -1;
@@ -409,17 +409,19 @@ spp_command_proc_do(void)
 		if (unlikely(msgbuf == NULL)) {
 			RTE_LOG(ERR, SPP_COMMAND_PROC,
 					"Cannot allocate memory for receive data(init).\n");
-			rte_exit(-1, "Cannot allocate memory for receive data(init).\n");
+			return -1;
 		}
 	}
 
 	ret = spp_connect_to_controller(&sock);
 	if (unlikely(ret != 0))
-		return;
+		return 0;
 
 	msg_ret = spp_receive_message(&sock, &msgbuf);
-	if (likely(msg_ret <= 0)) {
-		return;
+	if (unlikely(msg_ret == 0 || msg_ret == SPP_CONNERR_TEMPORARY)) {
+		return 0;
+	} else if (unlikely(msg_ret < 0)) {
+		return -1;
 	}
 
 	for (i = 0; i < msg_ret; ++i) {
@@ -445,4 +447,6 @@ spp_command_proc_do(void)
 	}
 
 	msg_len = msg_len + msg_ret;
+
+	return 0;
 }
diff --git a/src/vf/command_proc.h b/src/vf/command_proc.h
index 8774070..37e55ad 100644
--- a/src/vf/command_proc.h
+++ b/src/vf/command_proc.h
@@ -10,16 +10,19 @@
  * @param controller_port
  *  controller listen port number.
  *
- * @ret_val 0 succeeded.
- * @ret_val -1 failed.
+ * @retval 0  succeeded.
+ * @retval -1 failed.
  */
 int
 spp_command_proc_init(const char *controller_ip, int controller_port);
 
 /**
  * process command from controller.
+ *
+ * @retval 0  succeeded.
+ * @retval -1 failed.
  */
-void
+int
 spp_command_proc_do(void);
 
 #endif /* _COMMAND_PROC_H_ */
diff --git a/src/vf/spp_vf.c b/src/vf/spp_vf.c
index 7bb1ac0..bd97818 100644
--- a/src/vf/spp_vf.c
+++ b/src/vf/spp_vf.c
@@ -954,13 +954,17 @@ ut_main(int argc, char *argv[])
 		RTE_LOG(INFO, APP, "[Press Ctrl-C to quit ...]\n");
 
 		/* loop */
+		int ret_do = 0;
 #ifndef USE_UT_SPP_VF
 		while(likely(g_core_info[main_lcore_id].status != SPP_CORE_STOP_REQUEST)) {
 #else
 		{
 #endif
 			/* コマンド受付 */
-			spp_command_proc_do();
+			ret_do = spp_command_proc_do();
+			if (unlikely(ret_do != 0)) {
+				break;
+			}
 
 			/* CPUを占有しない様に1秒スリープ */
 			sleep(1);
@@ -970,6 +974,11 @@ ut_main(int argc, char *argv[])
 #endif /* SPP_RINGLATENCYSTATS_ENABLE */
 		}
 
+		/* エラー終了 */
+		if (unlikely(ret_do != 0)) {
+			break;
+		}
+
 		/* 正常終了 */
 		ret = 0;
 		break;
-- 
1.9.1

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

* [spp] [PATCH 34/57] spp_vf: modify conditional statement
  2017-12-26  1:54 ` Yasufumi Ogawa
                     ` (32 preceding siblings ...)
  2017-12-28  4:55   ` [spp] [PATCH 33/57] spp_vf: update sending error status x-fn-spp
@ 2017-12-28  4:55   ` x-fn-spp
  2017-12-28  4:55   ` [spp] [PATCH 35/57] spp_vf: add proc on receiving l2 multicast x-fn-spp
                     ` (22 subsequent siblings)
  56 siblings, 0 replies; 97+ messages in thread
From: x-fn-spp @ 2017-12-28  4:55 UTC (permalink / raw)
  To: spp

From: Hiroyuki Nakamura <nakamura.hioryuki@po.ntt-tx.co.jp>

Modify followings:
* Comments on function's return value.
* Conditional statement for the actions corresponding to return values
  of spp_receive_message.

Signed-off-by: Daiki Yamashita <yamashita.daiki.z01@as.ntt-tx.co.jp>
Signed-off-by: Yasufum Ogawa <ogawa.yasufumi@lab.ntt.co.jp>
---
 src/vf/command_conn.h |  8 ++++----
 src/vf/command_proc.c | 11 +++++++----
 2 files changed, 11 insertions(+), 8 deletions(-)

diff --git a/src/vf/command_conn.h b/src/vf/command_conn.h
index 932c647..d414ec6 100644
--- a/src/vf/command_conn.h
+++ b/src/vf/command_conn.h
@@ -15,8 +15,8 @@
  * @param controller_port
  *  controller listen port number.
  *
- * @retval 0                     succeeded.
- * @retval SPP_CONNERR_TEMPORARY temporary error. please retry.
+ * @retval 0  succeeded.
+ * @retval -1 failed.
  */
 int spp_command_conn_init(const char *controller_ip, int controller_port);
 
@@ -28,8 +28,8 @@ int spp_command_conn_init(const char *controller_ip, int controller_port);
  * @param sock
  *  socket that connect to controller.
  *
- * @retval 0 succeeded.
- * @retval -1 failed.
+ * @retval 0                     succeeded.
+ * @retval SPP_CONNERR_TEMPORARY temporary error. please retry.
  */
 int spp_connect_to_controller(int *sock);
 
diff --git a/src/vf/command_proc.c b/src/vf/command_proc.c
index c921b51..50418cc 100644
--- a/src/vf/command_proc.c
+++ b/src/vf/command_proc.c
@@ -418,10 +418,13 @@ spp_command_proc_do(void)
 		return 0;
 
 	msg_ret = spp_receive_message(&sock, &msgbuf);
-	if (unlikely(msg_ret == 0 || msg_ret == SPP_CONNERR_TEMPORARY)) {
-		return 0;
-	} else if (unlikely(msg_ret < 0)) {
-		return -1;
+	if (unlikely(msg_ret <= 0)) {
+		if (likely(msg_ret == 0))
+			return 0;
+		else if (unlikely(msg_ret == SPP_CONNERR_TEMPORARY))
+			return 0;
+		else
+			return -1;
 	}
 
 	for (i = 0; i < msg_ret; ++i) {
-- 
1.9.1

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

* [spp] [PATCH 35/57] spp_vf: add proc on receiving l2 multicast
  2017-12-26  1:54 ` Yasufumi Ogawa
                     ` (33 preceding siblings ...)
  2017-12-28  4:55   ` [spp] [PATCH 34/57] spp_vf: modify conditional statement x-fn-spp
@ 2017-12-28  4:55   ` x-fn-spp
  2017-12-28  4:55   ` [spp] [PATCH 36/57] spp_vf: extend limit on number of usable cores x-fn-spp
                     ` (21 subsequent siblings)
  56 siblings, 0 replies; 97+ messages in thread
From: x-fn-spp @ 2017-12-28  4:55 UTC (permalink / raw)
  To: spp

From: Hiroyuki Nakamura <nakamura.hioryuki@po.ntt-tx.co.jp>

Add two functions for L2 multicast packets
* Transmit them to multiple ports.
* Transmit them to default port when there is no classification.

Add followings to transmit packets to multiple ports:
* Make a list of ports corresponding to MAC addresses.
* Transmit packets of multicast address(I/G bit is 1) to all the ports
  listed.

Add followings to transmit packets to default port:
* Set default port via command.
* Use default port when there is no classification.

Signed-off-by: Daiki Yamashita <yamashita.daiki.z01@as.ntt-tx.co.jp>
Signed-off-by: Yasufum Ogawa <ogawa.yasufumi@lab.ntt.co.jp>
---
 src/vf/classifier_mac.c | 119 ++++++++++++++++++++++++++++++++++++++----------
 src/vf/command_dec.c    |   4 ++
 src/vf/spp_config.c     |   6 +++
 src/vf/spp_config.h     |   4 ++
 4 files changed, 108 insertions(+), 25 deletions(-)

diff --git a/src/vf/classifier_mac.c b/src/vf/classifier_mac.c
index cc4af2b..e69347f 100644
--- a/src/vf/classifier_mac.c
+++ b/src/vf/classifier_mac.c
@@ -64,6 +64,9 @@ static const size_t ETHER_ADDR_STR_BUF_SZ =
 /* classifier information */
 struct classifier_mac_info {
 	struct rte_hash *classifier_table;
+	int num_active_classified;
+	int active_classifieds[RTE_MAX_ETHPORTS];
+	int default_classified;
 };
 
 /* classifier management information */
@@ -91,27 +94,46 @@ static struct classifier_mac_mng_info g_classifier_mng_info[RTE_MAX_LCORE];
 		but since we want to start at 0. */
 static rte_atomic16_t g_hash_table_count = RTE_ATOMIC16_INIT(0xff);
 
-/* initialize classifier table. */
+/* initialize classifier information. */
 static int
-init_classifier_table(struct rte_hash **classifier_table,
+init_classifier_info(struct classifier_mac_info *classifier_info,
 		const struct spp_core_info *core_info)
 {
 	int ret = -1;
 	int i;
+	struct rte_hash **classifier_table = &classifier_info->classifier_table;
 	struct ether_addr eth_addr;
 	char mac_addr_str[ETHER_ADDR_STR_BUF_SZ];
 
 	rte_hash_reset(*classifier_table);
+	classifier_info->num_active_classified = 0;
+	classifier_info->default_classified = -1;
 
 	for (i = 0; i < core_info->num_tx_port; i++) {
 		if (core_info->tx_ports[i].mac_addr == 0) {
 			continue;
 		}
 
+		/* store active tx_port that associate with mac address */
+		classifier_info->active_classifieds[classifier_info->
+				num_active_classified++] = i;
+
+		/* store default classified */
+		if (unlikely(core_info->tx_ports[i].mac_addr ==
+				SPP_CONFIG_DEFAULT_CLASSIFIED_DMY_ADDR)) {
+			classifier_info->default_classified = i;
+			RTE_LOG(INFO, SPP_CLASSIFIER_MAC, "default classified. "
+					"if_type=%d, if_no=%d, dpdk_port=%d\n",
+					core_info->tx_ports[i].if_type,
+					core_info->tx_ports[i].if_no,
+					core_info->tx_ports[i].dpdk_port);
+			continue;
+		}
+
+		/* add entry to classifier mac table */
 		rte_memcpy(&eth_addr, &core_info->tx_ports[i].mac_addr, ETHER_ADDR_LEN);
 		ether_format_addr(mac_addr_str, sizeof(mac_addr_str), &eth_addr);
 
-		/* add entry to classifier mac table */
 		ret = rte_hash_add_key_data(*classifier_table,
 				(void*)&eth_addr, (void*)(long)i);
 		if (unlikely(ret < 0)) {
@@ -186,11 +208,9 @@ init_classifier(const struct spp_core_info *core_info,
 		}
 	}
 
-	/* populate the hash at reference table */
-	classifier_mac_table = &classifier_mng_info->info[classifier_mng_info->ref_index].
-			classifier_table;
-
-	ret = init_classifier_table(classifier_mac_table, core_info);
+	/* populate the classifier information at reference */
+	ret = init_classifier_info(&classifier_mng_info->
+			info[classifier_mng_info->ref_index], core_info);
 	if (unlikely(ret != 0)) {
 		RTE_LOG(ERR, SPP_CLASSIFIER_MAC,
 				"Cannot initialize classifer mac table. ret=%d\n", ret);
@@ -252,6 +272,42 @@ transmit_packet(struct classified_data *classified_data)
 	classified_data->num_pkt = 0;
 }
 
+/* set mbuf pointer to tx buffer
+	and transmit packet, if buffer is filled */
+static inline void
+push_packet(struct rte_mbuf *pkt, struct classified_data *classified_data)
+{
+	classified_data->pkts[classified_data->num_pkt++] = pkt;
+
+	/* transmit packet, if buffer is filled */
+	if (unlikely(classified_data->num_pkt == MAX_PKT_BURST)) {
+		RTE_LOG(DEBUG, SPP_CLASSIFIER_MAC,
+				"transimit packets (buffer is filled). "
+				"if_type=%d, if_no=%d, tx_port=%hhd, num_pkt=%hu\n",
+				classified_data->if_type,
+				classified_data->if_no,
+				classified_data->tx_port,
+				classified_data->num_pkt);
+		transmit_packet(classified_data);
+	}
+}
+
+/* handle L2 multicast(include broadcast) packet */
+static inline void
+handle_l2multicast_packet(struct rte_mbuf *pkt,
+		struct classifier_mac_info *classifier_info,
+		struct classified_data *classified_data)
+{
+	int i;
+
+	rte_mbuf_refcnt_update(pkt, classifier_info->num_active_classified);
+
+	for (i= 0; i < classifier_info->num_active_classified; i++) {
+		push_packet(pkt, classified_data + 
+				(long)classifier_info->active_classifieds[i]);
+	}
+}
+
 /* classify packet by destination mac address,
 		and transmit packet (conditional). */
 static inline void
@@ -262,7 +318,6 @@ classify_packet(struct rte_mbuf **rx_pkts, uint16_t n_rx,
 	int ret;
 	int i;
 	struct ether_hdr *eth;
-	struct classified_data *cd;
 	void *lookup_data;
 	char mac_addr_str[ETHER_ADDR_STR_BUF_SZ];
 
@@ -272,27 +327,41 @@ classify_packet(struct rte_mbuf **rx_pkts, uint16_t n_rx,
 		/* find in table (by destination mac address)*/
 		ret = rte_hash_lookup_data(classifier_info->classifier_table,
 				(const void*)&eth->d_addr, &lookup_data);
-		if (unlikely(ret < 0)) {
-			ether_format_addr(mac_addr_str, sizeof(mac_addr_str), &eth->d_addr);
-			RTE_LOG(ERR, SPP_CLASSIFIER_MAC,
-					"unknown mac address. ret=%d, mac_addr=%s\n", ret, mac_addr_str);
-			rte_pktmbuf_free(rx_pkts[i]);
-			continue;
-		}
+		if (ret < 0) {
+			/* L2 multicast(include broadcast) ? */
+			if (unlikely(is_multicast_ether_addr(&eth->d_addr))) {
+				RTE_LOG(DEBUG, SPP_CLASSIFIER_MAC,
+						"multicast mac address.\n");
+				handle_l2multicast_packet(rx_pkts[i],
+						classifier_info, classified_data);
+				continue;
+			}
 
-		/* set mbuf pointer to tx buffer */
-		cd = classified_data + (long)lookup_data;
-		cd->pkts[cd->num_pkt++] = rx_pkts[i];
+			/* if no default, drop packet */
+			if (unlikely(classifier_info->default_classified == -1)) {
+				ether_format_addr(mac_addr_str,
+						sizeof(mac_addr_str), &eth->d_addr);
+				RTE_LOG(ERR, SPP_CLASSIFIER_MAC,
+						"unknown mac address. "
+						"ret=%d, mac_addr=%s\n",
+						ret, mac_addr_str);
+				rte_pktmbuf_free(rx_pkts[i]);
+				continue;
+			}
 
-		/* transmit packet, if buffer is filled */
-		if (unlikely(cd->num_pkt == MAX_PKT_BURST)) {
+			/* to default classifed */
 			RTE_LOG(DEBUG, SPP_CLASSIFIER_MAC,
-                        		"transimit packets (buffer is filled). index=%ld, num_pkt=%hu\n", (long)lookup_data, cd->num_pkt);
-			transmit_packet(cd);
+					"to default classified.\n");
+			lookup_data = (void *)(long)classifier_info->default_classified;
 		}
+
+		/* set mbuf pointer to tx buffer
+			and transmit packet, if buffer is filled */
+		push_packet(rx_pkts[i], classified_data + (long)lookup_data);
 	}
 }
 
+/* change update index at classifier management information */
 static inline void
 change_update_index(struct classifier_mac_mng_info *classifier_mng_info, unsigned int lcore_id)
 {
@@ -322,8 +391,8 @@ spp_classifier_mac_update(struct spp_core_info *core_info)
 	RTE_LOG(INFO, SPP_CLASSIFIER_MAC,
 			"Core[%u] Start update component.\n", lcore_id);
 
-	/* initialize update side classifier table */
-	ret = init_classifier_table(&classifier_info->classifier_table, core_info);
+	/* initialize update side classifier information */
+	ret = init_classifier_info(classifier_info, core_info);
 	if (unlikely(ret != 0)) {
 		RTE_LOG(ERR, SPP_CLASSIFIER_MAC,
 				"Cannot update classifer mac. ret=%d\n", ret);
diff --git a/src/vf/command_dec.c b/src/vf/command_dec.c
index d3ff27a..3295618 100644
--- a/src/vf/command_dec.c
+++ b/src/vf/command_dec.c
@@ -158,6 +158,10 @@ decode_mac_addr_str_value(void *output, const json_t *value_obj,
 	int ret = -1;
 	const char* str_val = json_string_value(value_obj);
 
+	/* if default specification, convert to internal dummy address */
+	if (unlikely(strcmp(str_val, SPP_CONFIG_DEFAULT_CLASSIFIED_SPEC_STR) == 0))
+		str_val = SPP_CONFIG_DEFAULT_CLASSIFIED_DMY_ADDR_STR;
+
 	ret = spp_config_change_mac_str_to_int64(str_val);
 	if (unlikely(ret == -1)) {
 		RTE_LOG(ERR, SPP_COMMAND_PROC, "Bad mac address string. val=%s\n",
diff --git a/src/vf/spp_config.c b/src/vf/spp_config.c
index 8c82c13..663a609 100644
--- a/src/vf/spp_config.c
+++ b/src/vf/spp_config.c
@@ -319,6 +319,12 @@ config_load_classifier_table(const json_t *obj,
 			return -1;
 		}
 
+		/* デフォルト転送先指定であれば内部流通用ダミーアドレスに変換 */
+		if (unlikely(strcmp(tmp_table->mac_addr_str,
+				SPP_CONFIG_DEFAULT_CLASSIFIED_SPEC_STR) == 0))
+			strcpy(tmp_table->mac_addr_str,
+					SPP_CONFIG_DEFAULT_CLASSIFIED_DMY_ADDR_STR);
+
 		/* MACアドレス数値変換 */
 		int64_t ret_mac64 = spp_config_change_mac_str_to_int64(
 				tmp_table->mac_addr_str);
diff --git a/src/vf/spp_config.h b/src/vf/spp_config.h
index 7945807..ac2bc55 100644
--- a/src/vf/spp_config.h
+++ b/src/vf/spp_config.h
@@ -15,6 +15,10 @@
 #define SPP_CONFIG_CORE_MAX 64
 #define SPP_CONFIG_PATH_LEN 1024
 
+#define SPP_CONFIG_DEFAULT_CLASSIFIED_SPEC_STR     "default"
+#define SPP_CONFIG_DEFAULT_CLASSIFIED_DMY_ADDR_STR "00:00:00:00:00:01"
+#define SPP_CONFIG_DEFAULT_CLASSIFIED_DMY_ADDR     0x010000000000
+
 /*
  * Process type for each CORE
  */
-- 
1.9.1

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

* [spp] [PATCH 36/57] spp_vf: extend limit on number of usable cores
  2017-12-26  1:54 ` Yasufumi Ogawa
                     ` (34 preceding siblings ...)
  2017-12-28  4:55   ` [spp] [PATCH 35/57] spp_vf: add proc on receiving l2 multicast x-fn-spp
@ 2017-12-28  4:55   ` x-fn-spp
  2017-12-28  4:55   ` [spp] [PATCH 37/57] spp_vf: add restart procedure for vhost client x-fn-spp
                     ` (20 subsequent siblings)
  56 siblings, 0 replies; 97+ messages in thread
From: x-fn-spp @ 2017-12-28  4:55 UTC (permalink / raw)
  To: spp

From: Hiroyuki Nakamura <nakamura.hioryuki@po.ntt-tx.co.jp>

Extend the limit on the number of usable cores to 128.
Remove unnecessary check procedure.

Signed-off-by: Kentaro Watanabe <watanabe.kentaro.z01@as.ntt-tx.co.jp>
Signed-off-by: Yasufum Ogawa <ogawa.yasufumi@lab.ntt.co.jp>
---
 src/vf/spp_config.h |  2 +-
 src/vf/spp_vf.c     | 84 +++++------------------------------------------------
 2 files changed, 8 insertions(+), 78 deletions(-)

diff --git a/src/vf/spp_config.h b/src/vf/spp_config.h
index ac2bc55..69f6a3f 100644
--- a/src/vf/spp_config.h
+++ b/src/vf/spp_config.h
@@ -12,7 +12,7 @@
 
 #define SPP_CONFIG_STR_LEN 32
 #define SPP_CONFIG_MAC_TABLE_MAX 16
-#define SPP_CONFIG_CORE_MAX 64
+#define SPP_CONFIG_CORE_MAX 128
 #define SPP_CONFIG_PATH_LEN 1024
 
 #define SPP_CONFIG_DEFAULT_CLASSIFIED_SPEC_STR     "default"
diff --git a/src/vf/spp_vf.c b/src/vf/spp_vf.c
index 418520f..6947bf0 100644
--- a/src/vf/spp_vf.c
+++ b/src/vf/spp_vf.c
@@ -245,66 +245,6 @@ stop_process(int signal) {
 }
 
 /*
- * 起動パラメータのCPUのbitmapを数値へ変換
- */
-static int
-parse_cpu_bit(uint64_t *cpu, const char *cpu_bit)
-{
-	char *endptr = NULL;
-	uint64_t temp;
-
-	temp = strtoull(cpu_bit, &endptr, 0);
-	if (unlikely(endptr == cpu_bit) || unlikely(*endptr != '\0')) {
-		return -1;
-	}
-
-	*cpu = temp;
-	RTE_LOG(DEBUG, APP, "cpu = %lu", *cpu);
-	return 0;
-}
-
-/*
- * Parse the dpdk arguments for use in client app.
- */
-static int
-parse_dpdk_args(int argc, char *argv[])
-{
-	int cnt;
-	int option_index, opt;
-	const int argcopt = argc;
-	char *argvopt[argcopt];
-	const char *progname = argv[0];
-	static struct option lgopts[] = { {0} };
-
-	/* getoptを使用するとargvが並び変わるみたいなので、コピーを実施 */
-	for (cnt = 0; cnt < argcopt; cnt++) {
-		argvopt[cnt] = argv[cnt];
-	}
-
-	/* Check DPDK parameter */
-	optind = 0;
-	opterr = 0;
-	while ((opt = getopt_long(argc, argvopt, "c:", lgopts,
-			&option_index)) != EOF) {
-		switch (opt) {
-		case 'c':
-			/* CPU */
-			if (parse_cpu_bit(&g_startup_param.cpu, optarg) != 0) {
-				usage(progname);
-				return -1;
-			}
-			break;
-		default:
-			/* CPU */
-			/* DPDKのパラメータは他にもあるので、エラーとはしない */
-			break;
-		}
-	}
-
-	return 0;
-}
-
-/*
  * Parses the process ID of the application argument.
  */
 static int
@@ -493,7 +433,6 @@ set_form_proc_info(struct spp_config_area *config)
 	int core_cnt, rx_start, rx_cnt, tx_start, tx_cnt;
 	enum port_type if_type;
 	int if_no;
-	uint64_t cpu_bit = 0;
 	struct spp_config_functions *core_func = NULL;
 	struct spp_core_info *core_info = NULL;
 	struct patch_info *patch_info = NULL;
@@ -517,7 +456,12 @@ set_form_proc_info(struct spp_config_area *config)
 
 		/* Set CORE type */
 		core_info->type = core_func->type;
-		cpu_bit |= 1 << core_func->core_no;
+		if (!rte_lcore_is_enabled(core_func->core_no)) {
+			/* CPU mismatch */
+			RTE_LOG(ERR, APP, "CPU mismatch (cpu = %u)\n",
+					core_func->core_no);
+			return -1;
+		}
 
 		/* Set RX port */
 		rx_start = core_info->num_rx_port;
@@ -570,14 +514,6 @@ set_form_proc_info(struct spp_config_area *config)
 		}
 	}
 
-#if 0 /* bugfix#385 */
-	if (unlikely((cpu_bit & g_startup_param.cpu) != cpu_bit)) {
-		/* CPU mismatch */
-		RTE_LOG(ERR, APP, "CPU mismatch (cpu param = %lx, config = %lx)\n",
-				g_startup_param.cpu, cpu_bit);
-		return -1;
-	}
-#endif
 	return 0;
 }
 
@@ -883,12 +819,6 @@ ut_main(int argc, char *argv[])
 
 	unsigned int main_lcore_id = 0xffffffff;
 	while(1) {
-		/* Parse dpdk parameters */
-		int ret_parse = parse_dpdk_args(argc, argv);
-		if (unlikely(ret_parse != 0)) {
-			break;
-		}
-
 		/* DPDK initialize */
 		int ret_dpdk = rte_eal_init(argc, argv);
 		if (unlikely(ret_dpdk < 0)) {
@@ -903,7 +833,7 @@ ut_main(int argc, char *argv[])
 		rte_log_set_global_level(RTE_LOG_LEVEL);
 
 		/* Parse application parameters */
-		ret_parse = parse_app_args(argc, argv);
+		int ret_parse = parse_app_args(argc, argv);
 		if (unlikely(ret_parse != 0)) {
 			break;
 		}
-- 
1.9.1

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

* [spp] [PATCH 37/57] spp_vf: add restart procedure for vhost client
  2017-12-26  1:54 ` Yasufumi Ogawa
                     ` (35 preceding siblings ...)
  2017-12-28  4:55   ` [spp] [PATCH 36/57] spp_vf: extend limit on number of usable cores x-fn-spp
@ 2017-12-28  4:55   ` x-fn-spp
  2017-12-28  4:55   ` [spp] [PATCH 38/57] spp_vf: fix classifier mbuf handling x-fn-spp
                     ` (19 subsequent siblings)
  56 siblings, 0 replies; 97+ messages in thread
From: x-fn-spp @ 2017-12-28  4:55 UTC (permalink / raw)
  To: spp

From: Hiroyuki Nakamura <nakamura.hioryuki@po.ntt-tx.co.jp>

Add procedure for restarting vhost-user client

Signed-off-by: Kentaro Watanabe <watanabe.kentaro.z01@as.ntt-tx.co.jp>
Signed-off-by: Yasufum Ogawa <ogawa.yasufumi@lab.ntt.co.jp>
---
 src/vf/spp_vf.c | 36 ++++++++++++++++++++++++++++--------
 1 file changed, 28 insertions(+), 8 deletions(-)

diff --git a/src/vf/spp_vf.c b/src/vf/spp_vf.c
index 6947bf0..23c1bd9 100644
--- a/src/vf/spp_vf.c
+++ b/src/vf/spp_vf.c
@@ -23,15 +23,16 @@ enum SPP_LONGOPT_RETVAL {
 	/* add below */
 
 	SPP_LONGOPT_RETVAL_CONFIG,
-	SPP_LONGOPT_RETVAL_PROCESS_ID
+	SPP_LONGOPT_RETVAL_PROCESS_ID,
+	SPP_LONGOPT_RETVAL_VHOST_CLIENT
 };
 
 /* struct */
 struct startup_param {
-	uint64_t cpu;
 	int process_id;
 	char server_ip[INET_ADDRSTRLEN];
 	int server_port;
+	int vhost_client;
 };
 
 struct patch_info {
@@ -68,10 +69,15 @@ static char config_file_path[PATH_MAX];
 static void
 usage(const char *progname)
 {
-	RTE_LOG(INFO, APP, "Usage: %s [EAL args] -- --process-id PROC_ID [--config CONFIG_FILE_PATH] -s SERVER_IP:SERVER_PORT\n"
+	RTE_LOG(INFO, APP, "Usage: %s [EAL args] --"
+			" --process-id PROC_ID"
+			" [--config CONFIG_FILE_PATH]"
+			" -s SERVER_IP:SERVER_PORT"
+			" [--vhost-client]\n"
 			" --process-id PROCESS_ID   : My process ID\n"
 			" --config CONFIG_FILE_PATH : specific config file path\n"
 			" -s SERVER_IP:SERVER_PORT  : Access information to the server\n"
+			" --vhost-client            : Run vhost on client\n"
 			, progname);
 }
 
@@ -103,7 +109,7 @@ add_ring_pmd(int ring_id)
  * Set VHOST PMD
  */
 static int
-add_vhost_pmd(int index)
+add_vhost_pmd(int index, int client)
 {
 	struct rte_eth_conf port_conf = {
 		.rxmode = { .max_rx_pkt_len = ETHER_MAX_LEN }
@@ -129,7 +135,8 @@ add_vhost_pmd(int index)
 	name = get_vhost_backend_name(index);
 	iface = get_vhost_iface_name(index);
 
-	sprintf(devargs, "%s,iface=%s,queues=%d", name, iface, nr_queues);
+	sprintf(devargs, "%s,iface=%s,queues=%d,client=%d",
+			name, iface, nr_queues, client);
 	ret = rte_eth_dev_attach(devargs, &vhost_port_id);
 	if (unlikely(ret < 0)) {
 		RTE_LOG(ERR, APP, "rte_eth_dev_attach error. (ret = %d)\n", ret);
@@ -308,6 +315,7 @@ parse_app_args(int argc, char *argv[])
 	static struct option lgopts[] = { 
 			{ "config", required_argument, NULL, SPP_LONGOPT_RETVAL_CONFIG },
 			{ "process-id", required_argument, NULL, SPP_LONGOPT_RETVAL_PROCESS_ID },
+			{ "vhost-client", no_argument, NULL, SPP_LONGOPT_RETVAL_VHOST_CLIENT },
 			{ 0 },
 	};
 
@@ -316,6 +324,9 @@ parse_app_args(int argc, char *argv[])
 		argvopt[cnt] = argv[cnt];
 	}
 
+	/* Clear startup parameters */
+	memset(&g_startup_param, 0x00, sizeof(g_startup_param));
+
 	/* Check application parameter */
 	optind = 0;
 	opterr = 0;
@@ -336,6 +347,9 @@ parse_app_args(int argc, char *argv[])
 			}
 			proc_flg = 1;
 			break;
+		case SPP_LONGOPT_RETVAL_VHOST_CLIENT:
+			g_startup_param.vhost_client = 1;
+			break;
 		case 's':
 			if (parse_app_server(optarg, g_startup_param.server_ip,
 					&g_startup_param.server_port) != 0) {
@@ -356,11 +370,12 @@ parse_app_args(int argc, char *argv[])
 		usage(progname);
 		return -1;
 	}
-	RTE_LOG(INFO, APP, "application arguments value. (process id = %d, config = %s, server = %s:%d)\n",
+	RTE_LOG(INFO, APP, "application arguments value. (process id = %d, config = %s, server = %s:%d, vhost client = %d)\n",
 			g_startup_param.process_id,
 			config_file_path,
 			g_startup_param.server_ip,
-			g_startup_param.server_port);
+			g_startup_param.server_port,
+			g_startup_param.vhost_client);
 	return 0;
 }
 
@@ -619,7 +634,7 @@ set_vhost_interface(struct spp_config_area *config)
 		}
 
 		/* Set DPDK port */
-		int dpdk_port = add_vhost_pmd(vhost_cnt);
+		int dpdk_port = add_vhost_pmd(vhost_cnt, g_startup_param.vhost_client);
 		if (unlikely(dpdk_port < 0)) {
 			RTE_LOG(ERR, APP, "VHOST add failed. (no = %d)\n",
 					vhost_cnt);
@@ -779,6 +794,11 @@ static void
 del_vhost_sockfile(struct patch_info *vhost_patchs)
 {
 	int cnt;
+
+	/* Do not delete for vhost client. */
+	if (g_startup_param.vhost_client != 0)
+		return;
+
 	for (cnt = 0; cnt < RTE_MAX_ETHPORTS; cnt++) {
 		if (likely(vhost_patchs[cnt].use_flg == 0)) {
 			/* VHOST未使用はスキップ */
-- 
1.9.1

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

* [spp] [PATCH 38/57] spp_vf: fix classifier mbuf handling
  2017-12-26  1:54 ` Yasufumi Ogawa
                     ` (36 preceding siblings ...)
  2017-12-28  4:55   ` [spp] [PATCH 37/57] spp_vf: add restart procedure for vhost client x-fn-spp
@ 2017-12-28  4:55   ` x-fn-spp
  2017-12-28  4:55   ` [spp] [PATCH 39/57] spp_vf: add status command x-fn-spp
                     ` (18 subsequent siblings)
  56 siblings, 0 replies; 97+ messages in thread
From: x-fn-spp @ 2017-12-28  4:55 UTC (permalink / raw)
  To: spp

From: Hiroyuki Nakamura <nakamura.hioryuki@po.ntt-tx.co.jp>

Fix mbuf handling on receiving L2 multicast packet
when no destination port is set.

Signed-off-by: Kentaro Watanabe <watanabe.kentaro.z01@as.ntt-tx.co.jp>
Signed-off-by: Yasufum Ogawa <ogawa.yasufumi@lab.ntt.co.jp>
---
 src/vf/classifier_mac.c | 6 ++++++
 1 file changed, 6 insertions(+)

diff --git a/src/vf/classifier_mac.c b/src/vf/classifier_mac.c
index e69347f..64e9883 100644
--- a/src/vf/classifier_mac.c
+++ b/src/vf/classifier_mac.c
@@ -300,6 +300,12 @@ handle_l2multicast_packet(struct rte_mbuf *pkt,
 {
 	int i;
 
+	if (unlikely(classifier_info->num_active_classified == 0)) {
+		RTE_LOG(ERR, SPP_CLASSIFIER_MAC, "No mac address.\n");
+		rte_pktmbuf_free(pkt);
+		return;
+	}
+
 	rte_mbuf_refcnt_update(pkt, classifier_info->num_active_classified);
 
 	for (i= 0; i < classifier_info->num_active_classified; i++) {
-- 
1.9.1

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

* [spp] [PATCH 39/57] spp_vf: add status command
  2017-12-26  1:54 ` Yasufumi Ogawa
                     ` (37 preceding siblings ...)
  2017-12-28  4:55   ` [spp] [PATCH 38/57] spp_vf: fix classifier mbuf handling x-fn-spp
@ 2017-12-28  4:55   ` x-fn-spp
  2017-12-28  4:55   ` [spp] [PATCH 40/57] spp_vf: add output source information in error log x-fn-spp
                     ` (17 subsequent siblings)
  56 siblings, 0 replies; 97+ messages in thread
From: x-fn-spp @ 2017-12-28  4:55 UTC (permalink / raw)
  To: spp

From: Hiroyuki Nakamura <nakamura.hioryuki@po.ntt-tx.co.jp>

* classifier_mac.c: Add new data and associated operations.
* classifier_mac.c: Add new API to get classifier status information.
* command_dec.c: Add command type for new decoding rule.
* command_proc.c: Add status for preparing command response.

Signed-off-by: Daiki Yamashita <yamashita.daiki.z01@as.ntt-tx.co.jp>
Signed-off-by: Yasufum Ogawa <ogawa.yasufumi@lab.ntt.co.jp>
---
 src/vf/classifier_mac.c | 100 ++++++++++++++++++++++++++++++++++------
 src/vf/classifier_mac.h |  12 +++++
 src/vf/command_dec.c    |   4 ++
 src/vf/command_dec.h    |   2 +
 src/vf/command_proc.c   | 118 +++++++++++++++++++++++++++++++++++++-----------
 src/vf/spp_config.c     |  26 +++++++++++
 src/vf/spp_config.h     |   8 ++++
 src/vf/spp_vf.c         |  22 +++++++++
 src/vf/spp_vf.h         |  18 ++++++++
 9 files changed, 268 insertions(+), 42 deletions(-)

diff --git a/src/vf/classifier_mac.c b/src/vf/classifier_mac.c
index e69347f..81a20ac 100644
--- a/src/vf/classifier_mac.c
+++ b/src/vf/classifier_mac.c
@@ -61,6 +61,16 @@ static const size_t HASH_TABLE_NAME_BUF_SZ =
 static const size_t ETHER_ADDR_STR_BUF_SZ =
 		ETHER_ADDR_LEN * 2 + (ETHER_ADDR_LEN - 1) + 1;
 
+/* classified data (destination port, target packets, etc) */
+struct classified_data {
+	enum port_type  if_type;
+	int             if_no;
+	int             if_no_global;
+	uint8_t         tx_port;
+	uint16_t        num_pkt;
+	struct rte_mbuf *pkts[MAX_PKT_BURST];
+};
+
 /* classifier information */
 struct classifier_mac_info {
 	struct rte_hash *classifier_table;
@@ -74,15 +84,7 @@ struct classifier_mac_mng_info {
 	struct classifier_mac_info info[NUM_CLASSIFIER_MAC_INFO];
 	volatile int ref_index;
 	volatile int upd_index;
-};
-
-/* classified data (destination port, target packets, etc) */
-struct classified_data {
-	enum port_type  if_type;
-	int             if_no;
-	uint8_t         tx_port;
-	uint16_t        num_pkt;
-	struct rte_mbuf *pkts[MAX_PKT_BURST];
+	struct classified_data classified_data[RTE_MAX_ETHPORTS];
 };
 
 /* classifier information per lcore */
@@ -94,6 +96,12 @@ static struct classifier_mac_mng_info g_classifier_mng_info[RTE_MAX_LCORE];
 		but since we want to start at 0. */
 static rte_atomic16_t g_hash_table_count = RTE_ATOMIC16_INIT(0xff);
 
+static inline int
+is_used_mng_info(const struct classifier_mac_mng_info *mng_info)
+{
+	return (mng_info != NULL && mng_info->info[0].classifier_table != NULL);
+}
+
 /* initialize classifier information. */
 static int
 init_classifier_info(struct classifier_mac_info *classifier_info,
@@ -219,10 +227,11 @@ init_classifier(const struct spp_core_info *core_info,
 
 	/* store ports information */
 	for (i = 0; i < core_info->num_tx_port; i++) {
-		classified_data[i].if_type = core_info->tx_ports[i].if_type;
-		classified_data[i].if_no   = i;
-		classified_data[i].tx_port = core_info->tx_ports[i].dpdk_port;
-		classified_data[i].num_pkt = 0;
+		classified_data[i].if_type      = core_info->tx_ports[i].if_type;
+		classified_data[i].if_no        = i;
+		classified_data[i].if_no_global = core_info->tx_ports[i].if_no;
+		classified_data[i].tx_port      = core_info->tx_ports[i].dpdk_port;
+		classified_data[i].num_pkt      = 0;
 	}
 
 	return 0;
@@ -283,8 +292,9 @@ push_packet(struct rte_mbuf *pkt, struct classified_data *classified_data)
 	if (unlikely(classified_data->num_pkt == MAX_PKT_BURST)) {
 		RTE_LOG(DEBUG, SPP_CLASSIFIER_MAC,
 				"transimit packets (buffer is filled). "
-				"if_type=%d, if_no=%d, tx_port=%hhd, num_pkt=%hu\n",
+				"if_type=%d, if_no={%d,%d}, tx_port=%hhd, num_pkt=%hu\n",
 				classified_data->if_type,
+				classified_data->if_no_global,
 				classified_data->if_no,
 				classified_data->tx_port,
 				classified_data->num_pkt);
@@ -375,6 +385,15 @@ change_update_index(struct classifier_mac_mng_info *classifier_mng_info, unsigne
 	}
 }
 
+/* classifier(mac address) initialize globals. */
+int
+spp_classifier_mac_init(void)
+{
+	memset(g_classifier_mng_info, 0, sizeof(g_classifier_mng_info));
+
+	return 0;
+}
+
 /* classifier(mac address) update component info. */
 int
 spp_classifier_mac_update(struct spp_core_info *core_info)
@@ -428,7 +447,7 @@ spp_classifier_mac_do(void *arg)
 	struct rte_mbuf *rx_pkts[MAX_PKT_BURST];
 
 	const int n_classified_data = core_info->num_tx_port;
-	struct classified_data classified_data[n_classified_data];
+	struct classified_data *classified_data = classifier_mng_info->classified_data;
 
 	uint64_t cur_tsc, prev_tsc = 0;
 	const uint64_t drain_tsc = (rte_get_tsc_hz() + US_PER_S - 1) /
@@ -501,3 +520,54 @@ spp_classifier_mac_do(void *arg)
 
 	return 0;
 }
+
+/* classifier(mac address) iterate classifier table. */
+int spp_classifier_mac_iterate_table(
+		struct spp_iterate_classifier_table_params *params)
+{
+	int ret, i;
+	const void *key;
+	void *data;
+	uint32_t next = 0;
+	struct classifier_mac_mng_info *classifier_mng_info;
+	struct classifier_mac_info *classifier_info;
+	struct classified_data *classified_data;
+	struct spp_config_port_info port;
+	char mac_addr_str[ETHER_ADDR_STR_BUF_SZ];
+
+	for (i = 0; i < RTE_MAX_LCORE; i++) {
+		classifier_mng_info = g_classifier_mng_info + i;
+		if (! is_used_mng_info(classifier_mng_info))
+			continue;
+
+		classifier_info = classifier_mng_info->info + 
+				classifier_mng_info->ref_index;
+
+		classified_data = classifier_mng_info->classified_data;
+
+		RTE_LOG(DEBUG, SPP_CLASSIFIER_MAC,
+			"Core[%u] Start iterate classifier table.\n", i);
+
+		while(1) {
+			ret = rte_hash_iterate(classifier_info->classifier_table,
+					&key, &data, &next);
+
+			if (unlikely(ret < 0))
+				break;
+
+			ether_format_addr(mac_addr_str, sizeof(mac_addr_str),
+					(const struct ether_addr *)key);
+
+			port.if_type = (classified_data + (long)data)->if_type;
+			port.if_no   = (classified_data + (long)data)->if_no_global;
+
+			(*params->element_proc)(
+					params->opaque,
+					SPP_CLASSIFIER_TYPE_MAC,
+					mac_addr_str,
+					&port);
+		}
+	}
+
+	return 0;
+}
diff --git a/src/vf/classifier_mac.h b/src/vf/classifier_mac.h
index 98f47a5..b1d0198 100644
--- a/src/vf/classifier_mac.h
+++ b/src/vf/classifier_mac.h
@@ -3,6 +3,12 @@
 
 /* forward declaration */
 struct spp_core_info;
+struct spp_iterate_classifier_table_params;
+
+/**
+ * classifier(mac address) initialize globals.
+ */
+int spp_classifier_mac_init(void);
 
 /**
  * classifier(mac address) update component info.
@@ -23,4 +29,10 @@ int spp_classifier_mac_update(struct spp_core_info *core_info);
  */
 int spp_classifier_mac_do(void *arg);
 
+/**
+ * classifier(mac address) iterate classifier table.
+ */
+int spp_classifier_mac_iterate_table(
+		struct spp_iterate_classifier_table_params *params);
+
 #endif /* _CLASSIFIER_MAC_H_ */
diff --git a/src/vf/command_dec.c b/src/vf/command_dec.c
index 3295618..bc8829f 100644
--- a/src/vf/command_dec.c
+++ b/src/vf/command_dec.c
@@ -26,6 +26,7 @@ static const char *COMMAND_TYPE_STRINGS[] = {
 	"stop",
 #endif
 	"process",
+	"status",
 
 	/* termination */ "",
 };
@@ -422,6 +423,9 @@ spp_command_decode_request(struct spp_command_request *request, const char *requ
 		case SPP_CMDTYPE_PROCESS:
 			request->is_requested_process = 1;
 			break;
+		case SPP_CMDTYPE_STATUS:
+			request->is_requested_status = 1;
+			break;
 		default:
 			/* nothing to do */
 			break;
diff --git a/src/vf/command_dec.h b/src/vf/command_dec.h
index 25e1ea0..42a0168 100644
--- a/src/vf/command_dec.h
+++ b/src/vf/command_dec.h
@@ -40,6 +40,7 @@ enum spp_command_type {
 	SPP_CMDTYPE_STOP,
 #endif
 	SPP_CMDTYPE_PROCESS,
+	SPP_CMDTYPE_STATUS,
 };
 
 #if 0 /* not supported yet */
@@ -93,6 +94,7 @@ struct spp_command_request {
 	struct spp_command commands[SPP_CMD_MAX_COMMANDS];
 
 	int is_requested_process;
+	int is_requested_status;
 };
 
 /* decode error information */
diff --git a/src/vf/command_proc.c b/src/vf/command_proc.c
index 50418cc..a627277 100644
--- a/src/vf/command_proc.c
+++ b/src/vf/command_proc.c
@@ -50,13 +50,8 @@ execute_command(const struct spp_command *command)
 		ret = spp_flush();
 		break;
 
-	case SPP_CMDTYPE_PROCESS:
-		RTE_LOG(INFO, SPP_COMMAND_PROC, "Execute process command.\n");
-		/* nothing to do here */
-		break;
-
 	default:
-		RTE_LOG(ERR, SPP_COMMAND_PROC, "Unknown command. type=%d\n", command->type);
+		RTE_LOG(INFO, SPP_COMMAND_PROC, "Execute other command. type=%d\n", command->type);
 		/* nothing to do here */
 		break;
 	}
@@ -229,6 +224,73 @@ append_response_process_value(json_t *parent_obj)
 	return 0;
 }
 
+/* append classifier element value */
+static
+int append_classifier_element_value(
+		void *opaque,
+		__rte_unused enum spp_classifier_type type,
+		const char *data,
+		const struct spp_config_port_info *port)
+{
+	json_t *parent_obj = (json_t *)opaque;
+
+	char port_str[64];
+	spp_config_format_if_info(port_str, port->if_type, port->if_no);
+
+	json_array_append_new(parent_obj, json_pack(
+			"{ssssss}",
+			"type", "mac",
+			"value", data,
+			"port", port_str));
+
+	return 0;
+}
+
+/* append info value(status response) to specified json object */
+static int 
+append_response_info_value(json_t *parent_obj)
+{
+	int ret = -1;
+	json_t *info_obj, *tab_obj;
+	struct spp_iterate_classifier_table_params itr_params;
+
+	/* create classifier_table array */
+	tab_obj = json_array();
+	if (unlikely(tab_obj == NULL))
+		return -1;
+
+	itr_params.opaque = tab_obj;
+	itr_params.element_proc = append_classifier_element_value;
+
+	ret = spp_iterate_classifier_table(&itr_params);
+	if (unlikely(ret != 0)) {
+		json_decref(tab_obj);
+		return -1;
+	}
+
+	/* set classifier_table object in info object */
+	info_obj = json_object();
+	if (unlikely(info_obj == NULL)) {
+		json_decref(tab_obj);
+		return -1;
+	}
+
+	ret = json_object_set_new(info_obj, "classifier_table", tab_obj);
+	if (unlikely(ret != 0)) {
+		json_decref(tab_obj);
+		return -1;
+	}
+
+	/* set info object in parent object */
+	ret = json_object_set_new(parent_obj, "info", info_obj);
+	if (unlikely(ret != 0)) {
+		json_decref(info_obj);
+		return -1;
+	}
+
+	return 0;
+}
+
 /* send response for decode error */
 static void
 send_decode_error_response(int *sock, const struct spp_command_request *request,
@@ -244,10 +306,6 @@ send_decode_error_response(int *sock, const struct spp_command_request *request,
 		return;
 	}
 
-	/* **
-	 * output order of object in string is inverse to addition order
-	 * **/
-
 	/* create & append result array */
 	ret = append_response_decode_results_object(top_obj, request, decode_error);
 	if (unlikely(ret != 0)) {
@@ -257,10 +315,10 @@ send_decode_error_response(int *sock, const struct spp_command_request *request,
 	}
 
 	/* serialize */
-	msg = json_dumps(top_obj, JSON_INDENT(2));
+	msg = json_dumps(top_obj, JSON_INDENT(2) | JSON_PRESERVE_ORDER);
 	json_decref(top_obj);
 
-	RTE_LOG(INFO, SPP_COMMAND_PROC, "Make command response (decode error). "
+	RTE_LOG(DEBUG, SPP_COMMAND_PROC, "Make command response (decode error). "
 			"response_str=\n%s\n", msg);
 
 	/* send response to requester */
@@ -288,9 +346,13 @@ send_command_result_response(int *sock, const struct spp_command_request *reques
 		return;
 	}
 
-	/* **
-	 * output order of object in string is inverse to addition order
-	 * **/
+	/* create & append result array */
+	ret = append_response_command_results_object(top_obj, request, command_results);
+	if (unlikely(ret != 0)) {
+		RTE_LOG(ERR, SPP_COMMAND_PROC, "Failed to make command result response.");
+		json_decref(top_obj);
+		return;
+	}
 
 	/* append process information value */
 	if (request->is_requested_process) {
@@ -302,19 +364,21 @@ send_command_result_response(int *sock, const struct spp_command_request *reques
 		}
 	}
 
-	/* create & append result array */
-	ret = append_response_command_results_object(top_obj, request, command_results);
-	if (unlikely(ret != 0)) {
-		RTE_LOG(ERR, SPP_COMMAND_PROC, "Failed to make command result response.");
-		json_decref(top_obj);
-		return;
+	/* append info value */
+	if (request->is_requested_status) {
+		ret = append_response_info_value(top_obj);
+		if (unlikely(ret != 0)) {
+			RTE_LOG(ERR, SPP_COMMAND_PROC, "Failed to make command result response.");
+			json_decref(top_obj);
+			return;
+		}
 	}
 
 	/* serialize */
-	msg = json_dumps(top_obj, JSON_INDENT(2));
+	msg = json_dumps(top_obj, JSON_INDENT(2) | JSON_PRESERVE_ORDER);
 	json_decref(top_obj);
 
-	RTE_LOG(INFO, SPP_COMMAND_PROC, "Make command response (command result). "
+	RTE_LOG(DEBUG, SPP_COMMAND_PROC, "Make command response (command result). "
 			"response_str=\n%s\n", msg);
 
 	/* send response to requester */
@@ -342,7 +406,7 @@ process_request(int *sock, const char *request_str, size_t request_str_len)
 	memset(&decode_error, 0, sizeof(struct spp_command_decode_error));
 	memset(command_results, 0, sizeof(command_results));
 
-	RTE_LOG(INFO, SPP_COMMAND_PROC, "Start command request processing. "
+	RTE_LOG(DEBUG, SPP_COMMAND_PROC, "Start command request processing. "
 			"request_str=\n%.*s\n", (int)request_str_len, request_str);
 
 	/* decode request message */
@@ -351,11 +415,11 @@ process_request(int *sock, const char *request_str, size_t request_str_len)
 	if (unlikely(ret != 0)) {
 		/* send error response */
 		send_decode_error_response(sock, &request, &decode_error);
-		RTE_LOG(INFO, SPP_COMMAND_PROC, "End command request processing.\n");
+		RTE_LOG(DEBUG, SPP_COMMAND_PROC, "End command request processing.\n");
 		return ret;
 	}
 
-	RTE_LOG(INFO, SPP_COMMAND_PROC, "Command request is valid. "
+	RTE_LOG(DEBUG, SPP_COMMAND_PROC, "Command request is valid. "
 			"num_command=%d, num_valid_command=%d\n",
 			request.num_command, request.num_valid_command);
 
@@ -377,7 +441,7 @@ process_request(int *sock, const char *request_str, size_t request_str_len)
 	/* send response */
 	send_command_result_response(sock, &request, command_results);
 
-	RTE_LOG(INFO, SPP_COMMAND_PROC, "End command request processing.\n");
+	RTE_LOG(DEBUG, SPP_COMMAND_PROC, "End command request processing.\n");
 
 	return 0;
 }
diff --git a/src/vf/spp_config.c b/src/vf/spp_config.c
index 663a609..01f279a 100644
--- a/src/vf/spp_config.c
+++ b/src/vf/spp_config.c
@@ -198,6 +198,32 @@ spp_config_get_if_info(const char *port, enum port_type *if_type, int *if_no)
 }
 
 /*
+ * IF種別とIF番号からIF情報文字列を作成する
+ */
+int spp_config_format_if_info(char *port, enum port_type if_type, int if_no)
+{
+	const char* if_type_str;
+
+	switch (if_type) {
+	case PHY:
+		if_type_str = SPP_CONFIG_IFTYPE_NIC;
+		break;
+	case RING:
+		if_type_str = SPP_CONFIG_IFTYPE_RING;
+		break;
+	case VHOST:
+		if_type_str = SPP_CONFIG_IFTYPE_VHOST;
+		break;
+	default:
+		return -1;
+	}
+
+	sprintf(port, "%s%d", if_type_str, if_no);
+
+	return 0;
+}
+
+/*
  * MAC addressを文字列から数値へ変換
  */
 int64_t
diff --git a/src/vf/spp_config.h b/src/vf/spp_config.h
index 69f6a3f..a9bcb85 100644
--- a/src/vf/spp_config.h
+++ b/src/vf/spp_config.h
@@ -109,6 +109,14 @@ int64_t spp_config_change_mac_str_to_int64(const char *mac);
 int spp_config_get_if_info(const char *port, enum port_type *if_type, int *if_no);
 
 /*
+ * Format port string form if-type/if-number
+ *
+ * OK : 0
+ * NG : -1
+ */
+int spp_config_format_if_info(char *port, enum port_type if_type, int if_no);
+
+/*
  * Load config file
  * OK : 0
  * NG : -1
diff --git a/src/vf/spp_vf.c b/src/vf/spp_vf.c
index 23c1bd9..18533d1 100644
--- a/src/vf/spp_vf.c
+++ b/src/vf/spp_vf.c
@@ -877,6 +877,12 @@ ut_main(int argc, char *argv[])
 		}
 
 		/* 他機能部初期化 */
+		/* MAC振分初期化 */
+		int ret_classifier_mac_init = spp_classifier_mac_init();
+		if (unlikely(ret_classifier_mac_init != 0)) {
+			break;
+		}
+
 		/* コマンド機能部初期化 */
 		int ret_command_init = spp_command_proc_init(
 				g_startup_param.server_ip,
@@ -1130,3 +1136,19 @@ spp_flush(void)
 	memset(g_change_core, 0x00, sizeof(g_change_core));
 	return SPP_RET_OK;
 }
+
+/*
+ * Iterate Classifier_table
+ */
+int spp_iterate_classifier_table(struct spp_iterate_classifier_table_params *params)
+{
+	int ret;
+
+	ret = spp_classifier_mac_iterate_table(params);
+	if (unlikely(ret != 0)) {
+		RTE_LOG(ERR, APP, "Cannot iterate classfier_mac_table.\n");
+		return SPP_RET_NG;
+	}
+
+	return SPP_RET_OK;
+}
diff --git a/src/vf/spp_vf.h b/src/vf/spp_vf.h
index 4ca4568..bbdb904 100644
--- a/src/vf/spp_vf.h
+++ b/src/vf/spp_vf.h
@@ -82,4 +82,22 @@ int spp_update_classifier_table(enum spp_classifier_type type, const char *data,
  */
 int spp_flush(void);
 
+/* definition of iterated classifier element procedure function */
+typedef int (*spp_iterate_classifier_element_proc)(
+		void *opaque,
+		enum spp_classifier_type type,
+		const char *data,
+		const struct spp_config_port_info *port);
+
+/* iterate classifier table parameters */
+struct spp_iterate_classifier_table_params {
+	void *opaque;
+	spp_iterate_classifier_element_proc element_proc;
+};
+
+/*
+ * Iterate Classifier_table
+ */
+int spp_iterate_classifier_table(struct spp_iterate_classifier_table_params *params);
+
 #endif /* __SPP_VF_H__ */
-- 
1.9.1

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

* [spp] [PATCH 40/57] spp_vf: add output source information in error log
  2017-12-26  1:54 ` Yasufumi Ogawa
                     ` (38 preceding siblings ...)
  2017-12-28  4:55   ` [spp] [PATCH 39/57] spp_vf: add status command x-fn-spp
@ 2017-12-28  4:55   ` x-fn-spp
  2017-12-28  4:55   ` [spp] [PATCH 41/57] spp_vf: change function names x-fn-spp
                     ` (16 subsequent siblings)
  56 siblings, 0 replies; 97+ messages in thread
From: x-fn-spp @ 2017-12-28  4:55 UTC (permalink / raw)
  To: spp

From: Hiroyuki Nakamura <nakamura.hioryuki@po.ntt-tx.co.jp>

Add output source information in error log so that it becomes unique.

Signed-off-by: Kentaro Watanabe <watanabe.kentaro.z01@as.ntt-tx.co.jp>
Signed-off-by: Yasufum Ogawa <ogawa.yasufumi@lab.ntt.co.jp>
---
 src/vf/classifier_mac.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/src/vf/classifier_mac.c b/src/vf/classifier_mac.c
index 64e9883..157ee02 100644
--- a/src/vf/classifier_mac.c
+++ b/src/vf/classifier_mac.c
@@ -301,7 +301,7 @@ handle_l2multicast_packet(struct rte_mbuf *pkt,
 	int i;
 
 	if (unlikely(classifier_info->num_active_classified == 0)) {
-		RTE_LOG(ERR, SPP_CLASSIFIER_MAC, "No mac address.\n");
+		RTE_LOG(ERR, SPP_CLASSIFIER_MAC, "No mac address.(l2multicast packet)\n");
 		rte_pktmbuf_free(pkt);
 		return;
 	}
-- 
1.9.1

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

* [spp] [PATCH 41/57] spp_vf: change function names
  2017-12-26  1:54 ` Yasufumi Ogawa
                     ` (39 preceding siblings ...)
  2017-12-28  4:55   ` [spp] [PATCH 40/57] spp_vf: add output source information in error log x-fn-spp
@ 2017-12-28  4:55   ` x-fn-spp
  2017-12-28  4:55   ` [spp] [PATCH 42/57] spp_vf: change how to request commands x-fn-spp
                     ` (15 subsequent siblings)
  56 siblings, 0 replies; 97+ messages in thread
From: x-fn-spp @ 2017-12-28  4:55 UTC (permalink / raw)
  To: spp

From: Hiroyuki Nakamura <nakamura.hioryuki@po.ntt-tx.co.jp>

Change function name in program files according to the change of
the function name from "spp_config_format_if_info" to
"spp_config_format_port_string"

Signed-off-by: Daiki Yamashita <yamashita.daiki.z01@as.ntt-tx.co.jp>
Signed-off-by: Yasufum Ogawa <ogawa.yasufumi@lab.ntt.co.jp>
---
 src/vf/command_proc.c | 2 +-
 src/vf/spp_config.c   | 2 +-
 src/vf/spp_config.h   | 2 +-
 3 files changed, 3 insertions(+), 3 deletions(-)

diff --git a/src/vf/command_proc.c b/src/vf/command_proc.c
index a627277..fe18e22 100644
--- a/src/vf/command_proc.c
+++ b/src/vf/command_proc.c
@@ -235,7 +235,7 @@ int append_classifier_element_value(
 	json_t *parent_obj = (json_t *)opaque;
 
 	char port_str[64];
-	spp_config_format_if_info(port_str, port->if_type, port->if_no);
+	spp_config_format_port_string(port_str, port->if_type, port->if_no);
 
 	json_array_append_new(parent_obj, json_pack(
 			"{ssssss}",
diff --git a/src/vf/spp_config.c b/src/vf/spp_config.c
index 01f279a..27bce8f 100644
--- a/src/vf/spp_config.c
+++ b/src/vf/spp_config.c
@@ -200,7 +200,7 @@ spp_config_get_if_info(const char *port, enum port_type *if_type, int *if_no)
 /*
  * IF種別とIF番号からIF情報文字列を作成する
  */
-int spp_config_format_if_info(char *port, enum port_type if_type, int if_no)
+int spp_config_format_port_string(char *port, enum port_type if_type, int if_no)
 {
 	const char* if_type_str;
 
diff --git a/src/vf/spp_config.h b/src/vf/spp_config.h
index a9bcb85..7a8bdf6 100644
--- a/src/vf/spp_config.h
+++ b/src/vf/spp_config.h
@@ -114,7 +114,7 @@ int spp_config_get_if_info(const char *port, enum port_type *if_type, int *if_no
  * OK : 0
  * NG : -1
  */
-int spp_config_format_if_info(char *port, enum port_type if_type, int if_no);
+int spp_config_format_port_string(char *port, enum port_type if_type, int if_no);
 
 /*
  * Load config file
-- 
1.9.1

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

* [spp] [PATCH 42/57] spp_vf: change how to request commands
  2017-12-26  1:54 ` Yasufumi Ogawa
                     ` (40 preceding siblings ...)
  2017-12-28  4:55   ` [spp] [PATCH 41/57] spp_vf: change function names x-fn-spp
@ 2017-12-28  4:55   ` x-fn-spp
  2017-12-28  4:55   ` [spp] [PATCH 43/57] spp_vf: update command decode procedure x-fn-spp
                     ` (14 subsequent siblings)
  56 siblings, 0 replies; 97+ messages in thread
From: x-fn-spp @ 2017-12-28  4:55 UTC (permalink / raw)
  To: spp

From: Hiroyuki Nakamura <nakamura.hioryuki@po.ntt-tx.co.jp>

Change the way how to request commands.
spp_nfv command is used instead of requesting via json file.

Signed-off-by: Kentaro Watanabe <watanabe.kentaro.z01@as.ntt-tx.co.jp>
Signed-off-by: Yasufum Ogawa <ogawa.yasufumi@lab.ntt.co.jp>
---
 src/vf/command_dec.c  | 503 +++++++++++++++++++-------------------------------
 src/vf/command_dec.h  |  15 +-
 src/vf/command_proc.c |  44 +----
 src/vf/spp_config.c   |  14 +-
 src/vf/spp_config.h   |   2 +-
 src/vf/spp_vf.c       |  38 ++--
 src/vf/spp_vf.h       |   8 +-
 7 files changed, 233 insertions(+), 391 deletions(-)

diff --git a/src/vf/command_dec.c b/src/vf/command_dec.c
index bc8829f..468702f 100644
--- a/src/vf/command_dec.c
+++ b/src/vf/command_dec.c
@@ -4,33 +4,12 @@
 #include <rte_log.h>
 #include <rte_branch_prediction.h>
 
-#include <jansson.h>
-
 #include "spp_vf.h"
 #include "spp_config.h"
 #include "command_dec.h"
 
 #define RTE_LOGTYPE_SPP_COMMAND_PROC RTE_LOGTYPE_USER1
 
-/* command type string list
-	do it same as the order of enum command_type */
-static const char *COMMAND_TYPE_STRINGS[] = {
-#if 0 /* not supported yet */
-	"add",
-	"component",
-#endif
-	"classifier_table",
-	"flush",
-#if 0 /* not supported yet */
-	"forward",
-	"stop",
-#endif
-	"process",
-	"status",
-
-	/* termination */ "",
-};
-
 /* classifier type string list
 	do it same as the order of enum spp_classifier_type (spp_vf.h) */
 static const char *CLASSIFILER_TYPE_STRINGS[] = {
@@ -40,44 +19,15 @@ static const char *CLASSIFILER_TYPE_STRINGS[] = {
 	/* termination */ "",
 };
 
-/* forward declaration */
-struct json_value_decode_rule;
-
-/* definition of decode procedure function */
-typedef int (*json_value_decode_proc)(
-		void *, 
-		const json_t *, 
-		const struct json_value_decode_rule *, 
-		struct spp_command_decode_error *);
-
-/* rule definition that decode json object to c-struct */
-struct json_value_decode_rule {
-	char name[SPP_CMD_NAME_BUFSZ];
-	json_type json_type;
-	size_t offset;
-	json_value_decode_proc decode_proc;
-
-	struct {
-		json_type json_type;
-		size_t element_sz;
-		size_t offset_num;
-		size_t offset_num_valid;
-	} array;
-};
-
-/* get output address for decoded json value */
-#define DR_GET_OUTPUT(output_base, rule__) ((char *)output_base + rule__->offset)
-
 /* set decode error */
 inline int
 set_decode_error(struct spp_command_decode_error *error,
-		int error_code,
-		const struct json_value_decode_rule *error_rule)
+		const int error_code, const char *error_name)
 {
 	error->code = error_code;
 
-	if (likely(error_rule != NULL))
-		strcpy(error->value_name, error_rule->name);
+	if (likely(error_name != NULL))
+		strcpy(error->value_name, error_name);
 
 	return error->code;
 }
@@ -85,307 +35,242 @@ set_decode_error(struct spp_command_decode_error *error,
 /* set decode error */
 inline int
 set_string_value_decode_error(struct spp_command_decode_error *error,
-		const char* value,
-		const struct json_value_decode_rule *error_rule)
+		const char* value, const char *error_name)
 {
 	strcpy(error->value, value);
-	return set_decode_error(error, SPP_CMD_DERR_BAD_VALUE, error_rule);
+	return set_decode_error(error, SPP_CMD_DERR_BAD_VALUE, error_name);
 }
 
-/* helper */
-#define END_OF_DECODE_RULE {.name = ""},
-#define IS_END_OF_DECODE_RULE(rule) ((rule)->name[0] == '\0')
-
-/* definition helper that enum value decode procedure */
-#define DECODE_ENUM_VALUE(proc_name, enum_type, string_table)			\
-static int									\
-decode_##proc_name##_value(void *output, const json_t *value_obj,		\
-		const struct json_value_decode_rule *rule,			\
-		struct spp_command_decode_error *error)				\
-{										\
-	int i;									\
-	enum_type type;								\
-	const char *str_val = json_string_value(value_obj);			\
-										\
-	for (i = 0; string_table[i][0] != '\0'; ++i) {				\
-		if (unlikely(strcmp(str_val, string_table[i]) == 0)) {		\
-			type = i;						\
-			memcpy(output, &type, sizeof(enum_type));		\
-			return 0;						\
-		}								\
-	}									\
-										\
-	return set_string_value_decode_error(error, str_val, rule);		\
-}										\
-
-/* enum value decode procedure for "command_type" */
-DECODE_ENUM_VALUE(command_type, enum spp_command_type, COMMAND_TYPE_STRINGS)
-
-/* enum value decode procedure for "classifier_type" */
-DECODE_ENUM_VALUE(classifier_type, enum spp_classifier_type, CLASSIFILER_TYPE_STRINGS)
-
-#if 0 /* not supported yet */
-/* decode procedure for integer */
-static int
-decode_int_value(void *output, const json_t *value_obj,
-		__rte_unused const struct json_value_decode_rule *rule,
-		__rte_unused struct spp_command_decode_error *error)
+/* Split command line arguments with spaces */
+static void
+decode_argument_value(char *string, int *argc, char *argv[])
 {
-	int val = json_integer_value(value_obj);
-	memcpy(output, &val, sizeof(int));
+	int cnt = 0;
+	const char *delim = " ";
+	char *argv_tok = NULL;
+
+	argv_tok = strtok(string, delim);
+	while(argv_tok != NULL) {
+		argv[cnt] = argv_tok;
+		cnt++;
+		argv_tok = strtok(NULL, delim);
+	}
+	*argc = cnt;
+}
 
-	return 0;
+/* Get index of array */
+static int
+get_arrary_index(const char *match, const char *list[])
+{
+	int i;
+	for (i = 0; list[i][0] == '\0'; i++) {
+		if (strcmp(list[i], match) == 0)
+			return i;
+	}
+	return -1;
 }
 
-/* decode procedure for string */
+/* decoding procedure of port */
 static int
-decode_string_value(void *output, const json_t *value_obj,
-		__rte_unused const struct json_value_decode_rule *rule,
-		__rte_unused struct spp_command_decode_error *error)
+decode_port_value(void *output, const char *arg_val)
 {
-	const char* str_val = json_string_value(value_obj);
-	strcpy(output, str_val);
+	int ret = 0;
+	struct spp_config_port_info *port = output;
+	ret = spp_config_get_if_info(arg_val, &port->if_type, &port->if_no);
+	if (unlikely(ret != 0)) {
+		RTE_LOG(ERR, SPP_COMMAND_PROC, "Bad port. val=%s\n", arg_val);
+		return -1;
+	}
 
 	return 0;
 }
-#endif
 
-/* decode procedure for mac address string */
+/* decoding procedure of mac address string */
 static int
-decode_mac_addr_str_value(void *output, const json_t *value_obj,
-		const struct json_value_decode_rule *rule,
-		struct spp_command_decode_error *error)
+decode_mac_addr_str_value(void *output, const char *arg_val)
 {
-	int ret = -1;
-	const char* str_val = json_string_value(value_obj);
+	int64_t ret = 0;
+	const char *str_val = arg_val;
 
 	/* if default specification, convert to internal dummy address */
 	if (unlikely(strcmp(str_val, SPP_CONFIG_DEFAULT_CLASSIFIED_SPEC_STR) == 0))
 		str_val = SPP_CONFIG_DEFAULT_CLASSIFIED_DMY_ADDR_STR;
 
 	ret = spp_config_change_mac_str_to_int64(str_val);
-	if (unlikely(ret == -1)) {
+	if (unlikely(ret < 0)) {
 		RTE_LOG(ERR, SPP_COMMAND_PROC, "Bad mac address string. val=%s\n",
 				str_val);
-		return set_string_value_decode_error(error, str_val, rule);
+		return -1;
 	}
 
-	strcpy(output, str_val);
-
+	strcpy((char *)output, str_val);
 	return 0;
 }
 
-/* decode procedure for spp_config_port_info */
+/* decoding procedure of classifier type */
 static int
-decode_port_value(void *output, const json_t *value_obj,
-		const struct json_value_decode_rule *rule,
-		struct spp_command_decode_error *error)
+decode_classifier_type_value(void *output, const char *arg_val)
 {
-	int ret = -1;
-	const char* str_val = json_string_value(value_obj);
-	struct spp_config_port_info *port = (struct spp_config_port_info *)output;
-
-	if (strcmp(str_val, SPP_CMD_UNUSE) == 0) {
-		port->if_type = UNDEF;
-		port->if_no = 0;
-		return 0;
-	}
-
-	ret = spp_config_get_if_info(str_val, &port->if_type, &port->if_no);
-	if (unlikely(ret != 0)) {
-		RTE_LOG(ERR, SPP_COMMAND_PROC, "Bad port. val=%s\n", str_val);
-		return set_string_value_decode_error(error, str_val, rule);
-	}
-
-	return 0;
+        int ret = 0;
+	ret = get_arrary_index(arg_val, CLASSIFILER_TYPE_STRINGS);
+        if (unlikely(ret < 0)) {
+                RTE_LOG(ERR, SPP_COMMAND_PROC, "Unknown classifier type. val=%s\n", arg_val);
+                return -1;
+        }
+
+        *(int *)output = ret;
+        return 0;
 }
 
-/* decode json object */
+/* decode procedure for classifier value */
 static int
-decode_json_object(void *output, const json_t *parent_obj,
-		const struct json_value_decode_rule *rules,
-		struct spp_command_decode_error *error)
+decode_classifiert_value_value(void *output, const char *arg_val)
 {
-	int ret = -1;
-	int i, n;
-	json_t *obj;
-	json_t *value_obj;
-	const struct json_value_decode_rule *rule;
-
-	void *sub_output;
-
-	for (i = 0; unlikely(! IS_END_OF_DECODE_RULE(&rules[i])); ++ i) {
-		rule = rules + i;
-
-		RTE_LOG(DEBUG, SPP_COMMAND_PROC, "Get one object. name=%s\n",
-				rule->name);
-
-		value_obj = json_object_get(parent_obj, rule->name);
-		if (unlikely(value_obj == NULL)) {
-			RTE_LOG(ERR, SPP_COMMAND_PROC, "No parameter. "
-					"name=%s\n", rule->name);
-			return set_decode_error(error, SPP_CMD_DERR_NO_PARAM, rule);
-		} else if (unlikely(json_typeof(value_obj) != rule->json_type)) {
-			RTE_LOG(ERR, SPP_COMMAND_PROC, "Bad value type. "
-					"name=%s\n", rule->name);
-			return set_decode_error(error, SPP_CMD_DERR_BAD_TYPE, rule);
-		}
-
-		switch (rule->json_type) {
-		case JSON_ARRAY:
-			RTE_LOG(DEBUG, SPP_COMMAND_PROC, "Decode array. num=%lu\n",
-					json_array_size(value_obj));
-
-			*(int *)((char *)output + rule->array.offset_num) = 
-					(int)json_array_size(value_obj);
-
-			json_array_foreach(value_obj, n, obj) {
-				RTE_LOG(DEBUG, SPP_COMMAND_PROC, "Decode array element. "
-						"index=%d\n", n);
-				
-				if (unlikely(json_typeof(obj) != rule->array.json_type)) {
-					RTE_LOG(ERR, SPP_COMMAND_PROC, "Bad value type. "
-							"name=%s, index=%d\n", rule->name, n);
-					return set_decode_error(error, SPP_CMD_DERR_BAD_TYPE, rule);
-				}
-
-				sub_output = DR_GET_OUTPUT(output, rule) + 
-						(rule->array.element_sz * n);
-				ret = (*rule->decode_proc)(sub_output, obj, rule, error);
-				if (unlikely(ret != 0)) {
-					RTE_LOG(ERR, SPP_COMMAND_PROC, "Bad value. "
-							"name=%s, index=%d\n", rule->name, n);
-					/* decode error is set in decode function */
-					return ret;
-				}
-
-				*(int *)((char *)output +
-						rule->array.offset_num_valid) = n + 1;
-			}
+        int ret = -1;
+	struct spp_command_classifier_table *classifier_table = output;
+	switch(classifier_table->type) {
+		case SPP_CLASSIFIER_TYPE_MAC:
+			ret = decode_mac_addr_str_value(classifier_table->value, arg_val);
 			break;
 		default:
-			sub_output = DR_GET_OUTPUT(output, rule);
-			ret = (*rule->decode_proc)(sub_output, value_obj, rule, error);
-			if (unlikely(ret != 0)) {
-				RTE_LOG(ERR, SPP_COMMAND_PROC, "Bad value. "
-						"name=%s\n", rule->name);
-				/* decode error is set in decode function */
-				return ret;
-			}
 			break;
-		}
 	}
+        return ret;
+}
 
-	return 0;
+/* decode procedure for classifier port */
+static int
+decode_classifier_port_value(void *output, const char *arg_val)
+{
+	struct spp_config_port_info *port = output;
+
+        if (strcmp(arg_val, SPP_CMD_UNUSE) == 0) {
+                port->if_type = UNDEF;
+                port->if_no = 0;
+                return 0;
+        }
+
+	return decode_port_value(port, arg_val);
 }
 
-/* decode rule for command-base */
-const struct json_value_decode_rule DECODERULE_COMMAND_BASE[] = {
-	{
-		.name = "command",
-		.json_type = JSON_STRING,
-		.offset = offsetof(struct spp_command, type),
-		.decode_proc = decode_command_type_value,
-	},
-	END_OF_DECODE_RULE
+/* parameter list for decoding */
+struct decode_parameter_list {
+        const char *name;
+        size_t offset;
+        int (*func)(void *output, const char *arg_val);
 };
 
-#if 0 /* not supported yet */
-/* decode rule for add-command-spec */
-const struct json_value_decode_rule DECODERULE_ADD_COMMAND[] = {
-	{
-		.name = "ports",
-		.json_type = JSON_ARRAY,
-		.offset = offsetof(struct spp_command_add, ports),
-		.decode_proc = decode_port_value,
-
-		.array.element_sz = sizeof(struct spp_config_port_info),
-		.array.json_type = JSON_STRING,
-		.array.offset_num = offsetof(struct spp_command_add, num_port),
+/* parameter list for each command */
+static struct decode_parameter_list parameter_list[][SPP_CMD_MAX_PARAMETERS] = {
+	{                      /* classifier_table */
+		{
+			.name = "type",
+			.offset = offsetof(struct spp_command, spec.classifier_table.type),
+			.func = decode_classifier_type_value
+		},
+		{
+			.name = "value",
+			.offset = offsetof(struct spp_command, spec.classifier_table),
+			.func = decode_classifiert_value_value
+		},
+		{
+			.name = "port",
+			.offset = offsetof(struct spp_command, spec.classifier_table.port),
+			.func = decode_classifier_port_value
+		},
+		{ NULL, 0, NULL },
 	},
-	END_OF_DECODE_RULE
-};
-#endif
-
-/* decode rule for classifier-table-command-spec */
-const struct json_value_decode_rule DECODERULE_CLASSIFIER_TABLE_COMMAND[] = {
-	{
-		.name = "type",
-		.json_type = JSON_STRING,
-		.offset = offsetof(struct spp_command_classifier_table, type),
-		.decode_proc = decode_classifier_type_value,
-	},{
-		.name = "value",
-		.json_type = JSON_STRING,
-		.offset = offsetof(struct spp_command_classifier_table, value),
-		.decode_proc = decode_mac_addr_str_value,
-	},{
-		.name = "port",
-		.json_type = JSON_STRING,
-		.offset = offsetof(struct spp_command_classifier_table, port),
-		.decode_proc = decode_port_value,
-	},
-	END_OF_DECODE_RULE
+	{ { NULL, 0, NULL } }, /* flush            */
+	{ { NULL, 0, NULL } }, /* _get_client_id   */
+	{ { NULL, 0, NULL } }, /* status           */
+	{ { NULL, 0, NULL } }, /* termination      */
 };
 
-/* decode procedure for command */
+/* check by list for each command line argument */
 static int
-decode_command_object(void* output, const json_t *parent_obj,
-		__rte_unused const struct json_value_decode_rule *rule,
-		struct spp_command_decode_error *error)
+check_comand_argment_in_list(struct spp_command_request *request,
+				int argc, char *argv[],
+				struct spp_command_decode_error *error)
 {
-	int ret = -1;
-	struct spp_command *command = (struct spp_command *)output;
-	const struct json_value_decode_rule *spec_rules = NULL;
-
-	/* decode command-base */
-	ret = decode_json_object(command, parent_obj, DECODERULE_COMMAND_BASE, error);
-	if (unlikely(ret != 0)) {
-		RTE_LOG(ERR, SPP_COMMAND_PROC, "Bad command. ret=%d\n", ret);
-		/* decode error is set in decode_json_object function */
-		return ret;
+	int ret = 0;
+	int ci = request->commands[0].type;
+	int pi = 0;
+	static struct decode_parameter_list *list = NULL;
+	for(pi = 1; pi < argc-1; pi++) {
+		list = &parameter_list[ci][pi];
+		ret = (*list->func)((void *)((char*)&request->commands[0]+list->offset), argv[pi]);
+		if (unlikely(ret < 0)) {
+			RTE_LOG(ERR, SPP_COMMAND_PROC,
+					"Bad value. command = %s, name=%s, index=%d\n",
+					argv[0], list->name, pi);
+			return set_string_value_decode_error(error, argv[pi], list->name);
+		}
 	}
+	return 0;
+}
 
-	/* decode command-specific */
-	switch (command->type) {
-		case SPP_CMDTYPE_CLASSIFIER_TABLE:
-			spec_rules = DECODERULE_CLASSIFIER_TABLE_COMMAND;
-			break;
+/* command list for decoding */
+struct decode_command_list {
+	const char *name;
+	int   param_min;
+	int   param_max;
+	int (*func)(struct spp_command_request *request, int argc, char *argv[],
+			struct spp_command_decode_error *error);
+};
 
-		default:
-			/* nothing specific */
-			/* (unknown command is already checked) */
-			break;
-	}
+/* command list */
+static struct decode_command_list command_list[] = {
+	{ "classifier_table", 4, 4, check_comand_argment_in_list }, /* classifier_table */
+	{ "flush",            1, 1, NULL                         }, /* flush            */
+	{ "_get_client_id",   1, 1, NULL                         }, /* _get_client_id   */
+	{ "status",           1, 1, NULL                         }, /* status           */
+	{ "",                 0, 0, NULL                         }  /* termination      */
+};
 
-	if (likely(spec_rules != NULL)) {
-		ret = decode_json_object(&command->spec, parent_obj, spec_rules, error);
-		if (unlikely(ret != 0)) {
-			RTE_LOG(ERR, SPP_COMMAND_PROC, "Bad command. ret=%d\n", ret);
-			/* decode error is set in decode_json_object function */
-			return ret;
+/* Decode command line arguments */
+static int
+decode_command_argment(struct spp_command_request *request,
+			const char *request_str,
+			struct spp_command_decode_error *error)
+{
+	struct decode_command_list *list = NULL;
+	int i = 0;
+	int argc = 0;
+	char *argv[SPP_CMD_MAX_PARAMETERS];
+	char tmp_str[SPP_CMD_MAX_PARAMETERS*SPP_CMD_VALUE_BUFSZ];
+	memset(argv, 0x00, sizeof(argv));
+	memset(tmp_str, 0x00, sizeof(tmp_str));
+
+	request->num_command = 1;
+
+	strcpy(tmp_str, request_str);
+	decode_argument_value(tmp_str, &argc, argv);
+	RTE_LOG(DEBUG, SPP_COMMAND_PROC, "Decode array. num=%d\n", argc);
+
+	for (i = 0; command_list[i].name[0] != '\0'; i++) {
+		list = &command_list[i];
+		if (strcmp(argv[0], list->name) != 0) {
+			continue;
 		}
+
+		if (unlikely(argc < list->param_min) || unlikely(list->param_max < argc)) {
+			RTE_LOG(ERR, SPP_COMMAND_PROC, "Parameter number out of range."
+					"request_str=%s\n", request_str);
+			return set_decode_error(error, SPP_CMD_DERR_BAD_FORMAT, NULL);
+		}
+
+		request->commands[0].type = i;
+		if (list->func != NULL)
+			return (*list->func)(request, argc, argv, error);
+
+		return 0;
 	}
 
-	return 0;
+	RTE_LOG(ERR, SPP_COMMAND_PROC, "Unknown command. command=%s, request_str=%s\n",
+			argv[0], request_str);
+	return set_string_value_decode_error(error, argv[0], "command");
 }
 
-/* decode rule for command request */
-const struct json_value_decode_rule DECODERULE_REQUEST[] = {
-	{
-		.name = "commands",
-		.json_type = JSON_ARRAY,
-		.offset = offsetof(struct spp_command_request, commands),
-		.decode_proc = decode_command_object,
-
-		.array.element_sz = sizeof(struct spp_command),
-		.array.json_type = JSON_OBJECT,
-		.array.offset_num = offsetof(struct spp_command_request, num_command),
-		.array.offset_num_valid = offsetof(struct spp_command_request, num_valid_command),
-	},
-	END_OF_DECODE_RULE
-};
-
 /* decode request from no-null-terminated string */
 int
 spp_command_decode_request(struct spp_command_request *request, const char *request_str,
@@ -393,35 +278,21 @@ spp_command_decode_request(struct spp_command_request *request, const char *requ
 {
 	int ret = -1;
 	int i;
-	json_t *top_obj;
-	json_error_t json_error;
-
-	/* parse json string */
-	top_obj = json_loadb(request_str, request_str_len, 0, &json_error);
-	if (unlikely(top_obj == NULL)) {
-		RTE_LOG(ERR, SPP_COMMAND_PROC, "Cannot parse command request. "
-				"error=%s, request_str=%.*s\n", 
-				json_error.text, (int)request_str_len, request_str);
-		return set_decode_error(error, SPP_CMD_DERR_BAD_FORMAT, NULL);
-	}
 
-	/* decode request object */
-	ret = decode_json_object(request, top_obj, DECODERULE_REQUEST, error);
-	if (unlikely(ret != 0)) {
+	/* decode request */
+	ret = decode_command_argment(request, request_str, error);
+	if (unlikely(ret < 0)) {
 		RTE_LOG(ERR, SPP_COMMAND_PROC, "Cannot decode command request. "
 				"ret=%d, request_str=%.*s\n", 
 				ret, (int)request_str_len, request_str);
-		/* decode error is set in decode_json_object function */
+		return ret;
 	}
 
-	/* free json object */
-	json_decref(top_obj);
-
 	/* check getter command */
 	for (i = 0; i < request->num_valid_command; ++i) {
 		switch (request->commands[i].type) {
-		case SPP_CMDTYPE_PROCESS:
-			request->is_requested_process = 1;
+		case SPP_CMDTYPE_CLIENT_ID:
+			request->is_requested_client_id = 1;
 			break;
 		case SPP_CMDTYPE_STATUS:
 			request->is_requested_status = 1;
diff --git a/src/vf/command_dec.h b/src/vf/command_dec.h
index 42a0168..8850485 100644
--- a/src/vf/command_dec.h
+++ b/src/vf/command_dec.h
@@ -4,6 +4,9 @@
 /* max number of command per request */
 #define SPP_CMD_MAX_COMMANDS 32
 
+/* maximum number of parameters per command */
+#define SPP_CMD_MAX_PARAMETERS 8
+
 /* command name string buffer size (include null char) */
 #define SPP_CMD_NAME_BUFSZ  32
 
@@ -29,17 +32,9 @@ enum spp_command_decode_error_code {
 /* command type
 	do it same as the order of COMMAND_TYPE_STRINGS */
 enum spp_command_type {
-#if 0 /* not supported yet yet */
-	SPP_CMDTYPE_ADD,
-	SPP_CMDTYPE_COMPONENT,
-#endif
 	SPP_CMDTYPE_CLASSIFIER_TABLE,
 	SPP_CMDTYPE_FLUSH,
-#if 0 /* not supported yet */
-	SPP_CMDTYPE_FORWARD,
-	SPP_CMDTYPE_STOP,
-#endif
-	SPP_CMDTYPE_PROCESS,
+	SPP_CMDTYPE_CLIENT_ID,
 	SPP_CMDTYPE_STATUS,
 };
 
@@ -93,7 +88,7 @@ struct spp_command_request {
 	int num_valid_command;
 	struct spp_command commands[SPP_CMD_MAX_COMMANDS];
 
-	int is_requested_process;
+	int is_requested_client_id;
 	int is_requested_status;
 };
 
diff --git a/src/vf/command_proc.c b/src/vf/command_proc.c
index fe18e22..0dd1d56 100644
--- a/src/vf/command_proc.c
+++ b/src/vf/command_proc.c
@@ -206,18 +206,18 @@ append_response_command_results_object(json_t *parent_obj,
 	return 0;
 }
 
-/* append process value to specified json object */
+/* append client id value to specified json object */
 static int
-append_response_process_value(json_t *parent_obj)
+append_response_client_id_value(json_t *parent_obj)
 {
 	int ret = -1;
 	json_t *proc_obj;
 
-	proc_obj = json_integer(spp_get_process_id());
+	proc_obj = json_integer(spp_get_client_id());
 	if (unlikely(proc_obj == NULL))
 		return -1;
 
-	ret = json_object_set_new(parent_obj, "process", proc_obj);
+	ret = json_object_set_new(parent_obj, "client_id", proc_obj);
 	if (unlikely(ret != 0))
 		return -1;
 
@@ -354,9 +354,9 @@ send_command_result_response(int *sock, const struct spp_command_request *reques
 		return;
 	}
 
-	/* append process information value */
-	if (request->is_requested_process) {
-		ret = append_response_process_value(top_obj);
+	/* append client id information value */
+	if (request->is_requested_client_id) {
+		ret = append_response_client_id_value(top_obj);
 		if (unlikely(ret != 0)) {
 			RTE_LOG(ERR, SPP_COMMAND_PROC, "Failed to make command result response.");
 			json_decref(top_obj);
@@ -459,15 +459,11 @@ spp_command_proc_do(void)
 {
 	int ret = -1;
 	int msg_ret = -1;
-	int i;
 
 	static int sock = -1;
 	static char *msgbuf = NULL;
 	static size_t msg_len = 0;
 
-	static size_t rb_cnt = 0;
-	static size_t lb_cnt = 0;
-
 	if (unlikely(msgbuf == NULL)) {
 		msgbuf = spp_strbuf_allocate(CMD_REQ_BUF_INIT_SIZE);
 		if (unlikely(msgbuf == NULL)) {
@@ -491,29 +487,9 @@ spp_command_proc_do(void)
 			return -1;
 	}
 
-	for (i = 0; i < msg_ret; ++i) {
-		switch (*(msgbuf + msg_len + i)) {
-		case '{':
-			++lb_cnt;
-			break;
-		case '}':
-			++rb_cnt;
-			break;
-		}
-
-		if (likely(lb_cnt != 0) && unlikely(rb_cnt == lb_cnt)) {
-			msg_len += (i + 1);
-			ret = process_request(&sock, msgbuf, msg_len);
-
-			spp_strbuf_remove_front(msgbuf, msg_len);
-			msg_ret = 0;
-			msg_len = 0;
-			rb_cnt = 0;
-			lb_cnt = 0;
-		}
-	}
-
-	msg_len = msg_len + msg_ret;
+	msg_len += (msg_ret + 1);
+	ret = process_request(&sock, msgbuf, msg_len);
+	spp_strbuf_remove_front(msgbuf, msg_len);
 
 	return 0;
 }
diff --git a/src/vf/spp_config.c b/src/vf/spp_config.c
index 27bce8f..bca455c 100644
--- a/src/vf/spp_config.c
+++ b/src/vf/spp_config.c
@@ -162,18 +162,18 @@ spp_config_get_if_info(const char *port, enum port_type *if_type, int *if_no)
 	char *endptr = NULL;
 
 	/* IF type check */
-	if (strncmp(port, SPP_CONFIG_IFTYPE_NIC, strlen(SPP_CONFIG_IFTYPE_NIC)) == 0) {
+	if (strncmp(port, SPP_CONFIG_IFTYPE_NIC ":", strlen(SPP_CONFIG_IFTYPE_NIC)+1) == 0) {
 		/* NIC */
 		type = PHY;
-		no_str = &port[strlen(SPP_CONFIG_IFTYPE_NIC)];
-	} else if (strncmp(port, SPP_CONFIG_IFTYPE_VHOST, strlen(SPP_CONFIG_IFTYPE_VHOST)) == 0) {
+		no_str = &port[strlen(SPP_CONFIG_IFTYPE_NIC)+1];
+	} else if (strncmp(port, SPP_CONFIG_IFTYPE_VHOST ":", strlen(SPP_CONFIG_IFTYPE_VHOST)+1) == 0) {
 		/* VHOST */
 		type = VHOST;
-		no_str = &port[strlen(SPP_CONFIG_IFTYPE_VHOST)];
-	} else if (strncmp(port, SPP_CONFIG_IFTYPE_RING, strlen(SPP_CONFIG_IFTYPE_RING)) == 0) {
+		no_str = &port[strlen(SPP_CONFIG_IFTYPE_VHOST)+1];
+	} else if (strncmp(port, SPP_CONFIG_IFTYPE_RING ":", strlen(SPP_CONFIG_IFTYPE_RING)+1) == 0) {
 		/* RING */
 		type = RING;
-		no_str = &port[strlen(SPP_CONFIG_IFTYPE_RING)];
+		no_str = &port[strlen(SPP_CONFIG_IFTYPE_RING)+1];
 	} else {
 		/* OTHER */
 		RTE_LOG(ERR, APP, "Unknown interface type. (port = %s)\n", port);
@@ -218,7 +218,7 @@ int spp_config_format_port_string(char *port, enum port_type if_type, int if_no)
 		return -1;
 	}
 
-	sprintf(port, "%s%d", if_type_str, if_no);
+	sprintf(port, "%s:%d", if_type_str, if_no);
 
 	return 0;
 }
diff --git a/src/vf/spp_config.h b/src/vf/spp_config.h
index 7a8bdf6..5722afd 100644
--- a/src/vf/spp_config.h
+++ b/src/vf/spp_config.h
@@ -6,7 +6,7 @@
 
 #define SPP_CONFIG_FILE_PATH "/usr/local/etc/spp/spp.json"
 
-#define SPP_CONFIG_IFTYPE_NIC   "nic"
+#define SPP_CONFIG_IFTYPE_NIC   "phy"
 #define SPP_CONFIG_IFTYPE_VHOST "vhost"
 #define SPP_CONFIG_IFTYPE_RING  "ring"
 
diff --git a/src/vf/spp_vf.c b/src/vf/spp_vf.c
index 18533d1..20a3b40 100644
--- a/src/vf/spp_vf.c
+++ b/src/vf/spp_vf.c
@@ -23,13 +23,13 @@ enum SPP_LONGOPT_RETVAL {
 	/* add below */
 
 	SPP_LONGOPT_RETVAL_CONFIG,
-	SPP_LONGOPT_RETVAL_PROCESS_ID,
+	SPP_LONGOPT_RETVAL_CLIENT_ID,
 	SPP_LONGOPT_RETVAL_VHOST_CLIENT
 };
 
 /* struct */
 struct startup_param {
-	int process_id;
+	int client_id;
 	char server_ip[INET_ADDRSTRLEN];
 	int server_port;
 	int vhost_client;
@@ -70,11 +70,11 @@ static void
 usage(const char *progname)
 {
 	RTE_LOG(INFO, APP, "Usage: %s [EAL args] --"
-			" --process-id PROC_ID"
+			" --client-id CLIENT_ID"
 			" [--config CONFIG_FILE_PATH]"
 			" -s SERVER_IP:SERVER_PORT"
 			" [--vhost-client]\n"
-			" --process-id PROCESS_ID   : My process ID\n"
+			" --client-id CLIENT_ID   : My client ID\n"
 			" --config CONFIG_FILE_PATH : specific config file path\n"
 			" -s SERVER_IP:SERVER_PORT  : Access information to the server\n"
 			" --vhost-client            : Run vhost on client\n"
@@ -252,23 +252,23 @@ stop_process(int signal) {
 }
 
 /*
- * Parses the process ID of the application argument.
+ * Parses the client ID of the application argument.
  */
 static int
-parse_app_process_id(const char *process_id_str, int *process_id)
+parse_app_client_id(const char *client_id_str, int *client_id)
 {
 	int id = 0;
 	char *endptr = NULL;
 
-	id = strtol(process_id_str, &endptr, 0);
-	if (unlikely(process_id_str == endptr) || unlikely(*endptr != '\0'))
+	id = strtol(client_id_str, &endptr, 0);
+	if (unlikely(client_id_str == endptr) || unlikely(*endptr != '\0'))
 		return -1;
 
-	if (id >= SPP_PROCESS_MAX)
+	if (id >= SPP_CLIENT_MAX)
 		return -1;
 
-	*process_id = id;
-	RTE_LOG(DEBUG, APP, "Set process id = %d\n", *process_id);
+	*client_id = id;
+	RTE_LOG(DEBUG, APP, "Set client id = %d\n", *client_id);
 	return 0;
 }
 
@@ -314,7 +314,7 @@ parse_app_args(int argc, char *argv[])
 	const char *progname = argv[0];
 	static struct option lgopts[] = { 
 			{ "config", required_argument, NULL, SPP_LONGOPT_RETVAL_CONFIG },
-			{ "process-id", required_argument, NULL, SPP_LONGOPT_RETVAL_PROCESS_ID },
+			{ "client-id", required_argument, NULL, SPP_LONGOPT_RETVAL_CLIENT_ID },
 			{ "vhost-client", no_argument, NULL, SPP_LONGOPT_RETVAL_VHOST_CLIENT },
 			{ 0 },
 	};
@@ -340,8 +340,8 @@ parse_app_args(int argc, char *argv[])
 			}
 			strcpy(config_file_path, optarg);
 			break;
-		case SPP_LONGOPT_RETVAL_PROCESS_ID:
-			if (parse_app_process_id(optarg, &g_startup_param.process_id) != 0) {
+		case SPP_LONGOPT_RETVAL_CLIENT_ID:
+			if (parse_app_client_id(optarg, &g_startup_param.client_id) != 0) {
 				usage(progname);
 				return -1;
 			}
@@ -370,8 +370,8 @@ parse_app_args(int argc, char *argv[])
 		usage(progname);
 		return -1;
 	}
-	RTE_LOG(INFO, APP, "application arguments value. (process id = %d, config = %s, server = %s:%d, vhost client = %d)\n",
-			g_startup_param.process_id,
+	RTE_LOG(INFO, APP, "application arguments value. (client id = %d, config = %s, server = %s:%d, vhost client = %d)\n",
+			g_startup_param.client_id,
 			config_file_path,
 			g_startup_param.server_ip,
 			g_startup_param.server_port,
@@ -978,12 +978,12 @@ ut_main(int argc, char *argv[])
 }
 
 /*
- * Get process ID
+ * Get client ID
  */
 int
-spp_get_process_id(void)
+spp_get_client_id(void)
 {
-	return g_startup_param.process_id;
+	return g_startup_param.client_id;
 }
 
 /*
diff --git a/src/vf/spp_vf.h b/src/vf/spp_vf.h
index bbdb904..b0da048 100644
--- a/src/vf/spp_vf.h
+++ b/src/vf/spp_vf.h
@@ -4,7 +4,7 @@
 #include "common.h"
 #include "spp_config.h"
 
-#define SPP_PROCESS_MAX 128
+#define SPP_CLIENT_MAX 128
 
 /*
  * State on core
@@ -60,10 +60,10 @@ struct spp_core_info {
 };
 
 /*
- * Get process ID
- * RETURN : PROCESS ID(0~127)
+ * Get client ID
+ * RETURN : CLIENT ID(0~127)
  */
-int spp_get_process_id(void);
+int spp_get_client_id(void);
 
 /*
  * Update Classifier_table
-- 
1.9.1

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

* [spp] [PATCH 43/57] spp_vf: update command decode procedure
  2017-12-26  1:54 ` Yasufumi Ogawa
                     ` (41 preceding siblings ...)
  2017-12-28  4:55   ` [spp] [PATCH 42/57] spp_vf: change how to request commands x-fn-spp
@ 2017-12-28  4:55   ` x-fn-spp
  2017-12-28  4:55   ` [spp] [PATCH 44/57] spp_vf: remove debug log output procedures x-fn-spp
                     ` (13 subsequent siblings)
  56 siblings, 0 replies; 97+ messages in thread
From: x-fn-spp @ 2017-12-28  4:55 UTC (permalink / raw)
  To: spp

From: Hiroyuki Nakamura <nakamura.hioryuki@po.ntt-tx.co.jp>

update command decode procedures due to the change of
command request format (fix bugs caused by the change.)

* Fix bugs in comditional statements and loop index.
* Fix index of received character array.
* Add initializeion of received commands counter.

Signed-off-by: Kentaro Watanabe <watanabe.kentaro.z01@as.ntt-tx.co.jp>
Signed-off-by: Yasufum Ogawa <ogawa.yasufumi@lab.ntt.co.jp>
---
 src/vf/command_dec.c  | 21 ++++++++++++---------
 src/vf/command_proc.c |  6 ++----
 2 files changed, 14 insertions(+), 13 deletions(-)

diff --git a/src/vf/command_dec.c b/src/vf/command_dec.c
index 468702f..75619d9 100644
--- a/src/vf/command_dec.c
+++ b/src/vf/command_dec.c
@@ -63,7 +63,7 @@ static int
 get_arrary_index(const char *match, const char *list[])
 {
 	int i;
-	for (i = 0; list[i][0] == '\0'; i++) {
+	for (i = 0; list[i][0] != '\0'; i++) {
 		if (strcmp(list[i], match) == 0)
 			return i;
 	}
@@ -113,7 +113,7 @@ decode_classifier_type_value(void *output, const char *arg_val)
 {
         int ret = 0;
 	ret = get_arrary_index(arg_val, CLASSIFILER_TYPE_STRINGS);
-        if (unlikely(ret < 0)) {
+        if (unlikely(ret <= 0)) {
                 RTE_LOG(ERR, SPP_COMMAND_PROC, "Unknown classifier type. val=%s\n", arg_val);
                 return -1;
         }
@@ -196,13 +196,14 @@ check_comand_argment_in_list(struct spp_command_request *request,
 	int ci = request->commands[0].type;
 	int pi = 0;
 	static struct decode_parameter_list *list = NULL;
-	for(pi = 1; pi < argc-1; pi++) {
-		list = &parameter_list[ci][pi];
+	for(pi = 1; pi < argc; pi++) {
+		list = &parameter_list[ci][pi-1];
+RTE_LOG(ERR, SPP_COMMAND_PROC, "TEST: command=%s, name=%s, index=%d, value=%s\n", argv[0], list->name, pi, argv[pi]);
 		ret = (*list->func)((void *)((char*)&request->commands[0]+list->offset), argv[pi]);
 		if (unlikely(ret < 0)) {
 			RTE_LOG(ERR, SPP_COMMAND_PROC,
-					"Bad value. command = %s, name=%s, index=%d\n",
-					argv[0], list->name, pi);
+					"Bad value. command=%s, name=%s, index=%d, value=%s\n",
+					argv[0], list->name, pi, argv[pi]);
 			return set_string_value_decode_error(error, argv[pi], list->name);
 		}
 	}
@@ -241,8 +242,6 @@ decode_command_argment(struct spp_command_request *request,
 	memset(argv, 0x00, sizeof(argv));
 	memset(tmp_str, 0x00, sizeof(tmp_str));
 
-	request->num_command = 1;
-
 	strcpy(tmp_str, request_str);
 	decode_argument_value(tmp_str, &argc, argv);
 	RTE_LOG(DEBUG, SPP_COMMAND_PROC, "Decode array. num=%d\n", argc);
@@ -279,14 +278,18 @@ spp_command_decode_request(struct spp_command_request *request, const char *requ
 	int ret = -1;
 	int i;
 
+RTE_LOG(ERR, SPP_COMMAND_PROC, "ERROR:request_str=%s\n", request_str);
 	/* decode request */
+	request->num_command = 1;
 	ret = decode_command_argment(request, request_str, error);
-	if (unlikely(ret < 0)) {
+	if (unlikely(ret != 0)) {
 		RTE_LOG(ERR, SPP_COMMAND_PROC, "Cannot decode command request. "
 				"ret=%d, request_str=%.*s\n", 
 				ret, (int)request_str_len, request_str);
 		return ret;
 	}
+	request->num_valid_command = 1;
+RTE_LOG(ERR, SPP_COMMAND_PROC, "ERROR:command type=%d\n", request->commands[0].type);
 
 	/* check getter command */
 	for (i = 0; i < request->num_valid_command; ++i) {
diff --git a/src/vf/command_proc.c b/src/vf/command_proc.c
index 0dd1d56..ef1ae81 100644
--- a/src/vf/command_proc.c
+++ b/src/vf/command_proc.c
@@ -462,7 +462,6 @@ spp_command_proc_do(void)
 
 	static int sock = -1;
 	static char *msgbuf = NULL;
-	static size_t msg_len = 0;
 
 	if (unlikely(msgbuf == NULL)) {
 		msgbuf = spp_strbuf_allocate(CMD_REQ_BUF_INIT_SIZE);
@@ -487,9 +486,8 @@ spp_command_proc_do(void)
 			return -1;
 	}
 
-	msg_len += (msg_ret + 1);
-	ret = process_request(&sock, msgbuf, msg_len);
-	spp_strbuf_remove_front(msgbuf, msg_len);
+	ret = process_request(&sock, msgbuf, msg_ret);
+	spp_strbuf_remove_front(msgbuf, msg_ret);
 
 	return 0;
 }
-- 
1.9.1

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

* [spp] [PATCH 44/57] spp_vf: remove debug log output procedures
  2017-12-26  1:54 ` Yasufumi Ogawa
                     ` (42 preceding siblings ...)
  2017-12-28  4:55   ` [spp] [PATCH 43/57] spp_vf: update command decode procedure x-fn-spp
@ 2017-12-28  4:55   ` x-fn-spp
  2017-12-28  4:55   ` [spp] [PATCH 45/57] spp_vf: improve command_decoder program code x-fn-spp
                     ` (12 subsequent siblings)
  56 siblings, 0 replies; 97+ messages in thread
From: x-fn-spp @ 2017-12-28  4:55 UTC (permalink / raw)
  To: spp

From: Hiroyuki Nakamura <nakamura.hioryuki@po.ntt-tx.co.jp>

Remove procedures for logging information used for debug
since they are for debug only.

Signed-off-by: Kentaro Watanabe <watanabe.kentaro.z01@as.ntt-tx.co.jp>
Signed-off-by: Yasufum Ogawa <ogawa.yasufumi@lab.ntt.co.jp>
---
 src/vf/command_dec.c | 3 ---
 1 file changed, 3 deletions(-)

diff --git a/src/vf/command_dec.c b/src/vf/command_dec.c
index 75619d9..c09a342 100644
--- a/src/vf/command_dec.c
+++ b/src/vf/command_dec.c
@@ -198,7 +198,6 @@ check_comand_argment_in_list(struct spp_command_request *request,
 	static struct decode_parameter_list *list = NULL;
 	for(pi = 1; pi < argc; pi++) {
 		list = &parameter_list[ci][pi-1];
-RTE_LOG(ERR, SPP_COMMAND_PROC, "TEST: command=%s, name=%s, index=%d, value=%s\n", argv[0], list->name, pi, argv[pi]);
 		ret = (*list->func)((void *)((char*)&request->commands[0]+list->offset), argv[pi]);
 		if (unlikely(ret < 0)) {
 			RTE_LOG(ERR, SPP_COMMAND_PROC,
@@ -278,7 +277,6 @@ spp_command_decode_request(struct spp_command_request *request, const char *requ
 	int ret = -1;
 	int i;
 
-RTE_LOG(ERR, SPP_COMMAND_PROC, "ERROR:request_str=%s\n", request_str);
 	/* decode request */
 	request->num_command = 1;
 	ret = decode_command_argment(request, request_str, error);
@@ -289,7 +287,6 @@ RTE_LOG(ERR, SPP_COMMAND_PROC, "ERROR:request_str=%s\n", request_str);
 		return ret;
 	}
 	request->num_valid_command = 1;
-RTE_LOG(ERR, SPP_COMMAND_PROC, "ERROR:command type=%d\n", request->commands[0].type);
 
 	/* check getter command */
 	for (i = 0; i < request->num_valid_command; ++i) {
-- 
1.9.1

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

* [spp] [PATCH 45/57] spp_vf: improve command_decoder program code
  2017-12-26  1:54 ` Yasufumi Ogawa
                     ` (43 preceding siblings ...)
  2017-12-28  4:55   ` [spp] [PATCH 44/57] spp_vf: remove debug log output procedures x-fn-spp
@ 2017-12-28  4:55   ` x-fn-spp
  2017-12-28  4:55   ` [spp] [PATCH 46/57] spp_vf: fix a bug in status command x-fn-spp
                     ` (11 subsequent siblings)
  56 siblings, 0 replies; 97+ messages in thread
From: x-fn-spp @ 2017-12-28  4:55 UTC (permalink / raw)
  To: spp

From: Hiroyuki Nakamura <nakamura.hioryuki@po.ntt-tx.co.jp>

* Add procedure for error log output
* Add parameter check procedure
* Correct wording (argument->parameter)
* Change strtol to stortol_r.
* Change return type of decode_parameter_value from static void
  to static int.
* Fix typos.

Signed-off-by: Kentaro Watanabe <watanabe.kentaro.z01@as.ntt-tx.co.jp>
Signed-off-by: Yasufum Ogawa <ogawa.yasufumi@lab.ntt.co.jp>
---
 src/vf/command_dec.c | 61 +++++++++++++++++++++++++++++++---------------------
 1 file changed, 37 insertions(+), 24 deletions(-)

diff --git a/src/vf/command_dec.c b/src/vf/command_dec.c
index c09a342..9363b8f 100644
--- a/src/vf/command_dec.c
+++ b/src/vf/command_dec.c
@@ -41,21 +41,26 @@ set_string_value_decode_error(struct spp_command_decode_error *error,
 	return set_decode_error(error, SPP_CMD_DERR_BAD_VALUE, error_name);
 }
 
-/* Split command line arguments with spaces */
-static void
-decode_argument_value(char *string, int *argc, char *argv[])
+/* Split command line parameter with spaces */
+static int
+decode_parameter_value(char *string, int max, int *argc, char *argv[])
 {
 	int cnt = 0;
 	const char *delim = " ";
 	char *argv_tok = NULL;
+	char *saveptr = NULL;
 
-	argv_tok = strtok(string, delim);
+	argv_tok = strtok_r(string, delim, &saveptr);
 	while(argv_tok != NULL) {
+		if (cnt >= max)
+			return -1;
 		argv[cnt] = argv_tok;
 		cnt++;
-		argv_tok = strtok(NULL, delim);
+		argv_tok = strtok_r(NULL, delim, &saveptr);
 	}
 	*argc = cnt;
+
+	return 0;
 }
 
 /* Get index of array */
@@ -124,7 +129,7 @@ decode_classifier_type_value(void *output, const char *arg_val)
 
 /* decode procedure for classifier value */
 static int
-decode_classifiert_value_value(void *output, const char *arg_val)
+decode_classifier_value_value(void *output, const char *arg_val)
 {
         int ret = -1;
 	struct spp_command_classifier_table *classifier_table = output;
@@ -153,6 +158,8 @@ decode_classifier_port_value(void *output, const char *arg_val)
 	return decode_port_value(port, arg_val);
 }
 
+#define DECODE_PARAMETER_LIST_EMPTY { NULL, 0, NULL }
+
 /* parameter list for decoding */
 struct decode_parameter_list {
         const char *name;
@@ -162,7 +169,7 @@ struct decode_parameter_list {
 
 /* parameter list for each command */
 static struct decode_parameter_list parameter_list[][SPP_CMD_MAX_PARAMETERS] = {
-	{                      /* classifier_table */
+	{                                /* classifier_table */
 		{
 			.name = "type",
 			.offset = offsetof(struct spp_command, spec.classifier_table.type),
@@ -171,24 +178,24 @@ static struct decode_parameter_list parameter_list[][SPP_CMD_MAX_PARAMETERS] = {
 		{
 			.name = "value",
 			.offset = offsetof(struct spp_command, spec.classifier_table),
-			.func = decode_classifiert_value_value
+			.func = decode_classifier_value_value
 		},
 		{
 			.name = "port",
 			.offset = offsetof(struct spp_command, spec.classifier_table.port),
 			.func = decode_classifier_port_value
 		},
-		{ NULL, 0, NULL },
+		DECODE_PARAMETER_LIST_EMPTY,
 	},
-	{ { NULL, 0, NULL } }, /* flush            */
-	{ { NULL, 0, NULL } }, /* _get_client_id   */
-	{ { NULL, 0, NULL } }, /* status           */
-	{ { NULL, 0, NULL } }, /* termination      */
+	{ DECODE_PARAMETER_LIST_EMPTY }, /* flush            */
+	{ DECODE_PARAMETER_LIST_EMPTY }, /* _get_client_id   */
+	{ DECODE_PARAMETER_LIST_EMPTY }, /* status           */
+	{ DECODE_PARAMETER_LIST_EMPTY }, /* termination      */
 };
 
-/* check by list for each command line argument */
+/* check by list for each command line parameter */
 static int
-check_comand_argment_in_list(struct spp_command_request *request,
+decode_comand_parameter_in_list(struct spp_command_request *request,
 				int argc, char *argv[],
 				struct spp_command_decode_error *error)
 {
@@ -220,19 +227,20 @@ struct decode_command_list {
 
 /* command list */
 static struct decode_command_list command_list[] = {
-	{ "classifier_table", 4, 4, check_comand_argment_in_list }, /* classifier_table */
-	{ "flush",            1, 1, NULL                         }, /* flush            */
-	{ "_get_client_id",   1, 1, NULL                         }, /* _get_client_id   */
-	{ "status",           1, 1, NULL                         }, /* status           */
-	{ "",                 0, 0, NULL                         }  /* termination      */
+	{ "classifier_table", 4, 4, decode_comand_parameter_in_list }, /* classifier_table */
+	{ "flush",            1, 1, NULL                            }, /* flush            */
+	{ "_get_client_id",   1, 1, NULL                            }, /* _get_client_id   */
+	{ "status",           1, 1, NULL                            }, /* status           */
+	{ "",                 0, 0, NULL                            }  /* termination      */
 };
 
-/* Decode command line arguments */
+/* Decode command line parameters */
 static int
-decode_command_argment(struct spp_command_request *request,
+decode_command_in_list(struct spp_command_request *request,
 			const char *request_str,
 			struct spp_command_decode_error *error)
 {
+	int ret = 0;
 	struct decode_command_list *list = NULL;
 	int i = 0;
 	int argc = 0;
@@ -242,7 +250,12 @@ decode_command_argment(struct spp_command_request *request,
 	memset(tmp_str, 0x00, sizeof(tmp_str));
 
 	strcpy(tmp_str, request_str);
-	decode_argument_value(tmp_str, &argc, argv);
+	ret = decode_parameter_value(tmp_str, SPP_CMD_MAX_PARAMETERS, &argc, argv);
+	if (ret < 0) {
+		RTE_LOG(ERR, SPP_COMMAND_PROC, "Parameter number over limit."
+				"request_str=%s\n", request_str);
+		return set_decode_error(error, SPP_CMD_DERR_BAD_FORMAT, NULL);
+	}
 	RTE_LOG(DEBUG, SPP_COMMAND_PROC, "Decode array. num=%d\n", argc);
 
 	for (i = 0; command_list[i].name[0] != '\0'; i++) {
@@ -279,7 +292,7 @@ spp_command_decode_request(struct spp_command_request *request, const char *requ
 
 	/* decode request */
 	request->num_command = 1;
-	ret = decode_command_argment(request, request_str, error);
+	ret = decode_command_in_list(request, request_str, error);
 	if (unlikely(ret != 0)) {
 		RTE_LOG(ERR, SPP_COMMAND_PROC, "Cannot decode command request. "
 				"ret=%d, request_str=%.*s\n", 
-- 
1.9.1

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

* [spp] [PATCH 46/57] spp_vf: fix a bug in status command
  2017-12-26  1:54 ` Yasufumi Ogawa
                     ` (44 preceding siblings ...)
  2017-12-28  4:55   ` [spp] [PATCH 45/57] spp_vf: improve command_decoder program code x-fn-spp
@ 2017-12-28  4:55   ` x-fn-spp
  2017-12-28  4:55   ` [spp] [PATCH 47/57] spp_vf: add spp_vf.py instead of spp.py x-fn-spp
                     ` (10 subsequent siblings)
  56 siblings, 0 replies; 97+ messages in thread
From: x-fn-spp @ 2017-12-28  4:55 UTC (permalink / raw)
  To: spp

From: Hiroyuki Nakamura <nakamura.hioryuki@po.ntt-tx.co.jp>

Fix the problem that the default port set by classifier_table command
is not displayed with the status command.

Signed-off-by: Kentaro Watanabe <watanabe.kentaro.z01@as.ntt-tx.co.jp>
Signed-off-by: Yasufum Ogawa <ogawa.yasufumi@lab.ntt.co.jp>
---
 src/vf/classifier_mac.c | 11 +++++++++++
 1 file changed, 11 insertions(+)

diff --git a/src/vf/classifier_mac.c b/src/vf/classifier_mac.c
index 9769b30..a088040 100644
--- a/src/vf/classifier_mac.c
+++ b/src/vf/classifier_mac.c
@@ -554,6 +554,17 @@ int spp_classifier_mac_iterate_table(
 		RTE_LOG(DEBUG, SPP_CLASSIFIER_MAC,
 			"Core[%u] Start iterate classifier table.\n", i);
 
+		if (classifier_info->default_classified >= 0) {
+			port.if_type = (classified_data + classifier_info->default_classified)->if_type;
+			port.if_no   = (classified_data + classifier_info->default_classified)->if_no_global;
+
+			(*params->element_proc)(
+					params->opaque,
+					SPP_CLASSIFIER_TYPE_MAC,
+					SPP_CONFIG_DEFAULT_CLASSIFIED_SPEC_STR,
+					&port);
+		}
+
 		while(1) {
 			ret = rte_hash_iterate(classifier_info->classifier_table,
 					&key, &data, &next);
-- 
1.9.1

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

* [spp] [PATCH 47/57] spp_vf: add spp_vf.py instead of spp.py
  2017-12-26  1:54 ` Yasufumi Ogawa
                     ` (45 preceding siblings ...)
  2017-12-28  4:55   ` [spp] [PATCH 46/57] spp_vf: fix a bug in status command x-fn-spp
@ 2017-12-28  4:55   ` x-fn-spp
  2017-12-28  4:55   ` [spp] [PATCH 48/57] spp_vf: refactor for commnets in spp_vf.c x-fn-spp
                     ` (9 subsequent siblings)
  56 siblings, 0 replies; 97+ messages in thread
From: x-fn-spp @ 2017-12-28  4:55 UTC (permalink / raw)
  To: spp

From: Hiroyuki Nakamura <nakamura.hioryuki@po.ntt-tx.co.jp>

Add spp_vf.py as a modified version of spp.py.

Signed-off-by: Kentaro Watanabe <watanabe.kentaro.z01@as.ntt-tx.co.jp>
Signed-off-by: Yasufum Ogawa <ogawa.yasufumi@lab.ntt.co.jp>
---
 src/spp_vf.py | 443 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
 1 file changed, 443 insertions(+)
 create mode 100755 src/spp_vf.py

diff --git a/src/spp_vf.py b/src/spp_vf.py
new file mode 100755
index 0000000..40310db
--- /dev/null
+++ b/src/spp_vf.py
@@ -0,0 +1,443 @@
+#!/usr/bin/python
+"""Soft Patch Panel"""
+
+from __future__ import print_function
+from Queue import Queue
+from thread import start_new_thread
+from threading import Thread
+import cmd
+import getopt
+import select
+import socket
+import sys
+
+import json
+
+class GrowingList(list):
+    """GrowingList"""
+
+    def __setitem__(self, index, value):
+        if index >= len(self):
+            self.extend([None]*(index + 1 - len(self)))
+        list.__setitem__(self, index, value)
+
+MAX_SECONDARY = 16
+
+# init
+PRIMARY = ''
+SECONDARY_LIST = []
+SECONDARY_COUNT = 0
+
+#init primary comm channel
+MAIN2PRIMARY = Queue()
+PRIMARY2MAIN = Queue()
+
+#init secondary comm channel list
+MAIN2SEC = GrowingList()
+SEC2MAIN = GrowingList()
+
+def connectionthread(name, client_id, conn, m2s, s2m):
+    """Manage secondary process connections"""
+
+    cmd_str = 'hello'
+
+    #infinite loop so that function do not terminate and thread do not end.
+    while True:
+        try:
+            _, _, _ = select.select([conn,], [conn,], [], 5)
+        except select.error:
+            break
+
+        #Sending message to connected secondary
+        try:
+            cmd_str = m2s.get(True)
+            conn.send(cmd_str) #send only takes string
+        except KeyError:
+            break
+        except Exception, excep:
+            print (str(excep))
+            break
+
+        #Receiving from secondary
+        try:
+            data = conn.recv(1024) # 1024 stands for bytes of data to be received
+            if data:
+                s2m.put("recv:" + str(conn.fileno()) + ":" + "{" + data + "}")
+            else:
+                s2m.put("closing:" + str(conn))
+                break
+        except Exception, excep:
+            print (str(excep))
+            break
+
+    SECONDARY_LIST.remove(client_id)
+    conn.close()
+
+def getclientid(conn):
+    """Get client_id from client"""
+
+    try:
+        conn.send("_get_client_id")
+        #conn.send("{\"commands\":[{\"command\":\"process\"}]}")
+    except KeyError:
+        return -1
+
+    data = conn.recv(1024)
+    if data == None:
+        return -1
+
+    #client_id = int(data.strip('\0'))
+    json_dict = json.loads(data)
+    client_id = int(json_dict['client_id'])
+
+    if client_id < 0 or client_id > MAX_SECONDARY:
+        return -1
+
+    print ("secondary id %d" % client_id)
+    return client_id
+
+    found = 0
+    for i in SECONDARY_LIST:
+        if client_id == i:
+            found = 1
+            break
+
+    if found == 0:
+        return client_id
+
+    # client_id in use, find a free one
+    free_client_id = -1
+    for i in range(MAX_SECONDARY):
+        found = -1
+        for j in SECONDARY_LIST:
+            if i == j:
+                found = i
+                break
+        if found == -1:
+            free_client_id = i
+            break
+
+    if free_client_id < 0:
+        return -1
+
+    conn.send("_set_client_id %u" % free_client_id)
+    data = conn.recv(1024)
+
+    return free_client_id
+
+def acceptthread(sock, main2sec, sec2main):
+    """Listen for secondary processes"""
+
+    global SECONDARY_COUNT
+
+    try:
+        while True:
+            #Accepting incoming connections
+            conn, _ = sock.accept()
+
+            client_id = getclientid(conn)
+            if client_id < 0:
+                break
+
+            #Creating new thread.
+            #Calling secondarythread function for this function and passing
+            #conn as argument.
+
+            SECONDARY_LIST.append(client_id)
+            main2sec[client_id] = Queue()
+            sec2main[client_id] = Queue()
+            start_new_thread(connectionthread,
+                             ('secondary', client_id, conn,
+                              main2sec[client_id],
+                              sec2main[client_id], ))
+            SECONDARY_COUNT += 1
+    except Exception, excep:
+        print (str(excep))
+        sock.close()
+
+def command_primary(command):
+    """Send command to primary process"""
+
+    if PRIMARY:
+        MAIN2PRIMARY.put(command)
+        print (PRIMARY2MAIN.get(True))
+    else:
+        print ("primary not started")
+
+def command_secondary(sec_id, command):
+    """Send command to secondary process with sec_id"""
+
+    if sec_id in SECONDARY_LIST:
+        MAIN2SEC[sec_id].put(command)
+        print (SEC2MAIN[sec_id].get(True))
+    else:
+        print ("secondary id %d not exist" % sec_id)
+
+def print_status():
+    """Display information about connected clients"""
+
+    print ("Soft Patch Panel Status :")
+    print ("primary: %d" % PRIMARY)
+    print ("secondary count: %d" % len(SECONDARY_LIST))
+    for i in SECONDARY_LIST:
+        print ("Connected secondary id: %d" % i)
+
+def primarythread(sock, main2primary, primary2main):
+    """Manage primary process connection"""
+
+    global PRIMARY
+    cmd_str = ''
+
+    while True:
+        #waiting for connection
+        PRIMARY = False
+        conn, addr = sock.accept()
+        PRIMARY = True
+
+        while conn:
+            try:
+                _, _, _ = select.select([conn,], [conn,], [], 5)
+            except select.error:
+                break
+
+            #Sending message to connected primary
+            try:
+                cmd_str = main2primary.get(True)
+                conn.send(cmd_str) #send only takes string
+            except KeyError:
+                break
+            except Exception, excep:
+                print (str(excep))
+                break
+
+            #Receiving from primary
+            try:
+                data = conn.recv(1024) # 1024 stands for bytes of data to be received
+                if data:
+                    primary2main.put("recv:" + str(addr) + ":" + "{" + data + "}")
+                else:
+                    primary2main.put("closing:" + str(addr))
+                    conn.close()
+                    break
+            except Exception, excep:
+                print (str(excep))
+                break
+
+    print ("primary communication thread end")
+
+def close_all_secondary():
+    """Exit all secondary processes"""
+
+    return;
+
+    global SECONDARY_COUNT
+
+    tmp_list = []
+    for i in SECONDARY_LIST:
+        tmp_list.append(i)
+    for i in tmp_list:
+        command_secondary(i, 'exit')
+    SECONDARY_COUNT = 0
+
+def check_sec_cmds(cmds):
+    """Validate secondary commands before sending"""
+
+    return 1
+
+    level1 = ['status', 'exit', 'forward', 'stop']
+    level2 = ['add', 'patch', 'del']
+    patch_args = ['reset']
+    add_del_args = ['ring', 'vhost']
+    cmdlist = cmds.split(' ')
+    valid = 0
+
+    length = len(cmdlist)
+    if length == 1:
+        if cmdlist[0] in level1:
+            valid = 1
+    elif length == 2:
+        if cmdlist[0] == 'patch':
+            if cmdlist[1] in patch_args:
+                valid = 1
+    elif length == 3:
+        if cmdlist[0] in level2:
+            if cmdlist[0] == 'add' or cmdlist[0] == 'del':
+                if cmdlist[1] in add_del_args:
+                    if str.isdigit(cmdlist[2]):
+                        valid = 1
+            elif cmdlist[0] == 'patch':
+                if str.isdigit(cmdlist[1]) and str.isdigit(cmdlist[2]):
+                    valid = 1
+
+    return valid
+
+class Shell(cmd.Cmd):
+    """SPP command prompt"""
+
+    intro = 'Welcome to the spp.   Type help or ? to list commands.\n'
+    prompt = 'spp > '
+    recorded_file = None
+
+    COMMANDS = ['status', 'add', 'patch', 'ring', 'vhost',
+                'reset', 'exit', 'forward', 'stop', 'clear']
+
+    def complete_pri(self, text, line, begidx, endidx):
+        """Completion for primary process commands"""
+
+        if not text:
+            completions = self.COMMANDS[:]
+        else:
+            completions = [p
+                           for p in self.COMMANDS
+                           if p.startswith(text)
+                          ]
+        return completions
+
+    def complete_sec(self, text, line, begidx, endidx):
+        """Completion for secondary process commands"""
+
+        if not text:
+            completions = self.COMMANDS[:]
+        else:
+            completions = [p
+                           for p in self.COMMANDS
+                           if p.startswith(text)
+                          ]
+        return completions
+
+    def do_status(self, _):
+        """Display Soft Patch Panel Status"""
+
+        print_status()
+
+    def do_pri(self, command):
+        """Send command to primary process"""
+
+        if command and command in self.COMMANDS:
+            command_primary(command)
+        else:
+            print ("primary invalid command")
+
+    def do_sec(self, arg):
+        """Send command to secondary process"""
+
+        cmds = arg.split(';')
+        if len(cmds) < 2:
+            print ("error")
+        elif str.isdigit(cmds[0]):
+            sec_id = int(cmds[0])
+            if check_sec_cmds(cmds[1]):
+                command_secondary(sec_id, cmds[1])
+            else:
+                print ("invalid cmd")
+        else:
+            print (cmds[0])
+            print ("first %s" % cmds[1])
+
+    def do_record(self, arg):
+        """Save future commands to filename:  RECORD filename.cmd"""
+
+        self.recorded_file = open(arg, 'w')
+
+    def do_playback(self, arg):
+        """Playback commands from a file:  PLAYBACK filename.cmd"""
+
+        self.close()
+        try:
+            with open(arg) as recorded_file:
+                lines = []
+                for line in recorded_file:
+                    if line.strip().startswith("#"):
+                        continue
+                    lines.append(line)
+                self.cmdqueue.extend(lines)
+        except IOError:
+            print ("Error: File does not exist.")
+
+    def precmd(self, line):
+        line = line.lower()
+        if self.recorded_file and 'playback' not in line:
+            print(line, file=self.recorded_file)
+        return line
+
+    def close(self):
+        """Close record file"""
+
+        if self.recorded_file:
+            print("closing file")
+            self.recorded_file.close()
+            self.recorded_file = None
+
+    def do_bye(self, arg):
+        """Stop recording, close SPP, and exit: BYE"""
+
+        cmds = arg.split(' ')
+        if cmds[0] == 'sec':
+            close_all_secondary()
+        elif cmds[0] == 'all':
+            close_all_secondary()
+            command_primary('exit')
+        elif cmds[0] == '':
+            print('Thank you for using Soft Patch Panel')
+            self.close()
+            return True
+
+def main(argv):
+    """main"""
+
+    # Defining server address and port
+    host = ''  #'localhost' or '127.0.0.1' or '' are all same
+
+    try:
+        opts, _ = getopt.getopt(argv, "p:s:h", ["help", "primary = ", "secondary"])
+    except getopt.GetoptError:
+        print ('spp.py -p <primary__port_number> -s <secondary_port_number>')
+        sys.exit(2)
+    for opt, arg in opts:
+        if opt in ("-h", "--help"):
+            print ('spp.py -p <primary__port_number> -s <secondary_port_number>')
+            sys.exit()
+        elif opt in ("-p", "--primary"):
+            primary_port = int(arg)
+            print ("primary port : %d" % primary_port)
+        elif opt in ("-s", "--secondary"):
+            secondary_port = int(arg)
+            print ('secondary port : %d' % secondary_port)
+
+    #Creating primary socket object
+    primary_sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
+
+    #Binding primary socket to a address. bind() takes tuple of host and port.
+    primary_sock.bind((host, primary_port))
+
+    #Listening primary at the address
+    primary_sock.listen(1) #5 denotes the number of clients can queue
+
+    primary_thread = Thread(target=primarythread,
+                            args=(primary_sock, MAIN2PRIMARY, PRIMARY2MAIN,))
+    primary_thread.daemon = True
+    primary_thread.start()
+
+    #Creating secondary socket object
+    secondary_sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
+
+    #Binding secondary socket to a address. bind() takes tuple of host and port.
+    secondary_sock.bind((host, secondary_port))
+
+    #Listening secondary at the address
+    secondary_sock.listen(MAX_SECONDARY)
+
+    # secondary process handling thread
+    start_new_thread(acceptthread, (secondary_sock, MAIN2SEC, SEC2MAIN))
+
+    shell = Shell()
+    shell.cmdloop()
+    shell = None
+
+    primary_sock.shutdown(socket.SHUT_RDWR)
+    primary_sock.close()
+    secondary_sock.shutdown(socket.SHUT_RDWR)
+    secondary_sock.close()
+
+if __name__ == "__main__":
+    main(sys.argv[1:])
-- 
1.9.1

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

* [spp] [PATCH 48/57] spp_vf: refactor for commnets in spp_vf.c
  2017-12-26  1:54 ` Yasufumi Ogawa
                     ` (46 preceding siblings ...)
  2017-12-28  4:55   ` [spp] [PATCH 47/57] spp_vf: add spp_vf.py instead of spp.py x-fn-spp
@ 2017-12-28  4:55   ` x-fn-spp
  2017-12-28  4:55   ` [spp] [PATCH 49/57] spp_vf: refactor comments in classifier_mac.c x-fn-spp
                     ` (8 subsequent siblings)
  56 siblings, 0 replies; 97+ messages in thread
From: x-fn-spp @ 2017-12-28  4:55 UTC (permalink / raw)
  To: spp

From: Hiroyuki Nakamura <nakamura.hioryuki@po.ntt-tx.co.jp>

* Update remaining Japanese to English.
* Remove meaningless comments, for instance, 'Get client ID' for
  spp_get_client_id() or 'initialize' for init functions.
* Add suplementary comments for more understandable
* Add TODOs for futher revising.

Signed-off-by: Yasufumi Ogawa <ogawa.yasufumi@lab.ntt.co.jp>
---
 src/vf/spp_vf.c | 297 ++++++++++++++++++++++++++++----------------------------
 1 file changed, 147 insertions(+), 150 deletions(-)

diff --git a/src/vf/spp_vf.c b/src/vf/spp_vf.c
index 20a3b40..33373f5 100644
--- a/src/vf/spp_vf.c
+++ b/src/vf/spp_vf.c
@@ -12,7 +12,7 @@
 #include "spp_forward.h"
 #include "command_proc.h"
 
-/* define */
+/* TODO(yasufum) add desc how there are used */
 #define SPP_CORE_STATUS_CHECK_MAX 5
 #define SPP_RING_LATENCY_STATS_SAMPLING_INTERVAL 1000000
 
@@ -21,13 +21,13 @@ enum SPP_LONGOPT_RETVAL {
 	SPP_LONGOPT_RETVAL__ = 127,
 
 	/* add below */
-
+	/* TODO(yasufum) add description what and why add below */
 	SPP_LONGOPT_RETVAL_CONFIG,
 	SPP_LONGOPT_RETVAL_CLIENT_ID,
 	SPP_LONGOPT_RETVAL_VHOST_CLIENT
 };
 
-/* struct */
+/* Manage given options as global variable */
 struct startup_param {
 	int client_id;
 	char server_ip[INET_ADDRSTRLEN];
@@ -35,9 +35,10 @@ struct startup_param {
 	int vhost_client;
 };
 
+/* Status of patch and its cores, mac address assinged for it and port info */
 struct patch_info {
 	int      use_flg;
-	int      dpdk_port;
+	int      dpdk_port;  /* TODO(yasufum) add desc for what is this */
 	int      rx_core_no;
 	int      tx_core_no;
 	char     mac_addr_str[SPP_CONFIG_STR_LEN];
@@ -46,6 +47,8 @@ struct patch_info {
 	struct   spp_core_port_info *tx_core;
 };
 
+/* Manage number of interfaces and patch information  as global variable */
+/* TODO(yasufum) refactor, change if to iface */
 struct if_info {
 	int num_nic;
 	int num_vhost;
@@ -55,17 +58,16 @@ struct if_info {
 	struct patch_info ring_patchs[RTE_MAX_ETHPORTS];
 };
 
+/* Declare global variables */
 static struct spp_config_area	g_config;
 static struct startup_param	g_startup_param;
 static struct if_info		g_if_info;
 static struct spp_core_info	g_core_info[SPP_CONFIG_CORE_MAX];
-static int 			g_change_core[SPP_CONFIG_CORE_MAX];
+static int 			g_change_core[SPP_CONFIG_CORE_MAX];  /* TODO(yasufum) add desc how it is used and why changed core is kept */
 
 static char config_file_path[PATH_MAX];
 
-/*
- * print a usage message
- */
+/* Print help message */
 static void
 usage(const char *progname)
 {
@@ -81,16 +83,13 @@ usage(const char *progname)
 			, progname);
 }
 
-/*
- * Set RING PMD
- */
 static int
 add_ring_pmd(int ring_id)
 {
 	struct rte_ring *ring;
 	int ring_port_id;
 
-	/* look up ring, based on user's provided id*/
+	/* Lookup ring of given id */
 	ring = rte_ring_lookup(get_rx_queue_name(ring_id));
 	if (unlikely(ring == NULL)) {
 		RTE_LOG(ERR, APP,
@@ -98,16 +97,13 @@ add_ring_pmd(int ring_id)
 		return -1;
 	}
 
-	/* create ring pmd*/
+	/* Create ring pmd */
 	ring_port_id = rte_eth_from_ring(ring);
 	RTE_LOG(DEBUG, APP, "ring port id %d\n", ring_port_id);
 
 	return ring_port_id;
 }
 
-/*
- * Set VHOST PMD
- */
 static int
 add_vhost_pmd(int index, int client)
 {
@@ -187,27 +183,31 @@ add_vhost_pmd(int index, int client)
 	return vhost_port_id;
 }
 
-/*
- * Check core status
+/**
+ * Check status of all of cores is same as given
+ *
+ * It returns -1 as status mismatch if status is not same.
+ * If status is SPP_CONFIG_UNUSE, check is skipped.
  */
 static int
 check_core_status(enum spp_core_status status)
 {
-	int cnt;
+	int cnt;  /* increment core id */
 	for (cnt = 0; cnt < SPP_CONFIG_CORE_MAX; cnt++) {
 		if (g_core_info[cnt].type == SPP_CONFIG_UNUSE) {
 			continue;
 		}
 		if (g_core_info[cnt].status != status) {
-			/* Status mismatch */
+			/* Status is mismatched */
 			return -1;
 		}
 	}
 	return 0;
 }
 
-/*
- * Wait for core status check
+/**
+ * Run check_core_status() for SPP_CORE_STATUS_CHECK_MAX times with
+ * interval time (1sec)
  */
 static int
 check_core_status_wait(enum spp_core_status status)
@@ -225,34 +225,35 @@ check_core_status_wait(enum spp_core_status status)
 	return -1;
 }
 
-/*
- * Set core status
- */
+/* Set all core to given status */
 static void
 set_core_status(enum spp_core_status status)
 {
-	int core_cnt = 0;
+	int core_cnt = 0;  /* increment core id */
 	for(core_cnt = 0; core_cnt < SPP_CONFIG_CORE_MAX; core_cnt++) {
 		g_core_info[core_cnt].status = status;
 	}
 }
 
-/*
- * Process stop
+/**
+ * Set all of core status to SPP_CORE_STOP_REQUEST if received signal
+ * is SIGTERM or SIGINT
  */
 static void
 stop_process(int signal) {
 	if (unlikely(signal != SIGTERM) &&
 			unlikely(signal != SIGINT)) {
-		/* Other signals */
 		return;
 	}
 
 	set_core_status(SPP_CORE_STOP_REQUEST);
 }
 
-/*
- * Parses the client ID of the application argument.
+/**
+ * Convert string of given client id to inteter
+ *
+ * If succeeded, client id of interger is assigned to client_id and
+ * reuturn 0. Or return -1 if failed.
  */
 static int
 parse_app_client_id(const char *client_id_str, int *client_id)
@@ -272,9 +273,7 @@ parse_app_client_id(const char *client_id_str, int *client_id)
 	return 0;
 }
 
-/*
- * Parses server information of application arguments.
- */
+/* Parse options for server ip and port */
 static int
 parse_app_server(const char *server_str, char *server_ip, int *server_port)
 {
@@ -299,9 +298,7 @@ parse_app_server(const char *server_str, char *server_ip, int *server_port)
 	return 0;
 }
 
-/*
- * Parse the application arguments to the client app.
- */
+/* Parse options for client app */
 static int
 parse_app_args(int argc, char *argv[])
 {
@@ -319,7 +316,10 @@ parse_app_args(int argc, char *argv[])
 			{ 0 },
 	};
 
-	/* getoptを使用するとargvが並び変わるみたいなので、コピーを実施 */
+	/**
+	 * Save argv to argvopt to aovid loosing the order of options
+	 * by getopt_long()
+	 */
 	for (cnt = 0; cnt < argcopt; cnt++) {
 		argvopt[cnt] = argv[cnt];
 	}
@@ -327,7 +327,7 @@ parse_app_args(int argc, char *argv[])
 	/* Clear startup parameters */
 	memset(&g_startup_param, 0x00, sizeof(g_startup_param));
 
-	/* Check application parameter */
+	/* Check options of application */
 	optind = 0;
 	opterr = 0;
 	while ((opt = getopt_long(argc, argvopt, "s:", lgopts,
@@ -370,7 +370,8 @@ parse_app_args(int argc, char *argv[])
 		usage(progname);
 		return -1;
 	}
-	RTE_LOG(INFO, APP, "application arguments value. (client id = %d, config = %s, server = %s:%d, vhost client = %d)\n",
+	RTE_LOG(INFO, APP,
+			"app opts (client_id=%d,config=%s,server=%s:%d,vhost_client=%d)\n",
 			g_startup_param.client_id,
 			config_file_path,
 			g_startup_param.server_ip,
@@ -379,8 +380,13 @@ parse_app_args(int argc, char *argv[])
 	return 0;
 }
 
-/*
- * IF種別&IF番号のIF情報の領域取得
+/**
+ * Return patch info of given type and num of interface
+ *
+ * It returns NULL value if given type is invalid.
+ * TODO(yasufum) refactor name of func to be more understandable (area?)
+ * TODO(yasufum) refactor, change if to iface.
+ * TODO(yasufum) confirm why it returns not -1 but NULL.
  */
 static struct patch_info *
 get_if_area(enum port_type if_type, int if_no)
@@ -396,19 +402,20 @@ get_if_area(enum port_type if_type, int if_no)
 		return &g_if_info.ring_patchs[if_no];
 		break;
 	default:
-		/* エラー出力は呼び元でチェック */
 		return NULL;
 		break;
 	}
 }
 
-/*
- * IF情報初期化
+/**
+ * Initialize all of patch info by assingning -1
+ *
+ * TODO(yasufum) refactor, change if to iface.
  */
 static void
 init_if_info(void)
 {
-	int port_cnt;
+	int port_cnt;  /* increment ether ports */
 	memset(&g_if_info, 0x00, sizeof(g_if_info));
 	for (port_cnt = 0; port_cnt < RTE_MAX_ETHPORTS; port_cnt++) {
 		g_if_info.nic_patchs[port_cnt].rx_core_no   = -1;
@@ -420,8 +427,11 @@ init_if_info(void)
 	}
 }
 
-/*
- * CORE情報初期化
+/**
+ * Initialize g_core_info and its port info
+ *
+ * Clear g_core_info and set interface type of its port info to UNDEF.
+ * TODO(yasufum) refactor, change if to iface.
  */
 static void
 init_core_info(void)
@@ -438,13 +448,15 @@ init_core_info(void)
 	memset(g_change_core, 0x00, sizeof(g_change_core));
 }
 
-/*
- * Configのプロセス情報から管理情報に設定
+/**
+ * Set properties of g_core_info from config
+ *
+ * TODO(yasufum) refactor, change if to iface.
+ * TODO(yasufum) confirm meaning of funciton name and is typo ?
  */
 static int
 set_form_proc_info(struct spp_config_area *config)
 {
-	/* Configのproc_infoから内部管理情報へ設定 */
 	int core_cnt, rx_start, rx_cnt, tx_start, tx_cnt;
 	enum port_type if_type;
 	int if_no;
@@ -459,17 +471,17 @@ set_form_proc_info(struct spp_config_area *config)
 			continue;
 		}
 
-		/* Forwardをまとめる事は可、他種別は不可 */
-		if ((core_info->type != SPP_CONFIG_UNUSE) &&
-				((core_info->type != SPP_CONFIG_FORWARD) ||
-				(core_func->type != SPP_CONFIG_FORWARD))) {
-			RTE_LOG(ERR, APP, "Core in use. (core = %d, type = %d/%d)\n",
-					core_func->core_no,
-					core_func->type, core_info->type);
-			return -1;
-		}
+    /* Forwardをまとめる事は可、他種別は不可 */
+    /* TODO(yasufum) confirm what is the purpose and meaning */
+    if ((core_info->type != SPP_CONFIG_UNUSE) &&
+        ((core_info->type != SPP_CONFIG_FORWARD) ||
+         (core_func->type != SPP_CONFIG_FORWARD))) {
+      RTE_LOG(ERR, APP, "Core in use. (core = %d, type = %d/%d)\n",
+          core_func->core_no,
+          core_func->type, core_info->type);
+      return -1;
+    }
 
-		/* Set CORE type */
 		core_info->type = core_func->type;
 		if (!rte_lcore_is_enabled(core_func->core_no)) {
 			/* CPU mismatch */
@@ -478,7 +490,6 @@ set_form_proc_info(struct spp_config_area *config)
 			return -1;
 		}
 
-		/* Set RX port */
 		rx_start = core_info->num_rx_port;
 		core_info->num_rx_port += core_func->num_rx_port;
 		for (rx_cnt = 0; rx_cnt < core_func->num_rx_port; rx_cnt++) {
@@ -488,7 +499,7 @@ set_form_proc_info(struct spp_config_area *config)
 			core_info->rx_ports[rx_start + rx_cnt].if_type = if_type;
 			core_info->rx_ports[rx_start + rx_cnt].if_no   = if_no;
 
-			/* IF種別とIF番号に対応するIF情報の領域取得 */
+			/* Retrieve patch corresponding to type and number of the interface */
 			patch_info = get_if_area(if_type, if_no);
 
 			patch_info->use_flg = 1;
@@ -499,6 +510,7 @@ set_form_proc_info(struct spp_config_area *config)
 			}
 
 			/* IF情報からCORE情報を変更する場合用に設定 */
+      /* TODO(yasufum) confirm the meaning of this comment */
 			patch_info->rx_core_no = core_func->core_no;
 			patch_info->rx_core    = &core_info->rx_ports[rx_start + rx_cnt];
 		}
@@ -513,7 +525,6 @@ set_form_proc_info(struct spp_config_area *config)
 			core_info->tx_ports[tx_start + tx_cnt].if_type = if_type;
 			core_info->tx_ports[tx_start + tx_cnt].if_no   = if_no;
 
-			/* IF種別とIF番号に対応するIF情報の領域取得 */
 			patch_info = get_if_area(if_type, if_no);
 
 			patch_info->use_flg = 1;
@@ -524,6 +535,7 @@ set_form_proc_info(struct spp_config_area *config)
 			}
 
 			/* IF情報からCORE情報を変更する場合用に設定 */
+      /* TODO(yasufum) confirm the meaning of this comment */
 			patch_info->tx_core_no = core_func->core_no;
 			patch_info->tx_core    = &core_info->tx_ports[tx_start + tx_cnt];
 		}
@@ -532,13 +544,15 @@ set_form_proc_info(struct spp_config_area *config)
 	return 0;
 }
 
-/*
- * ConfigのMACテーブル情報から管理情報に設定
+/**
+ * Load mac table entries from config and setup patches
+ *
+ * TODO(yasufum) refactor, change if to iface.
+ * TODO(yasufum) confirm if additional description for the structure of mac table is needed.
  */
 static int
 set_from_classifier_table(struct spp_config_area *config)
 {
-	/* MAC table */
 	enum port_type if_type;
 	int if_no = 0;
 	int mac_cnt = 0;
@@ -550,7 +564,7 @@ set_from_classifier_table(struct spp_config_area *config)
 		if_type = mac_table->port.if_type;
 		if_no   = mac_table->port.if_no;
 
-		/* IF種別とIF番号に対応するIF情報の領域取得 */
+    /* Retrieve patch corresponding to type and number of the interface */
 		patch_info = get_if_area(if_type, if_no);
 
 		if (unlikely(patch_info->use_flg == 0)) {
@@ -559,8 +573,7 @@ set_from_classifier_table(struct spp_config_area *config)
 			return -1;
 		}
 
-		/* CORE情報側にもMACアドレスの情報設定 */
-		/* MACアドレスは送信側のみに影響する為、送信側のみ設定 */
+    /* Set mac address from the table for destination tx, not need for rx */
 		patch_info->mac_addr = mac_table->mac_addr;
 		strcpy(patch_info->mac_addr_str, mac_table->mac_addr_str);
 		if (unlikely(patch_info->tx_core != NULL)) {
@@ -571,8 +584,10 @@ set_from_classifier_table(struct spp_config_area *config)
 	return 0;
 }
 
-/*
- * NIC用の情報設定
+/**
+ * Setup patch info of port on host
+ *
+ * TODO(yasufum) refactor, change if to iface.
  */
 static int
 set_nic_interface(struct spp_config_area *config __attribute__ ((unused)))
@@ -587,15 +602,14 @@ set_nic_interface(struct spp_config_area *config __attribute__ ((unused)))
 	struct patch_info *patch_info = NULL;
 	for (nic_cnt = 0; nic_cnt < RTE_MAX_ETHPORTS; nic_cnt++) {
 		patch_info = &g_if_info.nic_patchs[nic_cnt];
-		/* Set DPDK port */
 		patch_info->dpdk_port = nic_cnt;
 
+    /* TODO(yasufum) confirm why it is needed */
 		if (patch_info->use_flg == 0) {
 			/* Not Used */
 			continue;
 		}
 
-		/* CORE情報側にもDPDKポート番号の情報設定 */
 		if (patch_info->rx_core != NULL) {
 			patch_info->rx_core->dpdk_port = nic_cnt;
 		}
@@ -603,7 +617,6 @@ set_nic_interface(struct spp_config_area *config __attribute__ ((unused)))
 			patch_info->tx_core->dpdk_port = nic_cnt;
 		}
 
-		/* NICの設定数カウント */
 		nic_num++;
 	}
 
@@ -612,17 +625,18 @@ set_nic_interface(struct spp_config_area *config __attribute__ ((unused)))
 				nic_num, g_if_info.num_nic);
 		return -1;
 	}
-	
+
 	return 0;
 }
 
-/*
- * VHOST用の情報設定
+/**
+ * Setup vhost interfaces from config
+ *
+ * TODO(yasufum) refactor, change if to iface.
  */
 static int
 set_vhost_interface(struct spp_config_area *config)
 {
-	/* VHOST Setting */
 	int vhost_cnt, vhost_num = 0;
 	g_if_info.num_vhost = config->proc.num_vhost;
 	struct patch_info *patch_info = NULL;
@@ -633,7 +647,6 @@ set_vhost_interface(struct spp_config_area *config)
 			continue;
 		}
 
-		/* Set DPDK port */
 		int dpdk_port = add_vhost_pmd(vhost_cnt, g_startup_param.vhost_client);
 		if (unlikely(dpdk_port < 0)) {
 			RTE_LOG(ERR, APP, "VHOST add failed. (no = %d)\n",
@@ -642,7 +655,6 @@ set_vhost_interface(struct spp_config_area *config)
 		}
 		patch_info->dpdk_port = dpdk_port;
 
-		/* CORE情報側にもDPDKポート番号の情報設定 */
 		if (patch_info->rx_core != NULL) {
 			patch_info->rx_core->dpdk_port = dpdk_port;
 		}
@@ -659,24 +671,26 @@ set_vhost_interface(struct spp_config_area *config)
 	return 0;
 }
 
-/*
- * RING用の情報設定
+/**
+ * Setup ring interfaces from config
+ *
+ * TODO(yasufum) refactor, change if to iface.
  */
 static int
 set_ring_interface(struct spp_config_area *config)
 {
-	/* RING Setting */
 	int ring_cnt, ring_num = 0;
 	g_if_info.num_ring = config->proc.num_ring;
 	struct patch_info *patch_info = NULL;
 	for (ring_cnt = 0; ring_cnt < RTE_MAX_ETHPORTS; ring_cnt++) {
 		patch_info = &g_if_info.ring_patchs[ring_cnt];
+
+    /* TODO(yasufum) confirm why it is needed */
 		if (patch_info->use_flg == 0) {
 			/* Not Used */
 			continue;
 		}
 
-		/* Set DPDK port */
 		int dpdk_port = add_ring_pmd(ring_cnt);
 		if (unlikely(dpdk_port < 0)) {
 			RTE_LOG(ERR, APP, "RING add failed. (no = %d)\n",
@@ -685,7 +699,6 @@ set_ring_interface(struct spp_config_area *config)
 		}
 		patch_info->dpdk_port = dpdk_port;
 
-		/* CORE情報側にもDPDKポート番号の情報設定 */
 		if (patch_info->rx_core != NULL) {
 			patch_info->rx_core->dpdk_port = dpdk_port;
 		}
@@ -702,60 +715,61 @@ set_ring_interface(struct spp_config_area *config)
 	return 0;
 }
 
-/*
- * 管理データ初期設定
+/**
+ * Setup management info for spp_vf
+ *
+ * TODO(yasufum) refactor, change if to iface.
+ * TODO(yasufum) refactor, change function name from manage to mng or management
  */
 static int
 init_manage_data(struct spp_config_area *config)
 {
-	/* Initialize */
+	/* Initialize interface and core infomation */
 	init_if_info();
 	init_core_info();
 
-	/* Set config data */
+  /* Load config for resource assingment and network configuration */
 	int ret_proc = set_form_proc_info(config);
 	if (unlikely(ret_proc != 0)) {
-		/* 関数内でログ出力済みなので、省略 */
 		return -1;
 	}
 	int ret_classifier = set_from_classifier_table(config);
 	if (unlikely(ret_classifier != 0)) {
-		/* 関数内でログ出力済みなので、省略 */
 		return -1;
 	}
 
-	/* Set interface data */
 	int ret_nic = set_nic_interface(config);
 	if (unlikely(ret_nic != 0)) {
-		/* 関数内でログ出力済みなので、省略 */
 		return -1;
 	}
 
 	int ret_vhost = set_vhost_interface(config);
 	if (unlikely(ret_vhost != 0)) {
-		/* 関数内でログ出力済みなので、省略 */
 		return -1;
 	}
 
 	int ret_ring = set_ring_interface(config);
 	if (unlikely(ret_ring != 0)) {
-		/* 関数内でログ出力済みなので、省略 */
 		return -1;
 	}
 
 	return 0;
 }
 
-#ifdef SPP_RINGLATENCYSTATS_ENABLE /* RING滞留時間 */
+#ifdef SPP_RINGLATENCYSTATS_ENABLE
+/**
+ * Print statistics of time for packet processing in ring interface
+ *
+ * TODO(yasufum) refactor, change if to iface.
+ */
 static void
 print_ring_latency_stats(void)
 {
-	/* Clear screen and move to top left */
+	/* Clear screen and move cursor to top left */
 	const char topLeft[] = { 27, '[', '1', ';', '1', 'H', '\0' };
 	const char clr[] = { 27, '[', '2', 'J', '\0' };
 	printf("%s%s", clr, topLeft);
 
-	/* Print per RING */
 	int ring_cnt, stats_cnt;
 	struct spp_ringlatencystats_ring_latency_stats stats[RTE_MAX_ETHPORTS];
 	memset(&stats, 0x00, sizeof(stats));
@@ -787,32 +801,30 @@ print_ring_latency_stats(void)
 }
 #endif /* SPP_RINGLATENCYSTATS_ENABLE */
 
-/*
- * VHOST用ソケットファイル削除
+/**
+ * Remove sock file
  */
 static void
 del_vhost_sockfile(struct patch_info *vhost_patchs)
 {
 	int cnt;
 
-	/* Do not delete for vhost client. */
+	/* Do not rmeove for if it is running in vhost-client mode. */
 	if (g_startup_param.vhost_client != 0)
 		return;
 
 	for (cnt = 0; cnt < RTE_MAX_ETHPORTS; cnt++) {
 		if (likely(vhost_patchs[cnt].use_flg == 0)) {
-			/* VHOST未使用はスキップ */
+			/* Skip removing if it is not using vhost */
 			continue;
 		}
 
-		/* 使用していたVHOSTについて削除を行う */
 		remove(get_vhost_iface_name(cnt));
 	}
 }
 
-/*
- * main
- */
+/* TODO(yasufum) refactor, change if to iface. */
+/* TODO(yasufum) change test using ut_main(), or add desccription for what and why use it */
 int
 #ifndef USE_UT_SPP_VF
 main(int argc, char *argv[])
@@ -834,25 +846,23 @@ ut_main(int argc, char *argv[])
 	signal(SIGTERM, stop_process);
 	signal(SIGINT,  stop_process);
 
-	/* set default config file path */
+	/* Setup config wiht default file path */
 	strcpy(config_file_path, SPP_CONFIG_FILE_PATH);
 
 	unsigned int main_lcore_id = 0xffffffff;
 	while(1) {
-		/* DPDK initialize */
 		int ret_dpdk = rte_eal_init(argc, argv);
 		if (unlikely(ret_dpdk < 0)) {
 			break;
 		}
 
-		/* Skip dpdk parameters */
 		argc -= ret_dpdk;
 		argv += ret_dpdk;
 
 		/* Set log level  */
 		rte_log_set_global_level(RTE_LOG_LEVEL);
 
-		/* Parse application parameters */
+		/* Parse spp_vf specific parameters */
 		int ret_parse = parse_app_args(argc, argv);
 		if (unlikely(ret_parse != 0)) {
 			break;
@@ -860,30 +870,25 @@ ut_main(int argc, char *argv[])
 
 		RTE_LOG(INFO, APP, "Load config file(%s)\n", config_file_path);
 
-		/* Load config */
 		int ret_config = spp_config_load_file(config_file_path, 0, &g_config);
 		if (unlikely(ret_config != 0)) {
 			break;
 		}
 
-		/* Get core id. */
+		/* Get lcore id of main thread to set its status after */
 		main_lcore_id = rte_lcore_id();
 
-		/* 起動パラメータとコンフィグチェック */
-		/* 各IF情報設定 */
 		int ret_manage = init_manage_data(&g_config);
 		if (unlikely(ret_manage != 0)) {
 			break;
 		}
 
-		/* 他機能部初期化 */
-		/* MAC振分初期化 */
 		int ret_classifier_mac_init = spp_classifier_mac_init();
 		if (unlikely(ret_classifier_mac_init != 0)) {
 			break;
 		}
 
-		/* コマンド機能部初期化 */
+    /* Setup connection for accepting commands from controller */
 		int ret_command_init = spp_command_proc_init(
 				g_startup_param.server_ip,
 				g_startup_param.server_port);
@@ -891,7 +896,7 @@ ut_main(int argc, char *argv[])
 			break;
 		}
 
-#ifdef SPP_RINGLATENCYSTATS_ENABLE /* RING滞留時間 */
+#ifdef SPP_RINGLATENCYSTATS_ENABLE
 		int ret_ringlatency = spp_ringlatencystats_init(
 				SPP_RING_LATENCY_STATS_SAMPLING_INTERVAL, g_if_info.num_ring);
 		if (unlikely(ret_ringlatency != 0)) {
@@ -899,7 +904,7 @@ ut_main(int argc, char *argv[])
 		}
 #endif /* SPP_RINGLATENCYSTATS_ENABLE */
 
-		/* Start  thread */
+		/* Start worker threads of classifier and forwarder */
 		unsigned int lcore_id = 0;
 		RTE_LCORE_FOREACH_SLAVE(lcore_id) {
 			if (g_core_info[lcore_id].type == SPP_CONFIG_CLASSIFIER_MAC) {
@@ -913,50 +918,48 @@ ut_main(int argc, char *argv[])
 			}
 		}
 
-		/* スレッド状態確認 */
+    /* Set the status of main thread to idle */
 		g_core_info[main_lcore_id].status = SPP_CORE_IDLE;
 		int ret_wait = check_core_status_wait(SPP_CORE_IDLE);
 		if (unlikely(ret_wait != 0)) {
 			break;
 		}
 
-		/* Start forward */
+		/* Start forwarding */
 		set_core_status(SPP_CORE_FORWARD);
 		RTE_LOG(INFO, APP, "My ID %d start handling message\n", 0);
 		RTE_LOG(INFO, APP, "[Press Ctrl-C to quit ...]\n");
 
-		/* loop */
+		/* Enter loop for accepting commands */
 		int ret_do = 0;
 #ifndef USE_UT_SPP_VF
 		while(likely(g_core_info[main_lcore_id].status != SPP_CORE_STOP_REQUEST)) {
 #else
 		{
 #endif
-			/* コマンド受付 */
+      /* Receive command */
 			ret_do = spp_command_proc_do();
 			if (unlikely(ret_do != 0)) {
 				break;
 			}
 
-			/* CPUを占有しない様に1秒スリープ */
 			sleep(1);
 
-#ifdef SPP_RINGLATENCYSTATS_ENABLE /* RING滞留時間 */
+#ifdef SPP_RINGLATENCYSTATS_ENABLE
 			print_ring_latency_stats();
 #endif /* SPP_RINGLATENCYSTATS_ENABLE */
 		}
 
-		/* エラー終了 */
+    /* TODO(yasufum) confirm, add why this check is needed because it is same the case of "ret = 0", or remove */
 		if (unlikely(ret_do != 0)) {
 			break;
 		}
 
-		/* 正常終了 */
 		ret = 0;
 		break;
 	}
 
-	/* exit */
+	/* Finalize to exit */
 	if (main_lcore_id == rte_lcore_id())
 	{
 		g_core_info[main_lcore_id].status = SPP_CORE_STOP;
@@ -965,29 +968,29 @@ ut_main(int argc, char *argv[])
 			RTE_LOG(ERR, APP, "Core did not stop.\n");
 		}
 
-		/* 使用していたVHOSTのソケットファイルを削除 */
+		/* Remove vhost sock file if it is not running in vhost-client mode */
 		del_vhost_sockfile(g_if_info.vhost_patchs);
 	}
 
-	/* 他機能部終了処理 */
-#ifdef SPP_RINGLATENCYSTATS_ENABLE /* RING滞留時間 */
+#ifdef SPP_RINGLATENCYSTATS_ENABLE
 	spp_ringlatencystats_uninit();
 #endif /* SPP_RINGLATENCYSTATS_ENABLE */
+
 	RTE_LOG(INFO, APP, "spp_vf exit.\n");
 	return ret;
 }
 
-/*
- * Get client ID
- */
 int
 spp_get_client_id(void)
 {
 	return g_startup_param.client_id;
 }
 
-/*
- * Check the MAC address used on the interface
+/**
+ * Check mac address used on the interface
+ *
+ * TODO(yasufum) refactor, change if to iface.
+ * TODO(yasufum) confirm, add the reason why this check is needed
  */
 static int
 check_mac_used_interface(uint64_t mac_addr, enum port_type *if_type, int *if_no)
@@ -1013,9 +1016,6 @@ check_mac_used_interface(uint64_t mac_addr, enum port_type *if_type, int *if_no)
 	return -1;
 }
 
-/*
- * Update Classifier_table
- */
 int
 spp_update_classifier_table(
 		enum spp_classifier_type type,
@@ -1103,18 +1103,16 @@ spp_update_classifier_table(
 		}
 	}
 
-	/* 更新コマンドで設定した場合、コア毎に変更有無を保持 */
+  /* TODO(yasufum) add desc how it is used and why changed core is kept */
 	g_change_core[patch_info->tx_core_no] = 1;
 	return SPP_RET_OK;
 }
 
-/*
- * Flush SPP component
- */
+/* Flush command to execute it */
 int
 spp_flush(void)
 {
-	int core_cnt = 0;
+	int core_cnt = 0;  /* increment core id */
 	int ret_classifier = 0;
 	struct spp_core_info *core_info = NULL;
 
@@ -1132,15 +1130,14 @@ spp_flush(void)
 		}
 	}
 
-	/* 更新完了により変更したコアをクリア */
+	/* Finally, zero-clear g_change_core */
 	memset(g_change_core, 0x00, sizeof(g_change_core));
 	return SPP_RET_OK;
 }
 
-/*
- * Iterate Classifier_table
- */
-int spp_iterate_classifier_table(struct spp_iterate_classifier_table_params *params)
+int
+spp_iterate_classifier_table(
+		struct spp_iterate_classifier_table_params *params)
 {
 	int ret;
 
-- 
1.9.1

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

* [spp] [PATCH 49/57] spp_vf: refactor comments in classifier_mac.c
  2017-12-26  1:54 ` Yasufumi Ogawa
                     ` (47 preceding siblings ...)
  2017-12-28  4:55   ` [spp] [PATCH 48/57] spp_vf: refactor for commnets in spp_vf.c x-fn-spp
@ 2017-12-28  4:55   ` x-fn-spp
  2017-12-28  4:55   ` [spp] [PATCH 50/57] spp_vf: refactor comments in spp_forward.c x-fn-spp
                     ` (7 subsequent siblings)
  56 siblings, 0 replies; 97+ messages in thread
From: x-fn-spp @ 2017-12-28  4:55 UTC (permalink / raw)
  To: spp

From: Hiroyuki Nakamura <nakamura.hioryuki@po.ntt-tx.co.jp>

* Add supplemental description for the reason why hash table count is
  needed.
* Add TODO for adding explanations of data structures.

Signed-off-by: Yasufumi Ogawa <ogawa.yasufumi@lab.ntt.co.jp>
---
 src/vf/classifier_mac.c | 12 ++++++++----
 1 file changed, 8 insertions(+), 4 deletions(-)

diff --git a/src/vf/classifier_mac.c b/src/vf/classifier_mac.c
index a088040..e2aa715 100644
--- a/src/vf/classifier_mac.c
+++ b/src/vf/classifier_mac.c
@@ -61,6 +61,8 @@ static const size_t HASH_TABLE_NAME_BUF_SZ =
 static const size_t ETHER_ADDR_STR_BUF_SZ =
 		ETHER_ADDR_LEN * 2 + (ETHER_ADDR_LEN - 1) + 1;
 
+/* TODO(yasufum) add explanation of data structure of classifier and mng info */
+
 /* classified data (destination port, target packets, etc) */
 struct classified_data {
 	enum port_type  if_type;
@@ -90,10 +92,12 @@ struct classifier_mac_mng_info {
 /* classifier information per lcore */
 static struct classifier_mac_mng_info g_classifier_mng_info[RTE_MAX_LCORE];
 
-/* hash table count. use to make hash table name.
-	[reason for value]
-		it is incremented at the time of use, 
-		but since we want to start at 0. */
+/**
+ * Hash table count used for making a name of hash table
+ *
+ * This function is required because it is incremented at the time of use,
+ * but since we want to start at 0.
+ */
 static rte_atomic16_t g_hash_table_count = RTE_ATOMIC16_INIT(0xff);
 
 static inline int
-- 
1.9.1

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

* [spp] [PATCH 50/57] spp_vf: refactor comments in spp_forward.c
  2017-12-26  1:54 ` Yasufumi Ogawa
                     ` (48 preceding siblings ...)
  2017-12-28  4:55   ` [spp] [PATCH 49/57] spp_vf: refactor comments in classifier_mac.c x-fn-spp
@ 2017-12-28  4:55   ` x-fn-spp
  2017-12-28  4:55   ` [spp] [PATCH 51/57] spp_vf: refactor for commnets in spp_config.c x-fn-spp
                     ` (6 subsequent siblings)
  56 siblings, 0 replies; 97+ messages in thread
From: x-fn-spp @ 2017-12-28  4:55 UTC (permalink / raw)
  To: spp

From: Hiroyuki Nakamura <nakamura.hioryuki@po.ntt-tx.co.jp>

* Update remaining Japanese to English.
* Add supplemental description for some of comments.

Signed-off-by: Yasufumi Ogawa <ogawa.yasufumi@lab.ntt.co.jp>
---
 src/vf/spp_forward.c | 32 +++++++++++++-------------------
 1 file changed, 13 insertions(+), 19 deletions(-)

diff --git a/src/vf/spp_forward.c b/src/vf/spp_forward.c
index e153e85..afe7c03 100644
--- a/src/vf/spp_forward.c
+++ b/src/vf/spp_forward.c
@@ -4,17 +4,13 @@
 
 #define RTE_LOGTYPE_FORWARD RTE_LOGTYPE_USER1
 
-/*
- * 送受信ポートの経路情報
- */
+/* A set of port info of rx and tx */
 struct rxtx {
 	struct spp_core_port_info rx;
 	struct spp_core_port_info tx;
 };
 
-/*
- * 使用するIF情報を移し替える
- */
+/* Set destination port as source */
 static void
 set_use_interface(struct spp_core_port_info *dst,
 		struct spp_core_port_info *src)
@@ -24,8 +20,11 @@ set_use_interface(struct spp_core_port_info *dst,
 	dst->dpdk_port = src->dpdk_port;
 }
 
-/*
- * Merge/Forward
+/**
+ * Forwarding packets as forwarder or merger
+ *
+ * Behavior of forwarding is defined as core_info->type which is given
+ * as an argument of void and typecasted to spp_config_info.
  */
 int
 spp_forward(void *arg)
@@ -35,23 +34,21 @@ spp_forward(void *arg)
 	int if_cnt, rxtx_num = 0;
 	struct rxtx patch[RTE_MAX_ETHPORTS];
 
-	/* RX/TX Info setting */
+  /* Decide the destination of forwarding */
 	rxtx_num = core_info->num_rx_port;
 	for (if_cnt = 0; if_cnt < rxtx_num; if_cnt++) {
 		set_use_interface(&patch[if_cnt].rx,
 				&core_info->rx_ports[if_cnt]);
+    /* Forwarding type is supposed to forwarder or merger */
 		if (core_info->type == SPP_CONFIG_FORWARD) {
-			/* FORWARD */
 			set_use_interface(&patch[if_cnt].tx,
 					&core_info->tx_ports[if_cnt]);
 		} else {
-			/* MERGE */
 			set_use_interface(&patch[if_cnt].tx,
 					&core_info->tx_ports[0]);
 		}
 	}
 
-	/* Thread IDLE */
 	core_info->status = SPP_CORE_IDLE;
 	RTE_LOG(INFO, FORWARD, "Core[%d] Start. (type = %d)\n", lcore_id,
 			core_info->type);
@@ -67,29 +64,27 @@ spp_forward(void *arg)
 				rx = &patch[cnt].rx;
 				tx = &patch[cnt].tx;
 
-				/* Packet receive */
+				/* Receive packets */
 				nb_rx = rte_eth_rx_burst(rx->dpdk_port, 0, bufs, MAX_PKT_BURST);
 				if (unlikely(nb_rx == 0)) {
 					continue;
 				}
 
-#ifdef SPP_RINGLATENCYSTATS_ENABLE /* RING滞留時間 */
+#ifdef SPP_RINGLATENCYSTATS_ENABLE
 				if (rx->if_type == RING) {
-					/* Receive port is RING */
 					spp_ringlatencystats_calculate_latency(rx->if_no,
 							bufs, nb_rx);
 				}
 				if (tx->if_type == RING) {
-					/* Send port is RING */
 					spp_ringlatencystats_add_time_stamp(tx->if_no,
 							bufs, nb_rx);
 				}
 #endif /* SPP_RINGLATENCYSTATS_ENABLE */
 
-				/* Send packet */
+				/* Send packets */
 				nb_tx = rte_eth_tx_burst(tx->dpdk_port, 0, bufs, nb_rx);
 
-				/* Free any unsent packets. */
+				/* Discard remained packets to release mbuf */
 				if (unlikely(nb_tx < nb_rx)) {
 					for (buf = nb_tx; buf < nb_rx; buf++) {
 						rte_pktmbuf_free(bufs[buf]);
@@ -99,7 +94,6 @@ spp_forward(void *arg)
 		}
 	}
 
-	/* Thread STOP */
 	RTE_LOG(INFO, FORWARD, "Core[%d] End. (type = %d)\n", lcore_id,
 			core_info->type);
 	core_info->status = SPP_CORE_STOP;
-- 
1.9.1

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

* [spp] [PATCH 51/57] spp_vf: refactor for commnets in spp_config.c
  2017-12-26  1:54 ` Yasufumi Ogawa
                     ` (49 preceding siblings ...)
  2017-12-28  4:55   ` [spp] [PATCH 50/57] spp_vf: refactor comments in spp_forward.c x-fn-spp
@ 2017-12-28  4:55   ` x-fn-spp
  2017-12-28  4:55   ` [spp] [PATCH 52/57] spp_vf: refactor no self-explanatory comments x-fn-spp
                     ` (5 subsequent siblings)
  56 siblings, 0 replies; 97+ messages in thread
From: x-fn-spp @ 2017-12-28  4:55 UTC (permalink / raw)
  To: spp

From: Hiroyuki Nakamura <nakamura.hioryuki@po.ntt-tx.co.jp>

* Update remaining Japanese to English.
* Remove meaningless comments, for instance, 'Get client ID' for
  spp_get_client_id() or 'initialize' for init functions.
* Add suplementary comments for more understandable
* Add TODOs for futher revising.
* Remove nouse whitespaces.

Signed-off-by: Yasufumi Ogawa <ogawa.yasufumi@lab.ntt.co.jp>
---
 src/vf/spp_config.c | 197 ++++++++++++++++++++++------------------------------
 1 file changed, 83 insertions(+), 114 deletions(-)

diff --git a/src/vf/spp_config.c b/src/vf/spp_config.c
index bca455c..55129ac 100644
--- a/src/vf/spp_config.c
+++ b/src/vf/spp_config.c
@@ -24,8 +24,12 @@
 #define JSONPATH_TX_PORT    "$.tx_port"
 #define JSONPATH_TX_TABLE   "$.tx_port_table"
 
-/*
+/**
  * Instead of json_path_get
+ *
+ * TODO(yasufum) confirm, add instead of what
+ * TODO(yasufum) confirm, add reason why this function is needed
+ * TODO(yasufum) confirm, add roles of obj, new_obj to make it more understandable
  */
 json_t *
 spp_config_get_path_obj(const json_t *json, const char *path)
@@ -74,69 +78,69 @@ spp_config_get_path_obj(const json_t *json, const char *path)
 	return new_obj;
 }
 
-/*
+/**
  * Get integer data from config
+ *
+ * If target is found, the result is assigned to argument 'value' and
+ * it reutrns 0, or returns -1 if not found.
  */
 static int
 config_get_int_value(const json_t *obj, const char *path, int *value)
 {
-	/* 指定パラメータのJsonオブジェクト取得 */
+	/* Use tmp to get target value of integer */
 	json_t *tmp_obj = spp_config_get_path_obj(obj, path);
 	if (unlikely(tmp_obj == NULL)) {
-		/* 必須でないデータを取得する場合を考慮し、DEBUGログとする。 */
+		/* For debugging, logging a case of null */
 		RTE_LOG(DEBUG, APP, "No parameter. (path = %s)\n", path);
 		return -1;
 	}
 
-	/* Integer type check */
 	if (unlikely(!json_is_integer(tmp_obj))) {
-		/* 必須でないデータを取得する場合を考慮し、DEBUGログとする。 */
+		/* For debugging, logging for other than target type */
 		RTE_LOG(DEBUG, APP, "Not an integer. (path = %s)\n", path);
 		return -1;
 	}
 
-	/* Set to OUT parameter */
 	*value = json_integer_value(tmp_obj);
 	RTE_LOG(DEBUG, APP, "get value = %d\n", *value);
 	return 0;
 }
 
 /*
- * Get String data from config
+ * Get string data from config
+ *
+ * If target is found, the result is assigned to argument 'value' and
+ * it reutrns 0, or returns -1 if not found.
  */
 static int
 config_get_str_value(const json_t *obj, const char *path, char *value)
 {
-	/* 指定パラメータのJsonオブジェクト取得 */
 	json_t *tmp_obj = spp_config_get_path_obj(obj, path);
 	if (unlikely(tmp_obj == NULL)) {
 		RTE_LOG(DEBUG, APP, "No parameter. (path = %s)\n", path);
 		return -1;
 	}
 
-	/* String type check */
 	if (unlikely(!json_is_string(tmp_obj))) {
+		/* For debugging, logging for other than target type */
 		RTE_LOG(DEBUG, APP, "Not a string. (path = %s)\n", path);
 		return -1;
 	}
 
-	/* Set to OUT parameter */
 	strcpy(value, json_string_value(tmp_obj));
 	RTE_LOG(DEBUG, APP, "get value = %s\n", value);
 	return 0;
 }
 
-/*
- * コンフィグ情報初期化
- */
+/* TODO(yasufum) change function name to be realized doing init, for instance, init_config_area()  */
 static void
 config_init_data(struct spp_config_area *config)
 {
-	/* 0クリア */
+  /* Clear config area with zero */
 	memset(config, 0x00, sizeof(struct spp_config_area));
 	int core_cnt, port_cnt, table_cnt;
 
-	/* IF種別初期設定 */
+  /* Set all of interface type of ports and mac tables to UNDEF */
 	for (core_cnt = 0; core_cnt < SPP_CONFIG_CORE_MAX; core_cnt++) {
 		for (port_cnt = 0; port_cnt < RTE_MAX_ETHPORTS; port_cnt++) {
 			config->proc.functions[core_cnt].rx_ports[port_cnt].if_type = UNDEF;
@@ -150,9 +154,13 @@ config_init_data(struct spp_config_area *config)
 	return;
 }
 
-/*
- * IFの情報からIF種別とIF番号を取得する
- * ("ring0" -> 種別:"ring"、番号:0)
+/**
+ * Sepeparate port id of combination of iface type and number and
+ * assign to given argment, if_type and if_no.
+ *
+ * For instance, 'ring:0' is separated to 'ring' and '0'.
+ *
+ * TODO(yasufum) change if to iface
  */
 int
 spp_config_get_if_info(const char *port, enum port_type *if_type, int *if_no)
@@ -161,7 +169,7 @@ spp_config_get_if_info(const char *port, enum port_type *if_type, int *if_no)
 	const char *no_str = NULL;
 	char *endptr = NULL;
 
-	/* IF type check */
+	/* Find out which type of interface from port */
 	if (strncmp(port, SPP_CONFIG_IFTYPE_NIC ":", strlen(SPP_CONFIG_IFTYPE_NIC)+1) == 0) {
 		/* NIC */
 		type = PHY;
@@ -180,7 +188,7 @@ spp_config_get_if_info(const char *port, enum port_type *if_type, int *if_no)
 		return -1;
 	}
 
-	/* IF番号を文字列から数値変換 */
+  /* Change type of number of interface */
 	int ret_no = strtol(no_str, &endptr, 0);
 	if (unlikely(no_str == endptr) || unlikely(*endptr != '\0')) { 
 		/* No IF number */
@@ -188,7 +196,6 @@ spp_config_get_if_info(const char *port, enum port_type *if_type, int *if_no)
 		return -1;
 	}
 
-	/* Set OUT parameter */
 	*if_type = type;
 	*if_no = ret_no;
 
@@ -197,8 +204,9 @@ spp_config_get_if_info(const char *port, enum port_type *if_type, int *if_no)
 	return 0;
 }
 
-/*
- * IF種別とIF番号からIF情報文字列を作成する
+/**
+ * Generate a formatted string of conbination from interface type and
+ * number and assign to given 'port'
  */
 int spp_config_format_port_string(char *port, enum port_type if_type, int if_no)
 {
@@ -223,8 +231,8 @@ int spp_config_format_port_string(char *port, enum port_type if_type, int if_no)
 	return 0;
 }
 
-/*
- * MAC addressを文字列から数値へ変換
+/**
+ * Change mac address of 'aa:bb:cc:dd:ee:ff' to int64 and return it
  */
 int64_t
 spp_config_change_mac_str_to_int64(const char *mac)
@@ -253,14 +261,14 @@ spp_config_change_mac_str_to_int64(const char *mac)
 			break;
 		}
 
-		/* 各数値をまとめる */
+		/* Append separated value to the result */
 		token_val = (int64_t)ret_tol;
 		ret_mac |= token_val << (token_cnt * 8);
 		token_cnt++;
 		str = NULL;
 	}
 
-	/* 区切り文字が5個以外 */
+	/* Check for mal-formatted address */
 	if (unlikely(token_cnt != ETHER_ADDR_LEN)) {
 		RTE_LOG(ERR, APP, "MAC address format error. (mac = %s)\n",
 				 mac);
@@ -272,21 +280,17 @@ spp_config_change_mac_str_to_int64(const char *mac)
 	return ret_mac;
 }
 
-/*
- * Classifier table読み込み
- */
 static int
 config_load_classifier_table(const json_t *obj,
 		struct spp_config_classifier_table *classifier_table)
 {
-	/* classifier_table用オブジェクト取得 */
 	json_t *classifier_obj = spp_config_get_path_obj(obj, JSONPATH_CLASSIFIER_TABLE);
 	if (unlikely(classifier_obj == NULL)) {
 		RTE_LOG(INFO, APP, "No classifier table.\n");
 		return 0;
 	}
 
-	/* name取得 */
+	/* Name of classifier table */
 	int ret_name = config_get_str_value(classifier_obj, JSONPATH_NAME,
 			classifier_table->name);
 	if (unlikely(ret_name != 0)) {
@@ -294,22 +298,20 @@ config_load_classifier_table(const json_t *obj,
 		return -1;
 	}
 
-	/* table用オブジェクト取得 */
+	/* Setup classifier as an array */
 	json_t *array_obj = spp_config_get_path_obj(classifier_obj, JSONPATH_TABLE);
 	if (unlikely(!array_obj)) {
 		RTE_LOG(ERR, APP, "Json object get failed. (path = %s)\n",
 				JSONPATH_TABLE);
 		return -1;
 	}
-
-	/* table用オブジェクトが配列かチェック */
 	if (unlikely(!json_is_array(array_obj))) {
 		RTE_LOG(ERR, APP, "Not an array. (path = %s)\n",
 				JSONPATH_TABLE);
 		return -1;
 	}
 
-	/* table用オブジェクトの要素数取得 */
+	/* Get the number of tables to set an attribute of classifier_table */
 	int array_num = json_array_size(array_obj);
 	if (unlikely(array_num <= 0) ||
 			unlikely(array_num > SPP_CONFIG_MAC_TABLE_MAX)) {
@@ -319,14 +321,14 @@ config_load_classifier_table(const json_t *obj,
 	}
 	classifier_table->num_table = array_num;
 
-	/* テーブルの各要素毎にデータ取得 */
+  /* Setup for each of mac tables */
 	struct spp_config_mac_table_element *tmp_table = NULL;
 	char if_str[SPP_CONFIG_STR_LEN];
 	int table_cnt = 0;
 	for (table_cnt = 0; table_cnt < array_num; table_cnt++) {
 		tmp_table = &classifier_table->mac_tables[table_cnt];
 
-		/* 要素取得 */
+		/* Get contents from the table */
 		json_t *elements_obj = json_array_get(array_obj, table_cnt);
 		if (unlikely(elements_obj == NULL)) {
 			RTE_LOG(ERR, APP,
@@ -335,7 +337,6 @@ config_load_classifier_table(const json_t *obj,
 			return -1;
 		}
 
-		/* MACアドレス(文字列)取得 */
 		int ret_mac = config_get_str_value(elements_obj, JSONPATH_MAC,
 				tmp_table->mac_addr_str);
 		if (unlikely(ret_mac != 0)) {
@@ -345,13 +346,16 @@ config_load_classifier_table(const json_t *obj,
 			return -1;
 		}
 
-		/* デフォルト転送先指定であれば内部流通用ダミーアドレスに変換 */
+    /**
+     * If mac address is set to 'default', replace it to reserved
+     * dummy address for validation.
+     */
 		if (unlikely(strcmp(tmp_table->mac_addr_str,
 				SPP_CONFIG_DEFAULT_CLASSIFIED_SPEC_STR) == 0))
 			strcpy(tmp_table->mac_addr_str,
 					SPP_CONFIG_DEFAULT_CLASSIFIED_DMY_ADDR_STR);
 
-		/* MACアドレス数値変換 */
+		/* Convert mac address to integer */
 		int64_t ret_mac64 = spp_config_change_mac_str_to_int64(
 				tmp_table->mac_addr_str);
 		if (unlikely(ret_mac64 == -1)) {
@@ -362,7 +366,7 @@ config_load_classifier_table(const json_t *obj,
 		}
 		tmp_table->mac_addr = ret_mac64;
 
-		/* IF情報取得 */
+		/* Extract a set of port type and number of interface */
 		int ret_if_str = config_get_str_value(elements_obj,
 				JSONPATH_PORT, if_str);
 		if (unlikely(ret_if_str != 0)) {
@@ -371,8 +375,7 @@ config_load_classifier_table(const json_t *obj,
 				table_cnt, JSONPATH_PORT);
 			return -1;
 		}
-
-		/* IF種別とIF番号に分割 */
+    /* And separate it to type and number */
 		int ret_if = spp_config_get_if_info(if_str, &tmp_table->port.if_type,
 				&tmp_table->port.if_no);
 		if (unlikely(ret_if != 0)) {
@@ -386,8 +389,8 @@ config_load_classifier_table(const json_t *obj,
 	return 0;
 }
 
-/*
- * 処理種別を文字列から数値変換
+/**
+ * Return the type of forwarder as a member of enum of spp_core_type
  */
 static enum spp_core_type
 config_change_core_type(const char *core_type)
@@ -398,19 +401,17 @@ config_change_core_type(const char *core_type)
 		return SPP_CONFIG_CLASSIFIER_MAC;
 	} else if (strncmp(core_type, CONFIG_CORE_TYPE_MERGE,
 			 strlen(CONFIG_CORE_TYPE_MERGE)+1) == 0) {
-		/* Merge */
+		/* Merger */
 		return SPP_CONFIG_MERGE;
 	} else if (strncmp(core_type, CONFIG_CORE_TYPE_FORWARD,
 			 strlen(CONFIG_CORE_TYPE_FORWARD)+1) == 0) {
-		/* Forward */
+		/* Forwarder */
 		return SPP_CONFIG_FORWARD;
 	}
 	return SPP_CONFIG_UNUSE;
 }
 
-/*
- * 受信ポート取得
- */
+/* Set behavior of rx port for forwarder, merger or classifier */
 static int
 config_set_rx_port(enum spp_core_type type, json_t *obj,
 		struct spp_config_functions *functions)
@@ -418,8 +419,7 @@ config_set_rx_port(enum spp_core_type type, json_t *obj,
 	struct spp_config_port_info *tmp_rx_port = NULL;
 	char if_str[SPP_CONFIG_STR_LEN];
 	if (type == SPP_CONFIG_MERGE) {
-		/* Merge */
-		/* 受信ポート用オブジェクト取得 */
+		/* Merger */
 		json_t *array_obj = spp_config_get_path_obj(obj, JSONPATH_RX_PORT);
 		if (unlikely(!array_obj)) {
 			RTE_LOG(ERR, APP, "Json object get failed. (path = %s, route = merge)\n",
@@ -427,14 +427,13 @@ config_set_rx_port(enum spp_core_type type, json_t *obj,
 			return -1;
 		}
 
-		/* 受信ポート用オブジェクトが配列かチェック */
 		if (unlikely(!json_is_array(array_obj))) {
 			RTE_LOG(ERR, APP, "Not an array. (path = %s, route = merge)\n",
 				JSONPATH_TABLE);
 			return -1;
 		}
 
-		/* 受信ポート用オブジェクトの要素数取得 */
+	  /* Check if the size of array is not over RTE_MAX_ETHPORTS */
 		int port_num = json_array_size(array_obj);
 		if (unlikely(port_num <= 0) ||
 				unlikely(port_num > RTE_MAX_ETHPORTS)) {
@@ -444,12 +443,11 @@ config_set_rx_port(enum spp_core_type type, json_t *obj,
 		}
 		functions->num_rx_port = port_num;
 
-		/* 要素毎にデータ取得 */
+		/* Get interface type and number of each of entries for merging */
 		int array_cnt = 0;
 		for (array_cnt = 0; array_cnt < port_num; array_cnt++) {
 			tmp_rx_port = &functions->rx_ports[array_cnt];
 
-			/* 要素取得 */
 			json_t *elements_obj = json_array_get(array_obj, array_cnt);
 			if (unlikely(elements_obj == NULL)) {
 				RTE_LOG(ERR, APP,
@@ -458,7 +456,6 @@ config_set_rx_port(enum spp_core_type type, json_t *obj,
 				return -1;
 			}
 
-			/* String type check */
 			if (unlikely(!json_is_string(elements_obj))) {
 				RTE_LOG(ERR, APP, "Not a string. (path = %s, No = %d, route = merge)\n",
 						JSONPATH_RX_PORT, array_cnt);
@@ -466,7 +463,7 @@ config_set_rx_port(enum spp_core_type type, json_t *obj,
 			}
 			strcpy(if_str, json_string_value(elements_obj));
 
-			/* IF種別とIF番号に分割 */
+			/* Separate combination of interface type and number to each */
 			int ret_if = spp_config_get_if_info(if_str, &tmp_rx_port->if_type,
 					&tmp_rx_port->if_no);
 			if (unlikely(ret_if != 0)) {
@@ -477,18 +474,18 @@ config_set_rx_port(enum spp_core_type type, json_t *obj,
 			}
 		}
 	} else {
-		/* Classifier/Forward */
+		/* Classifier or forwarder */
 		tmp_rx_port = &functions->rx_ports[0];
 		functions->num_rx_port = 1;
 
-		/* 受信ポート取得 */
+		/* Get receiving port */
 		int ret_rx_port = config_get_str_value(obj, JSONPATH_RX_PORT, if_str);
 		if (unlikely(ret_rx_port != 0)) {
 			RTE_LOG(ERR, APP, "RX port get failed.\n");
 			return -1;
 		}
 
-		/* IF種別とIF番号に分割 */
+		/* Separate it to interface type and number */
 		int ret_if = spp_config_get_if_info(if_str, &tmp_rx_port->if_type,
 				&tmp_rx_port->if_no);
 		if (unlikely(ret_if != 0)) {
@@ -501,9 +498,7 @@ config_set_rx_port(enum spp_core_type type, json_t *obj,
 	return 0;
 }
 
-/*
- * 送信先ポート情報取得
- */
+/* Set behavior of tx port for forwarder, merger or classifier */
 static int
 config_set_tx_port(enum spp_core_type type, json_t *obj,
 		struct spp_config_functions *functions,
@@ -513,11 +508,11 @@ config_set_tx_port(enum spp_core_type type, json_t *obj,
 	struct spp_config_port_info *tmp_tx_port = NULL;
 	char if_str[SPP_CONFIG_STR_LEN];
 	if ((type == SPP_CONFIG_MERGE) || (type == SPP_CONFIG_FORWARD)) {
-		/* Merge or Forward */
+		/* Merger or forwarder */
 		tmp_tx_port = &functions->tx_ports[0];
 		functions->num_tx_port = 1;
 
-		/* 送信ポート取得 */
+		/* Get receiving port */
 		int ret_tx_port = config_get_str_value(obj,
 				JSONPATH_TX_PORT, if_str);
 		if (unlikely(ret_tx_port != 0)) {
@@ -525,7 +520,7 @@ config_set_tx_port(enum spp_core_type type, json_t *obj,
 			return -1;
 		}
 
-		/* IF種別とIF番号に分割 */
+		/* Separate it to interface type and number */
 		int ret_if = spp_config_get_if_info(if_str, &tmp_tx_port->if_type,
 				&tmp_tx_port->if_no);
 		if (unlikely(ret_if != 0)) {
@@ -538,23 +533,17 @@ config_set_tx_port(enum spp_core_type type, json_t *obj,
 		/* Classifier */
 		json_t *table_obj = spp_config_get_path_obj(obj, JSONPATH_TX_TABLE);
 		if (unlikely(table_obj != NULL)) {
-			/* Classifier Tableから取得 */
 			functions->num_tx_port = classifier_table->num_table;
 			struct spp_config_mac_table_element *tmp_mac_table = NULL;
 			for (cnt = 0; cnt < classifier_table->num_table; cnt++) {
 				tmp_tx_port = &functions->tx_ports[cnt];
 				tmp_mac_table = &classifier_table->mac_tables[cnt];
 
-				/* MAC振り分けテーブルより設定 */
 				tmp_tx_port->if_type = tmp_mac_table->port.if_type;
 				tmp_tx_port->if_no   = tmp_mac_table->port.if_no;
 			}
-			
-		}
-		else
-		{
-			/* tx_portパラメータより取得 */
-			/* 送信ポート用オブジェクト取得 */
+		} else {
+			/* Get sending ports if table_obj is NULL */
 			json_t *array_obj = spp_config_get_path_obj(obj, JSONPATH_TX_PORT);
 			if (unlikely(array_obj == NULL)) {
 				RTE_LOG(ERR, APP, "Json object get failed. (path = %s, route = classifier)\n",
@@ -562,14 +551,13 @@ config_set_tx_port(enum spp_core_type type, json_t *obj,
 				return -1;
 			}
 
-			/* 送信ポート用オブジェクトが配列かチェック */
 			if (unlikely(!json_is_array(array_obj))) {
 				RTE_LOG(ERR, APP, "Not an array. (path = %s, route = classifier)\n",
 					JSONPATH_TX_PORT);
 				return -1;
 			}
 
-			/* 受信ポート用オブジェクトの要素数取得 */
+	    /* Check if the size of array is not over RTE_MAX_ETHPORTS */
 			int port_num = json_array_size(array_obj);
 			if (unlikely(port_num <= 0) ||
 					unlikely(port_num > RTE_MAX_ETHPORTS)) {
@@ -579,12 +567,10 @@ config_set_tx_port(enum spp_core_type type, json_t *obj,
 			}
 			functions->num_tx_port = port_num;
 
-			/* 要素毎にデータ取得 */
 			int array_cnt = 0;
 			for (array_cnt = 0; array_cnt < port_num; array_cnt++) {
 				tmp_tx_port = &functions->tx_ports[array_cnt];
 
-				/* 要素取得 */
 				json_t *elements_obj = json_array_get(array_obj, array_cnt);
 				if (unlikely(elements_obj == NULL)) {
 					RTE_LOG(ERR, APP,
@@ -593,7 +579,7 @@ config_set_tx_port(enum spp_core_type type, json_t *obj,
 					return -1;
 				}
 
-				/* String type check */
+        /* Get sending port */
 				if (unlikely(!json_is_string(elements_obj))) {
 					RTE_LOG(ERR, APP, "Not a string. (path = %s, No = %d, route = classifier)\n",
 							JSONPATH_TX_PORT, array_cnt);
@@ -601,7 +587,7 @@ config_set_tx_port(enum spp_core_type type, json_t *obj,
 				}
 				strcpy(if_str, json_string_value(elements_obj));
 
-				/* IF種別とIF番号に分割 */
+		    /* Separate it to interface type and number */
 				int ret_if = spp_config_get_if_info(if_str, &tmp_tx_port->if_type,
 						&tmp_tx_port->if_no);
 				if (unlikely(ret_if != 0)) {
@@ -617,16 +603,13 @@ config_set_tx_port(enum spp_core_type type, json_t *obj,
 	return 0;
 }
 
-/*
- * プロセス情報取得
- */
 static int
 config_load_proc_info(const json_t *obj, int node_id, struct spp_config_area *config)
 {
 	struct spp_config_proc_info *proc = &config->proc;
 	struct spp_config_classifier_table *classifier_table = &config->classifier_table;
 
-	/* proc_table用オブジェクト取得 */
+	/* TODO(yasufum) add comment after updating definition of the function in spp_config.c */
 	json_t *proc_table_obj = spp_config_get_path_obj(obj, JSONPATH_PROC_TABLE);
 	if (unlikely(proc_table_obj == NULL)) {
 		RTE_LOG(ERR, APP, "Json object get failed. (path = %s)\n",
@@ -634,14 +617,14 @@ config_load_proc_info(const json_t *obj, int node_id, struct spp_config_area *co
 		return -1;
 	}
 
-	/* table用オブジェクトが配列かチェック */
+	/* Return error code if it is not an array_obj */
 	if (unlikely(!json_is_array(proc_table_obj))) {
 		RTE_LOG(ERR, APP, "Not an array. (path = %s)\n",
 				JSONPATH_TABLE);
 		return -1;
 	}
 
-	/* table用オブジェクトの要素数取得 */
+	/* Check if the size of array is not over node_id */
 	int proc_table_num = json_array_size(proc_table_obj);
 	if (unlikely(proc_table_num < node_id)) {
 		RTE_LOG(ERR, APP, "No process data. (Size = %d, Node = %d)\n",
@@ -649,7 +632,7 @@ config_load_proc_info(const json_t *obj, int node_id, struct spp_config_area *co
 		return -1;
 	}
 
-	/* 要素取得 */
+	/* Get proc_obj for attributes */
 	json_t *proc_obj = json_array_get(proc_table_obj, node_id);
 	if (unlikely(proc_obj == NULL)) {
 		RTE_LOG(ERR, APP, "Process data get failed. (Node = %d)\n",
@@ -657,14 +640,14 @@ config_load_proc_info(const json_t *obj, int node_id, struct spp_config_area *co
 		return -1;
 	}
 
-	/* name取得 */
+	/* Name of proc */
 	int ret_name = config_get_str_value(proc_obj, JSONPATH_NAME, proc->name);
 	if (unlikely(ret_name != 0)) {
 		RTE_LOG(ERR, APP, "Process name get failed.\n");
 		return -1;
 	}
 
-	/* VHOST数取得 */
+	/* Number of vhost interfaces of proc */
 	int ret_vhost = config_get_int_value(proc_obj, JSONPATH_NUM_VHOST,
 			&proc->num_vhost);
 	if (unlikely(ret_vhost != 0)) {
@@ -672,7 +655,7 @@ config_load_proc_info(const json_t *obj, int node_id, struct spp_config_area *co
 		return -1;
 	}
 
-	/* RING数取得 */
+	/* Number of ring interfaces of proc */
 	int ret_ring = config_get_int_value(proc_obj, JSONPATH_NUM_RING,
 			&proc->num_ring);
 	if (unlikely(ret_ring != 0)) {
@@ -680,7 +663,7 @@ config_load_proc_info(const json_t *obj, int node_id, struct spp_config_area *co
 		return -1;
 	}
 
-	/* functions用オブジェクト取得 */
+	/* Get the number of operator functions */
 	json_t *array_obj = spp_config_get_path_obj(proc_obj, JSONPATH_FUNCTIONS);
 	if (unlikely(!array_obj)) {
 		RTE_LOG(ERR, APP, "Json object get failed. (path = %s)\n",
@@ -688,14 +671,12 @@ config_load_proc_info(const json_t *obj, int node_id, struct spp_config_area *co
 		return -1;
 	}
 
-	/* functions用オブジェクトが配列かチェック */
 	if (unlikely(!json_is_array(array_obj))) {
 		RTE_LOG(ERR, APP, "Not an array. (path = %s)\n",
 				JSONPATH_FUNCTIONS);
 		return -1;
 	}
 
-	/* functions用オブジェクトの要素数取得 */
 	int array_num = json_array_size(array_obj);
 	if (unlikely(array_num <= 0) ||
 			unlikely(array_num > SPP_CONFIG_CORE_MAX)) {
@@ -705,14 +686,13 @@ config_load_proc_info(const json_t *obj, int node_id, struct spp_config_area *co
 	}
 	proc->num_func = array_num;
 
-	/* 要素毎にデータ取得 */
+	/* Get each of operator functions */
 	struct spp_config_functions *tmp_functions = NULL;
 	char core_type_str[SPP_CONFIG_STR_LEN];
 	int array_cnt = 0;
 	for (array_cnt = 0; array_cnt < array_num; array_cnt++) {
 		tmp_functions = &proc->functions[array_cnt];
 
-		/* 要素取得 */
 		json_t *elements_obj = json_array_get(array_obj, array_cnt);
 		if (unlikely(elements_obj == NULL)) {
 			RTE_LOG(ERR, APP,
@@ -721,7 +701,7 @@ config_load_proc_info(const json_t *obj, int node_id, struct spp_config_area *co
 			return -1;
 		}
 
-		/* CORE番号取得 */
+		/* Get number and type of the core */
 		int ret_core = config_get_int_value(elements_obj, JSONPATH_CORE_NO,
 				&tmp_functions->core_no);
 		if (unlikely(ret_core != 0)) {
@@ -730,7 +710,6 @@ config_load_proc_info(const json_t *obj, int node_id, struct spp_config_area *co
 			return -1;
 		}
 
-		/* 処理種別取得 */
 		int ret_core_type = config_get_str_value(elements_obj,
 				 JSONPATH_CORE_TYPE, core_type_str);
 		if (unlikely(ret_core_type != 0)) {
@@ -739,7 +718,7 @@ config_load_proc_info(const json_t *obj, int node_id, struct spp_config_area *co
 			return -1;
 		}
 
-		/* 処理種別を数値に変換 */
+		/* Convert the type of core to a member of enum spp_core_type */
 		enum spp_core_type core_type = config_change_core_type(core_type_str);
 		if (unlikely(core_type == SPP_CONFIG_UNUSE)) {
 			RTE_LOG(ERR, APP,
@@ -749,7 +728,7 @@ config_load_proc_info(const json_t *obj, int node_id, struct spp_config_area *co
 		}
 		tmp_functions->type = core_type;
 
-		/* 受信ポート取得 */
+		/* Get rx and tx ports */
 		int ret_rx_port = config_set_rx_port(core_type, elements_obj,
 				tmp_functions);
 		if (unlikely(ret_rx_port != 0)) {
@@ -758,7 +737,6 @@ config_load_proc_info(const json_t *obj, int node_id, struct spp_config_area *co
 			return -1;
 		}
 
-		/* 送信ポート取得 */
 		int ret_tx_port = config_set_tx_port(core_type, elements_obj,
 				tmp_functions, classifier_table);
 		if (unlikely(ret_tx_port != 0)) {
@@ -771,18 +749,11 @@ config_load_proc_info(const json_t *obj, int node_id, struct spp_config_area *co
 	return 0;
 }
 
-/*
- * Load config file
- * OK : 0
- * NG : -1
- */
 int
 spp_config_load_file(const char* config_file_path, int node_id, struct spp_config_area *config)
 {
-	/* Config initialize */
 	config_init_data(config);
-	
-	/* Config load */
+
 	json_error_t json_error;
 	json_t *conf_obj = json_load_file(config_file_path, 0, &json_error);
 	if (unlikely(conf_obj == NULL)) {
@@ -792,7 +763,6 @@ spp_config_load_file(const char* config_file_path, int node_id, struct spp_confi
 		return -1;
 	}
 
-	/* classifier table */
 	int ret_classifier = config_load_classifier_table(conf_obj,
 			&config->classifier_table);
 	if (unlikely(ret_classifier != 0)) {
@@ -801,7 +771,6 @@ spp_config_load_file(const char* config_file_path, int node_id, struct spp_confi
 		return -1;
 	}
 
-	/* proc info */
 	int ret_proc = config_load_proc_info(conf_obj, node_id, config);
 	if (unlikely(ret_proc != 0)) {
 		RTE_LOG(ERR, APP, "Process table load failed.\n");
@@ -809,7 +778,7 @@ spp_config_load_file(const char* config_file_path, int node_id, struct spp_confi
 		return -1;
 	}
 
-	/* Config object release */
+	/* Finally, release config object */
 	json_decref(conf_obj);
 
 	return 0;
-- 
1.9.1

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

* [spp] [PATCH 52/57] spp_vf: refactor no self-explanatory comments
  2017-12-26  1:54 ` Yasufumi Ogawa
                     ` (50 preceding siblings ...)
  2017-12-28  4:55   ` [spp] [PATCH 51/57] spp_vf: refactor for commnets in spp_config.c x-fn-spp
@ 2017-12-28  4:55   ` x-fn-spp
  2017-12-28  4:56   ` [spp] [PATCH 53/57] spp_vf: correct typo of function name x-fn-spp
                     ` (4 subsequent siblings)
  56 siblings, 0 replies; 97+ messages in thread
From: x-fn-spp @ 2017-12-28  4:55 UTC (permalink / raw)
  To: spp

From: Hiroyuki Nakamura <nakamura.hioryuki@po.ntt-tx.co.jp>

Signed-off-by: Yasufumi Ogawa <ogawa.yasufumi@lab.ntt.co.jp>
---
 src/vf/spp_vf.c | 25 ++++++++++---------------
 1 file changed, 10 insertions(+), 15 deletions(-)

diff --git a/src/vf/spp_vf.c b/src/vf/spp_vf.c
index 33373f5..44cd720 100644
--- a/src/vf/spp_vf.c
+++ b/src/vf/spp_vf.c
@@ -384,9 +384,9 @@ parse_app_args(int argc, char *argv[])
  * Return patch info of given type and num of interface
  *
  * It returns NULL value if given type is invalid.
+ *
  * TODO(yasufum) refactor name of func to be more understandable (area?)
  * TODO(yasufum) refactor, change if to iface.
- * TODO(yasufum) confirm why it returns not -1 but NULL.
  */
 static struct patch_info *
 get_if_area(enum port_type if_type, int if_no)
@@ -471,8 +471,9 @@ set_form_proc_info(struct spp_config_area *config)
 			continue;
 		}
 
-    /* Forwardをまとめる事は可、他種別は不可 */
-    /* TODO(yasufum) confirm what is the purpose and meaning */
+    /* Check if type of core_info is SPP_CONFIG_FORWARD because this
+     * this type is only available for several settings.
+     */
     if ((core_info->type != SPP_CONFIG_UNUSE) &&
         ((core_info->type != SPP_CONFIG_FORWARD) ||
          (core_func->type != SPP_CONFIG_FORWARD))) {
@@ -509,8 +510,7 @@ set_form_proc_info(struct spp_config_area *config)
 				return -1;
 			}
 
-			/* IF情報からCORE情報を変更する場合用に設定 */
-      /* TODO(yasufum) confirm the meaning of this comment */
+			/* Hold core info is to be referred for updating this information */
 			patch_info->rx_core_no = core_func->core_no;
 			patch_info->rx_core    = &core_info->rx_ports[rx_start + rx_cnt];
 		}
@@ -534,8 +534,7 @@ set_form_proc_info(struct spp_config_area *config)
 				return -1;
 			}
 
-			/* IF情報からCORE情報を変更する場合用に設定 */
-      /* TODO(yasufum) confirm the meaning of this comment */
+			/* Hold core info is to be referred for updating this information */
 			patch_info->tx_core_no = core_func->core_no;
 			patch_info->tx_core    = &core_info->tx_ports[tx_start + tx_cnt];
 		}
@@ -548,7 +547,6 @@ set_form_proc_info(struct spp_config_area *config)
  * Load mac table entries from config and setup patches
  *
  * TODO(yasufum) refactor, change if to iface.
- * TODO(yasufum) confirm if additional description for the structure of mac table is needed.
  */
 static int
 set_from_classifier_table(struct spp_config_area *config)
@@ -604,9 +602,8 @@ set_nic_interface(struct spp_config_area *config __attribute__ ((unused)))
 		patch_info = &g_if_info.nic_patchs[nic_cnt];
 		patch_info->dpdk_port = nic_cnt;
 
-    /* TODO(yasufum) confirm why it is needed */
+    /* Skip for no used nic */
 		if (patch_info->use_flg == 0) {
-			/* Not Used */
 			continue;
 		}
 
@@ -685,9 +682,8 @@ set_ring_interface(struct spp_config_area *config)
 	for (ring_cnt = 0; ring_cnt < RTE_MAX_ETHPORTS; ring_cnt++) {
 		patch_info = &g_if_info.ring_patchs[ring_cnt];
 
-    /* TODO(yasufum) confirm why it is needed */
 		if (patch_info->use_flg == 0) {
-			/* Not Used */
+      /* Skip for no used nic */
 			continue;
 		}
 
@@ -825,6 +821,7 @@ del_vhost_sockfile(struct patch_info *vhost_patchs)
 
 /* TODO(yasufum) refactor, change if to iface. */
 /* TODO(yasufum) change test using ut_main(), or add desccription for what and why use it */
+/* TODO(yasufum) change to return -1 explicity if error is occured. */
 int
 #ifndef USE_UT_SPP_VF
 main(int argc, char *argv[])
@@ -950,7 +947,6 @@ ut_main(int argc, char *argv[])
 #endif /* SPP_RINGLATENCYSTATS_ENABLE */
 		}
 
-    /* TODO(yasufum) confirm, add why this check is needed because it is same the case of "ret = 0", or remove */
 		if (unlikely(ret_do != 0)) {
 			break;
 		}
@@ -987,10 +983,9 @@ spp_get_client_id(void)
 }
 
 /**
- * Check mac address used on the interface
+ * Check mac address used on the interface for registering or removing
  *
  * TODO(yasufum) refactor, change if to iface.
- * TODO(yasufum) confirm, add the reason why this check is needed
  */
 static int
 check_mac_used_interface(uint64_t mac_addr, enum port_type *if_type, int *if_no)
-- 
1.9.1

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

* [spp] [PATCH 53/57] spp_vf: correct typo of function name
  2017-12-26  1:54 ` Yasufumi Ogawa
                     ` (51 preceding siblings ...)
  2017-12-28  4:55   ` [spp] [PATCH 52/57] spp_vf: refactor no self-explanatory comments x-fn-spp
@ 2017-12-28  4:56   ` x-fn-spp
  2017-12-28  4:56   ` [spp] [PATCH 54/57] spp_vf: support new command x-fn-spp
                     ` (3 subsequent siblings)
  56 siblings, 0 replies; 97+ messages in thread
From: x-fn-spp @ 2017-12-28  4:56 UTC (permalink / raw)
  To: spp

From: Hiroyuki Nakamura <nakamura.hioryuki@po.ntt-tx.co.jp>

Change 'set_form_proc_info' to 'set_from_proc_info'.

Signed-off-by: Yasufumi Ogawa <ogawa.yasufumi@lab.ntt.co.jp>
---
 src/vf/spp_vf.c | 5 ++---
 1 file changed, 2 insertions(+), 3 deletions(-)

diff --git a/src/vf/spp_vf.c b/src/vf/spp_vf.c
index 44cd720..c7268e5 100644
--- a/src/vf/spp_vf.c
+++ b/src/vf/spp_vf.c
@@ -452,10 +452,9 @@ init_core_info(void)
  * Set properties of g_core_info from config
  *
  * TODO(yasufum) refactor, change if to iface.
- * TODO(yasufum) confirm meaning of funciton name and is typo ?
  */
 static int
-set_form_proc_info(struct spp_config_area *config)
+set_from_proc_info(struct spp_config_area *config)
 {
 	int core_cnt, rx_start, rx_cnt, tx_start, tx_cnt;
 	enum port_type if_type;
@@ -725,7 +724,7 @@ init_manage_data(struct spp_config_area *config)
 	init_core_info();
 
   /* Load config for resource assingment and network configuration */
-	int ret_proc = set_form_proc_info(config);
+	int ret_proc = set_from_proc_info(config);
 	if (unlikely(ret_proc != 0)) {
 		return -1;
 	}
-- 
1.9.1

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

* [spp] [PATCH 54/57] spp_vf: support new command
  2017-12-26  1:54 ` Yasufumi Ogawa
                     ` (52 preceding siblings ...)
  2017-12-28  4:56   ` [spp] [PATCH 53/57] spp_vf: correct typo of function name x-fn-spp
@ 2017-12-28  4:56   ` x-fn-spp
  2017-12-28  4:56   ` [spp] [PATCH 55/57] spp_vf: add display of status command x-fn-spp
                     ` (2 subsequent siblings)
  56 siblings, 0 replies; 97+ messages in thread
From: x-fn-spp @ 2017-12-28  4:56 UTC (permalink / raw)
  To: spp

From: Hiroyuki Nakamura <nakamura.hioryuki@po.ntt-tx.co.jp>

Newly support 'component' command.
* 'component' command provides start/stop function for component 
  such as forwarder, classifier etc.
* Support naming function for 'component' and 
  its name can be used for later command operations.
* Support core selection function for 'component'. 

Newly support 'port' command.
* 'port' command provides function for creating port such as ring, 
  vhost, phy. 
* Also provides function for assigning port to 'component'. 
  This can be done by specifying the name of 'component'.
* 'port' command initializes the port to be used for the first time.

Newly support 'exit' command.
* 'exit' command provides stop function for spp_vf process.

And modify 'classifier_table' command.
* Add operation types. (add/del)
* Add wait procedure for initialization to complete.

Also, to support above commands, the structure of management
data has been changed.

Signed-off-by: Kentaro Watanabe <watanabe.kentaro.z01@as.ntt-tx.co.jp>
Signed-off-by: Yasufum Ogawa <ogawa.yasufumi@lab.ntt.co.jp>
---
 src/spp_vf.py           |    6 +-
 src/vf/Makefile         |    2 +-
 src/vf/classifier_mac.c |  251 ++++++----
 src/vf/classifier_mac.h |   14 +-
 src/vf/command_dec.c    |  400 +++++++++++++--
 src/vf/command_dec.h    |   52 +-
 src/vf/command_proc.c   |   36 +-
 src/vf/command_proc.h   |    3 +-
 src/vf/spp_config.c     |   26 +-
 src/vf/spp_forward.c    |  199 +++++---
 src/vf/spp_forward.h    |    9 +-
 src/vf/spp_vf.c         | 1269 ++++++++++++++++++++++++++++++-----------------
 src/vf/spp_vf.h         |  199 +++++++-
 13 files changed, 1718 insertions(+), 748 deletions(-)

diff --git a/src/spp_vf.py b/src/spp_vf.py
index 40310db..505a142 100755
--- a/src/spp_vf.py
+++ b/src/spp_vf.py
@@ -60,7 +60,7 @@ def connectionthread(name, client_id, conn, m2s, s2m):
 
         #Receiving from secondary
         try:
-            data = conn.recv(1024) # 1024 stands for bytes of data to be received
+            data = conn.recv(2048) # 2048 stands for bytes of data to be received
             if data:
                 s2m.put("recv:" + str(conn.fileno()) + ":" + "{" + data + "}")
             else:
@@ -212,7 +212,7 @@ def primarythread(sock, main2primary, primary2main):
 
             #Receiving from primary
             try:
-                data = conn.recv(1024) # 1024 stands for bytes of data to be received
+                data = conn.recv(2048) # 2048 stands for bytes of data to be received
                 if data:
                     primary2main.put("recv:" + str(addr) + ":" + "{" + data + "}")
                 else:
@@ -228,8 +228,6 @@ def primarythread(sock, main2primary, primary2main):
 def close_all_secondary():
     """Exit all secondary processes"""
 
-    return;
-
     global SECONDARY_COUNT
 
     tmp_list = []
diff --git a/src/vf/Makefile b/src/vf/Makefile
index 1284733..a2ac128 100644
--- a/src/vf/Makefile
+++ b/src/vf/Makefile
@@ -40,7 +40,7 @@ include $(RTE_SDK)/mk/rte.vars.mk
 APP = spp_vf
 
 # all source are stored in SRCS-y
-SRCS-y := spp_vf.c spp_config.c classifier_mac.c spp_forward.c string_buffer.c command_conn.c command_dec.c command_proc.c ringlatencystats.c ../shared/common.c
+SRCS-y := spp_vf.c classifier_mac.c spp_forward.c string_buffer.c command_conn.c command_dec.c command_proc.c ringlatencystats.c ../shared/common.c
 
 CFLAGS += $(WERROR_FLAGS) -O3
 CFLAGS += -I$(SRCDIR)/../shared
diff --git a/src/vf/classifier_mac.c b/src/vf/classifier_mac.c
index e2aa715..937a8c0 100644
--- a/src/vf/classifier_mac.c
+++ b/src/vf/classifier_mac.c
@@ -40,7 +40,7 @@
 
 /* interval that wait untill change update index
 		micro second */
-#define CHANGE_UPDATE_INDEX_WAIT_INTERVAL 10
+#define CHANGE_UPDATE_INDEX_WAIT_INTERVAL SPP_CHANGE_UPDATE_INTERVAL
 
 /* interval that transmit burst packet, if buffer is not filled.
 		nano second */
@@ -65,12 +65,12 @@ static const size_t ETHER_ADDR_STR_BUF_SZ =
 
 /* classified data (destination port, target packets, etc) */
 struct classified_data {
-	enum port_type  if_type;
-	int             if_no;
-	int             if_no_global;
-	uint8_t         tx_port;
-	uint16_t        num_pkt;
-	struct rte_mbuf *pkts[MAX_PKT_BURST];
+	enum port_type  if_type;              /* interface type (see "enum port_type") */
+	int             if_no;                /* index of ports handled by classifier  */
+	int             if_no_global;         /* interface number                      */
+	uint8_t         port;                 /* port number used by dpdk              */
+	uint16_t        num_pkt;              /* the number of packets in pkts[]       */
+	struct rte_mbuf *pkts[MAX_PKT_BURST]; /* packet array to be classified         */
 };
 
 /* classifier information */
@@ -79,6 +79,9 @@ struct classifier_mac_info {
 	int num_active_classified;
 	int active_classifieds[RTE_MAX_ETHPORTS];
 	int default_classified;
+	int n_classified_data_tx;
+	struct classified_data classified_data_rx;
+	struct classified_data classified_data_tx[RTE_MAX_ETHPORTS];
 };
 
 /* classifier management information */
@@ -86,7 +89,6 @@ struct classifier_mac_mng_info {
 	struct classifier_mac_info info[NUM_CLASSIFIER_MAC_INFO];
 	volatile int ref_index;
 	volatile int upd_index;
-	struct classified_data classified_data[RTE_MAX_ETHPORTS];
 };
 
 /* classifier information per lcore */
@@ -109,20 +111,40 @@ is_used_mng_info(const struct classifier_mac_mng_info *mng_info)
 /* initialize classifier information. */
 static int
 init_classifier_info(struct classifier_mac_info *classifier_info,
-		const struct spp_core_info *core_info)
+		const struct spp_component_info *component_info)
 {
 	int ret = -1;
 	int i;
 	struct rte_hash **classifier_table = &classifier_info->classifier_table;
 	struct ether_addr eth_addr;
 	char mac_addr_str[ETHER_ADDR_STR_BUF_SZ];
+	struct classified_data *classified_data_rx = &classifier_info->classified_data_rx;
+	struct classified_data *classified_data_tx = classifier_info->classified_data_tx;
+	struct spp_port_info *tx_port = NULL;
 
 	rte_hash_reset(*classifier_table);
 	classifier_info->num_active_classified = 0;
 	classifier_info->default_classified = -1;
+	classifier_info->n_classified_data_tx = component_info->num_tx_port;
+	if (component_info->num_rx_port != 0) {
+		classified_data_rx->if_type      = component_info->rx_ports[0]->if_type;
+		classified_data_rx->if_no        = 0;
+		classified_data_rx->if_no_global = component_info->rx_ports[0]->if_no;
+		classified_data_rx->port         = component_info->rx_ports[0]->dpdk_port;
+		classified_data_rx->num_pkt      = 0;
+	}
+
+	for (i = 0; i < component_info->num_tx_port; i++) {
+		tx_port = component_info->tx_ports[i];
 
-	for (i = 0; i < core_info->num_tx_port; i++) {
-		if (core_info->tx_ports[i].mac_addr == 0) {
+		/* store ports information */
+		classified_data_tx[i].if_type      = tx_port->if_type;
+		classified_data_tx[i].if_no        = i;
+		classified_data_tx[i].if_no_global = tx_port->if_no;
+		classified_data_tx[i].port         = tx_port->dpdk_port;
+		classified_data_tx[i].num_pkt      = 0;
+
+		if (component_info->tx_ports[i]->mac_addr == 0) {
 			continue;
 		}
 
@@ -131,19 +153,19 @@ init_classifier_info(struct classifier_mac_info *classifier_info,
 				num_active_classified++] = i;
 
 		/* store default classified */
-		if (unlikely(core_info->tx_ports[i].mac_addr ==
-				SPP_CONFIG_DEFAULT_CLASSIFIED_DMY_ADDR)) {
+		if (unlikely(tx_port->mac_addr ==
+				SPP_DEFAULT_CLASSIFIED_DMY_ADDR)) {
 			classifier_info->default_classified = i;
 			RTE_LOG(INFO, SPP_CLASSIFIER_MAC, "default classified. "
 					"if_type=%d, if_no=%d, dpdk_port=%d\n",
-					core_info->tx_ports[i].if_type,
-					core_info->tx_ports[i].if_no,
-					core_info->tx_ports[i].dpdk_port);
+					tx_port->if_type,
+					tx_port->if_no,
+					tx_port->dpdk_port);
 			continue;
 		}
 
 		/* add entry to classifier mac table */
-		rte_memcpy(&eth_addr, &core_info->tx_ports[i].mac_addr, ETHER_ADDR_LEN);
+		rte_memcpy(&eth_addr, &tx_port->mac_addr, ETHER_ADDR_LEN);
 		ether_format_addr(mac_addr_str, sizeof(mac_addr_str), &eth_addr);
 
 		ret = rte_hash_add_key_data(*classifier_table,
@@ -160,9 +182,9 @@ init_classifier_info(struct classifier_mac_info *classifier_info,
 		RTE_LOG(INFO, SPP_CLASSIFIER_MAC, "Add entry to classifier mac table. "
 				"mac_addr=%s, if_type=%d, if_no=%d, dpdk_port=%d\n",
 				mac_addr_str, 
-				core_info->tx_ports[i].if_type, 
-				core_info->tx_ports[i].if_no, 
-				core_info->tx_ports[i].dpdk_port);
+				tx_port->if_type, 
+				tx_port->if_no, 
+				tx_port->dpdk_port);
 	}
 
 	return 0;
@@ -170,19 +192,25 @@ init_classifier_info(struct classifier_mac_info *classifier_info,
 
 /* initialize classifier. */
 static int
-init_classifier(const struct spp_core_info *core_info,
-		struct classifier_mac_mng_info *classifier_mng_info, 
-		struct classified_data *classified_data)
+init_classifier(struct classifier_mac_mng_info *classifier_mng_info)
 {
 	int ret = -1;
 	int i;
 	char hash_table_name[HASH_TABLE_NAME_BUF_SZ];
 
 	struct rte_hash **classifier_mac_table = NULL;
+	struct spp_component_info component_info;
 
 	memset(classifier_mng_info, 0, sizeof(struct classifier_mac_mng_info));
+	/*
+	 * Set the same value for "ref_index" and "upd_index"
+	 * so that it will not be changed from others during initialization,
+	 * and update "upd_index" after initialization is completed.
+	 * Therefore, this setting is consciously described.
+	 */
 	classifier_mng_info->ref_index = 0;
-	classifier_mng_info->upd_index = classifier_mng_info->ref_index + 1;
+	classifier_mng_info->upd_index = 0;
+	memset(&component_info, 0x00, sizeof(component_info));
 
 #ifdef RTE_MACHINE_CPUFLAG_SSE4_2
 	RTE_LOG(DEBUG, SPP_CLASSIFIER_MAC, "Enabled SSE4.2. use crc hash.\n");
@@ -222,21 +250,15 @@ init_classifier(const struct spp_core_info *core_info,
 
 	/* populate the classifier information at reference */
 	ret = init_classifier_info(&classifier_mng_info->
-			info[classifier_mng_info->ref_index], core_info);
+			info[classifier_mng_info->ref_index], &component_info);
 	if (unlikely(ret != 0)) {
 		RTE_LOG(ERR, SPP_CLASSIFIER_MAC,
 				"Cannot initialize classifer mac table. ret=%d\n", ret);
 		return -1;
 	}
 
-	/* store ports information */
-	for (i = 0; i < core_info->num_tx_port; i++) {
-		classified_data[i].if_type      = core_info->tx_ports[i].if_type;
-		classified_data[i].if_no        = i;
-		classified_data[i].if_no_global = core_info->tx_ports[i].if_no;
-		classified_data[i].tx_port      = core_info->tx_ports[i].dpdk_port;
-		classified_data[i].num_pkt      = 0;
-	}
+	/* updating side can be set by completion of initialization. */
+	classifier_mng_info->upd_index = classifier_mng_info->ref_index + 1;
 
 	return 0;
 }
@@ -270,7 +292,7 @@ transmit_packet(struct classified_data *classified_data)
 #endif
 
 	/* transmit packets */
-	n_tx = rte_eth_tx_burst(classified_data->tx_port, 0,
+	n_tx = rte_eth_tx_burst(classified_data->port, 0,
 			classified_data->pkts, classified_data->num_pkt);
 
 	/* free cannnot transmit packets */
@@ -279,12 +301,32 @@ transmit_packet(struct classified_data *classified_data)
 			rte_pktmbuf_free(classified_data->pkts[i]);
 		RTE_LOG(DEBUG, SPP_CLASSIFIER_MAC,
 				"drop packets(tx). num=%hu, dpdk_port=%hhu\n",
-				classified_data->num_pkt - n_tx, classified_data->tx_port);
+				classified_data->num_pkt - n_tx, classified_data->port);
 	}
 
 	classified_data->num_pkt = 0;
 }
 
+/* transmit packet to one destination. */
+static inline void
+transmit_all_packet(struct classifier_mac_info *classifier_info)
+{
+	int i;
+	struct classified_data *classified_data_tx = classifier_info->classified_data_tx;
+
+	for (i = 0; i < classifier_info->n_classified_data_tx; i++) {
+		if (unlikely(classified_data_tx[i].num_pkt != 0)) {
+			RTE_LOG(INFO, SPP_CLASSIFIER_MAC,
+					"transimit all packets (drain). "
+					"index=%d, "
+					"num_pkt=%hu\n",
+					i,
+					classified_data_tx[i].num_pkt);
+			transmit_packet(&classified_data_tx[i]);
+		}
+	}
+}
+
 /* set mbuf pointer to tx buffer
 	and transmit packet, if buffer is filled */
 static inline void
@@ -300,7 +342,7 @@ push_packet(struct rte_mbuf *pkt, struct classified_data *classified_data)
 				classified_data->if_type,
 				classified_data->if_no_global,
 				classified_data->if_no,
-				classified_data->tx_port,
+				classified_data->port,
 				classified_data->num_pkt);
 		transmit_packet(classified_data);
 	}
@@ -383,13 +425,18 @@ classify_packet(struct rte_mbuf **rx_pkts, uint16_t n_rx,
 
 /* change update index at classifier management information */
 static inline void
-change_update_index(struct classifier_mac_mng_info *classifier_mng_info, unsigned int lcore_id)
+change_update_index(struct classifier_mac_mng_info *classifier_mng_info, int id)
 {
 	if (unlikely(classifier_mng_info->ref_index == 
 			classifier_mng_info->upd_index)) {
+
+		/* Transmit all packets for switching the using data. */
+		transmit_all_packet(classifier_mng_info->info +
+				classifier_mng_info->ref_index);
+
 		RTE_LOG(DEBUG, SPP_CLASSIFIER_MAC,
-				"Core[%u] Change update index.\n", lcore_id);
-		classifier_mng_info->upd_index = 
+				"Core[%u] Change update index.\n", id);
+		classifier_mng_info->ref_index =
 				(classifier_mng_info->upd_index + 1) % 
 				NUM_CLASSIFIER_MAC_INFO;
 	}
@@ -406,22 +453,26 @@ spp_classifier_mac_init(void)
 
 /* classifier(mac address) update component info. */
 int
-spp_classifier_mac_update(struct spp_core_info *core_info)
+spp_classifier_mac_update(struct spp_component_info *component_info)
 {
 	int ret = -1;
-	unsigned int lcore_id = core_info->lcore_id;
-
+	int id = component_info->component_id;
 	struct classifier_mac_mng_info *classifier_mng_info =
-			g_classifier_mng_info + lcore_id;
+			g_classifier_mng_info + id;
 
-	struct classifier_mac_info *classifier_info =
-			classifier_mng_info->info + classifier_mng_info->upd_index;
+	struct classifier_mac_info *classifier_info = NULL;
 
 	RTE_LOG(INFO, SPP_CLASSIFIER_MAC,
-			"Core[%u] Start update component.\n", lcore_id);
+			"Component[%u] Start update component.\n", id);
+
+	/* wait until no longer access the new update side */
+	while(likely(classifier_mng_info->ref_index == classifier_mng_info->upd_index))
+		rte_delay_us_block(CHANGE_UPDATE_INDEX_WAIT_INTERVAL);
+
+	classifier_info = classifier_mng_info->info + classifier_mng_info->upd_index;
 
 	/* initialize update side classifier information */
-	ret = init_classifier_info(classifier_info, core_info);
+	ret = init_classifier_info(classifier_info, component_info);
 	if (unlikely(ret != 0)) {
 		RTE_LOG(ERR, SPP_CLASSIFIER_MAC,
 				"Cannot update classifer mac. ret=%d\n", ret);
@@ -429,105 +480,96 @@ spp_classifier_mac_update(struct spp_core_info *core_info)
 	}
 
 	/* change index of reference side */
-	classifier_mng_info->ref_index = classifier_mng_info->upd_index;
+	classifier_mng_info->upd_index = classifier_mng_info->ref_index;
 
 	/* wait until no longer access the new update side */
 	while(likely(classifier_mng_info->ref_index == classifier_mng_info->upd_index))
 		rte_delay_us_block(CHANGE_UPDATE_INDEX_WAIT_INTERVAL);
 
 	RTE_LOG(INFO, SPP_CLASSIFIER_MAC,
-			"Core[%u] Complete update component.\n", lcore_id);
+			"Component[%u] Complete update component.\n", id);
 
 	return 0;
 }
 
 /* classifier(mac address) thread function. */
 int
-spp_classifier_mac_do(void *arg)
+spp_classifier_mac_do(int id)
 {
 	int ret = -1;
 	int i;
 	int n_rx;
 	unsigned int lcore_id = rte_lcore_id();
-	struct spp_core_info *core_info = (struct spp_core_info *)arg;
 	struct classifier_mac_mng_info *classifier_mng_info =
-			g_classifier_mng_info + rte_lcore_id();
+			g_classifier_mng_info + id;
 
 	struct classifier_mac_info *classifier_info = NULL;
 	struct rte_mbuf *rx_pkts[MAX_PKT_BURST];
 
-	const int n_classified_data = core_info->num_tx_port;
-	struct classified_data *classified_data = classifier_mng_info->classified_data;
+	struct classified_data *classified_data_rx = NULL;
+	struct classified_data *classified_data_tx = NULL;
 
 	uint64_t cur_tsc, prev_tsc = 0;
 	const uint64_t drain_tsc = (rte_get_tsc_hz() + US_PER_S - 1) /
 			US_PER_S * DRAIN_TX_PACKET_INTERVAL;
 
 	/* initialize */
-	ret = init_classifier(core_info, classifier_mng_info, classified_data);
+	ret = init_classifier(classifier_mng_info);
 	if (unlikely(ret != 0))
 		return ret;
 
-	/* to idle  */
-	core_info->status = SPP_CORE_IDLE;
-	RTE_LOG(INFO, SPP_CLASSIFIER_MAC, "Core[%u] Start. (type = %d)\n",
-			lcore_id, core_info->type);
-
-	while(likely(core_info->status == SPP_CORE_IDLE) ||
-			likely(core_info->status == SPP_CORE_FORWARD)) {
-
-		while(likely(core_info->status == SPP_CORE_FORWARD)) {
-			/* change index of update side */
-			change_update_index(classifier_mng_info, lcore_id);
-
-			/* decide classifier infomation of the current cycle */
-			classifier_info = classifier_mng_info->info + 
-					classifier_mng_info->ref_index;
-
-			/* drain tx packets, if buffer is not filled for interval */
-			cur_tsc = rte_rdtsc();
-			if (unlikely(cur_tsc - prev_tsc > drain_tsc)) {
-				for (i = 0; i < n_classified_data; i++) {
-					if (unlikely(classified_data[i].num_pkt != 0)) {
-						RTE_LOG(DEBUG, SPP_CLASSIFIER_MAC,
-                        					"transimit packets (drain). "
-								"index=%d, "
-								"num_pkt=%hu, "
-								"interval=%lu\n",
-								i,
-								classified_data[i].num_pkt,
-								cur_tsc - prev_tsc);
-						transmit_packet(&classified_data[i]);
-					}
+	while(likely(spp_get_core_status(lcore_id) == SPP_CORE_FORWARD) &&
+			likely(spp_check_core_index(lcore_id) == 0)) {
+		/* change index of update side */
+		change_update_index(classifier_mng_info, id);
+
+		/* decide classifier infomation of the current cycle */
+		classifier_info = classifier_mng_info->info + 
+				classifier_mng_info->ref_index;
+		classified_data_rx = &classifier_info->classified_data_rx;
+		classified_data_tx = classifier_info->classified_data_tx;
+
+		/* drain tx packets, if buffer is not filled for interval */
+		cur_tsc = rte_rdtsc();
+		if (unlikely(cur_tsc - prev_tsc > drain_tsc)) {
+			for (i = 0; i < classifier_info->n_classified_data_tx; i++) {
+				if (unlikely(classified_data_tx[i].num_pkt != 0)) {
+					RTE_LOG(DEBUG, SPP_CLASSIFIER_MAC,
+							"transimit packets (drain). "
+							"index=%d, "
+							"num_pkt=%hu, "
+							"interval=%lu\n",
+							i,
+							classified_data_tx[i].num_pkt,
+							cur_tsc - prev_tsc);
+					transmit_packet(&classified_data_tx[i]);
 				}
-				prev_tsc = cur_tsc;
 			}
+			prev_tsc = cur_tsc;
+		}
 
-			/* retrieve packets */
-			n_rx = rte_eth_rx_burst(core_info->rx_ports[0].dpdk_port, 0,
-					rx_pkts, MAX_PKT_BURST);
-			if (unlikely(n_rx == 0))
-				continue;
+		/* retrieve packets */
+		n_rx = rte_eth_rx_burst(classified_data_rx->port, 0,
+				rx_pkts, MAX_PKT_BURST);
+		if (unlikely(n_rx == 0))
+			continue;
 
 #ifdef SPP_RINGLATENCYSTATS_ENABLE
-			if (core_info->rx_ports[0].if_type == RING)
-				spp_ringlatencystats_calculate_latency(
-						core_info->rx_ports[0].if_no, rx_pkts, n_rx);
+		if (classified_data_rx->if_type == RING)
+			spp_ringlatencystats_calculate_latency(
+					classified_data_rx->if_no, rx_pkts, n_rx);
 #endif
 
-			/* classify and transmit (filled) */
-			classify_packet(rx_pkts, n_rx, classifier_info, classified_data);
-		}
+		/* classify and transmit (filled) */
+		classify_packet(rx_pkts, n_rx, classifier_info, classified_data_tx);
 	}
 
 	/* just in case */
-	change_update_index(classifier_mng_info, lcore_id);
+	change_update_index(classifier_mng_info, id);
 
 	/* uninitialize */
 	uninit_classifier(classifier_mng_info);
 
-	core_info->status = SPP_CORE_STOP;
-
 	return 0;
 }
 
@@ -542,7 +584,7 @@ int spp_classifier_mac_iterate_table(
 	struct classifier_mac_mng_info *classifier_mng_info;
 	struct classifier_mac_info *classifier_info;
 	struct classified_data *classified_data;
-	struct spp_config_port_info port;
+	struct spp_port_index port;
 	char mac_addr_str[ETHER_ADDR_STR_BUF_SZ];
 
 	for (i = 0; i < RTE_MAX_LCORE; i++) {
@@ -553,7 +595,7 @@ int spp_classifier_mac_iterate_table(
 		classifier_info = classifier_mng_info->info + 
 				classifier_mng_info->ref_index;
 
-		classified_data = classifier_mng_info->classified_data;
+		classified_data = classifier_info->classified_data_tx;
 
 		RTE_LOG(DEBUG, SPP_CLASSIFIER_MAC,
 			"Core[%u] Start iterate classifier table.\n", i);
@@ -565,10 +607,11 @@ int spp_classifier_mac_iterate_table(
 			(*params->element_proc)(
 					params->opaque,
 					SPP_CLASSIFIER_TYPE_MAC,
-					SPP_CONFIG_DEFAULT_CLASSIFIED_SPEC_STR,
+					SPP_DEFAULT_CLASSIFIED_SPEC_STR,
 					&port);
 		}
 
+		next = 0;
 		while(1) {
 			ret = rte_hash_iterate(classifier_info->classifier_table,
 					&key, &data, &next);
diff --git a/src/vf/classifier_mac.h b/src/vf/classifier_mac.h
index b1d0198..f182668 100644
--- a/src/vf/classifier_mac.h
+++ b/src/vf/classifier_mac.h
@@ -2,7 +2,7 @@
 #define _CLASSIFIER_MAC_H_
 
 /* forward declaration */
-struct spp_core_info;
+struct spp_component_info;
 struct spp_iterate_classifier_table_params;
 
 /**
@@ -13,21 +13,21 @@ int spp_classifier_mac_init(void);
 /**
  * classifier(mac address) update component info.
  *
- * @param core_info
- *  point to struct spp_core_info.
+ * @param component_info
+ *  point to struct spp_component_info.
  *
  * @ret_val 0  succeeded.
  * @ret_val -1 failed.
  */
-int spp_classifier_mac_update(struct spp_core_info *core_info);
+int spp_classifier_mac_update(struct spp_component_info *component_info);
 
 /**
  * classifier(mac address) thread function.
  *
- * @param arg
- *  pointer to struct spp_core_info.
+ * @param id
+ *  unique component ID.
  */
-int spp_classifier_mac_do(void *arg);
+int spp_classifier_mac_do(int id);
 
 /**
  * classifier(mac address) iterate classifier table.
diff --git a/src/vf/command_dec.c b/src/vf/command_dec.c
index 9363b8f..166901c 100644
--- a/src/vf/command_dec.c
+++ b/src/vf/command_dec.c
@@ -5,7 +5,6 @@
 #include <rte_branch_prediction.h>
 
 #include "spp_vf.h"
-#include "spp_config.h"
 #include "command_dec.h"
 
 #define RTE_LOGTYPE_SPP_COMMAND_PROC RTE_LOGTYPE_USER1
@@ -19,6 +18,28 @@ static const char *CLASSIFILER_TYPE_STRINGS[] = {
 	/* termination */ "",
 };
 
+/* command action type string list
+	do it same as the order of enum spp_command_action (spp_vf.h) */
+static const char *COMMAND_ACTION_STRINGS[] = {
+	"none",
+	"start",
+	"stop",
+	"add",
+	"del",
+
+	/* termination */ "",
+};
+
+/* port rxtx string list
+	do it same as the order of enum spp_port_rxtx (spp_vf.h) */
+static const char *PORT_RXTX_STRINGS[] = {
+	"none",
+	"rx",
+	"tx",
+
+	/* termination */ "",
+};
+
 /* set decode error */
 inline int
 set_decode_error(struct spp_command_decode_error *error,
@@ -75,13 +96,44 @@ get_arrary_index(const char *match, const char *list[])
 	return -1;
 }
 
+/* Get unsigned int type value */
+static int
+get_uint_value(	unsigned int *output,
+		const char *arg_val,
+		unsigned int min,
+		unsigned int max)
+{
+	unsigned int ret = 0;
+	char *endptr = NULL;
+	ret = strtoul(arg_val, &endptr, 0);
+	if (unlikely(endptr == arg_val) || unlikely(*endptr != '\0'))
+		return -1;
+
+	if (unlikely(ret < min) || unlikely(ret > max))
+		return -1;
+
+	*output = ret;
+	return 0;
+}
+
+/* decoding procedure of string */
+static int
+decode_str_value(char *output, const char *arg_val)
+{
+	if (strlen(arg_val) >= SPP_CMD_VALUE_BUFSZ)
+		return -1;
+
+	strcpy(output, arg_val);
+	return 0;
+}
+
 /* decoding procedure of port */
 static int
 decode_port_value(void *output, const char *arg_val)
 {
 	int ret = 0;
-	struct spp_config_port_info *port = output;
-	ret = spp_config_get_if_info(arg_val, &port->if_type, &port->if_no);
+	struct spp_port_index *port = output;
+	ret = spp_get_if_info(arg_val, &port->if_type, &port->if_no);
 	if (unlikely(ret != 0)) {
 		RTE_LOG(ERR, SPP_COMMAND_PROC, "Bad port. val=%s\n", arg_val);
 		return -1;
@@ -90,6 +142,188 @@ decode_port_value(void *output, const char *arg_val)
 	return 0;
 }
 
+/* decoding procedure of core */
+static int
+decode_core_value(void *output, const char *arg_val)
+{
+	int ret = 0;
+	ret = get_uint_value(output, arg_val, 0, RTE_MAX_LCORE-1);
+	if (unlikely(ret < 0)) {
+		RTE_LOG(ERR, SPP_COMMAND_PROC, "Bad core id. val=%s\n", arg_val);
+		return -1;
+	}
+
+	return 0;
+}
+
+/* decoding procedure of action for component command */
+static int
+decode_component_action_value(void *output, const char *arg_val)
+{
+	int ret = 0;
+	ret = get_arrary_index(arg_val, COMMAND_ACTION_STRINGS);
+	if (unlikely(ret <= 0)) {
+		RTE_LOG(ERR, SPP_COMMAND_PROC, "Unknown component action. val=%s\n", arg_val);
+		return -1;
+	}
+
+	if (unlikely(ret != SPP_CMD_ACTION_START) && unlikely(ret != SPP_CMD_ACTION_STOP)) {
+		RTE_LOG(ERR, SPP_COMMAND_PROC, "Unknown component action. val=%s\n", arg_val);
+		return -1;
+	}
+
+	*(int *)output = ret;
+	return 0;
+}
+
+/* decoding procedure of action for component command */
+static int
+decode_component_name_value(void *output, const char *arg_val)
+{
+	int ret = 0;
+	struct spp_command_component *component = output;
+
+	/* "stop" has no core ID parameter. */
+	if (component->action == SPP_CMD_ACTION_START) {
+		ret = spp_get_component_id(arg_val);
+		if (unlikely(ret >= 0)) {
+			RTE_LOG(ERR, SPP_COMMAND_PROC,
+					"Component name in used. val=%s\n",
+					arg_val);
+			return -1;
+		}
+	}
+
+	return decode_str_value(component->name, arg_val);
+}
+
+/* decoding procedure of core id for component command */
+static int
+decode_component_core_value(void *output, const char *arg_val)
+{
+	struct spp_command_component *component = output;
+
+	/* "stop" has no core ID parameter. */
+	if (component->action != SPP_CMD_ACTION_START)
+		return 0;
+
+	return decode_core_value(&component->core, arg_val);
+}
+
+/* decoding procedure of type for component command */
+static int
+decode_component_type_value(void *output, const char *arg_val)
+{
+	enum spp_component_type org_type, set_type;
+	struct spp_command_component *component = output;
+
+	/* "stop" has no type parameter. */
+	if (component->action != SPP_CMD_ACTION_START)
+		return 0;
+
+	set_type = spp_change_component_type(arg_val);
+	if (unlikely(set_type <= 0)) {
+		RTE_LOG(ERR, SPP_COMMAND_PROC,
+				"Unknown component type. val=%s\n",
+				arg_val);
+		return -1;
+	}
+
+	org_type = spp_get_component_type_update(component->core);
+	if ((org_type != SPP_COMPONENT_UNUSE) && (org_type != set_type)) {
+		RTE_LOG(ERR, SPP_COMMAND_PROC,
+				"Component type does not match. val=%s (org=%d, new=%d)\n",
+				arg_val, org_type, set_type);
+		return -1;
+	}
+
+	component->type = set_type;
+	return 0;
+}
+
+/* decoding procedure of action for port command */
+static int
+decode_port_action_value(void *output, const char *arg_val)
+{
+	int ret = 0;
+	ret = get_arrary_index(arg_val, COMMAND_ACTION_STRINGS);
+	if (unlikely(ret <= 0)) {
+		RTE_LOG(ERR, SPP_COMMAND_PROC, "Unknown port action. val=%s\n", arg_val);
+		return -1;
+	}
+
+	if (unlikely(ret != SPP_CMD_ACTION_ADD) && unlikely(ret != SPP_CMD_ACTION_DEL)) {
+		RTE_LOG(ERR, SPP_COMMAND_PROC, "Unknown port action. val=%s\n", arg_val);
+		return -1;
+	}
+
+	*(int *)output = ret;
+	return 0;
+}
+
+/* decoding procedure of port for port command */
+static int
+decode_port_port_value(void *output, const char *arg_val)
+{
+	int ret = -1;
+	struct spp_port_index tmp_port;
+	struct spp_command_port *port = output;
+
+	ret = decode_port_value(&tmp_port, arg_val);
+	if (ret < 0)
+		return -1;
+
+	if ((port->action == SPP_CMD_ACTION_ADD) &&
+			(spp_check_used_port(tmp_port.if_type, tmp_port.if_no, SPP_PORT_RXTX_RX) >= 0) &&
+			(spp_check_used_port(tmp_port.if_type, tmp_port.if_no, SPP_PORT_RXTX_TX) >= 0)) {
+		RTE_LOG(ERR, SPP_COMMAND_PROC, "Port in used. (port command) val=%s\n", arg_val);
+		return -1;
+	}
+
+	port->port.if_type = tmp_port.if_type;
+	port->port.if_no   = tmp_port.if_no;
+	return 0;
+}
+
+/* decoding procedure of rxtx type for port command */
+static int
+decode_port_rxtx_value(void *output, const char *arg_val)
+{
+	int ret = 0;
+	struct spp_command_port *port = output;
+
+	ret = get_arrary_index(arg_val, PORT_RXTX_STRINGS);
+	if (unlikely(ret <= 0)) {
+		RTE_LOG(ERR, SPP_COMMAND_PROC, "Unknown port rxtx. val=%s\n", arg_val);
+		return -1;
+	}
+
+	if ((port->action == SPP_CMD_ACTION_ADD) &&
+			(spp_check_used_port(port->port.if_type, port->port.if_no, ret) >= 0)) {
+		RTE_LOG(ERR, SPP_COMMAND_PROC, "Port in used. (port command) val=%s\n", arg_val);
+		return -1;
+	}
+
+	port->rxtx = ret;
+	return 0;
+}
+
+/* decoding procedure of component name for port command */
+static int
+decode_port_name_value(void *output, const char *arg_val)
+{
+	int ret = 0;
+
+	ret = spp_get_component_id(arg_val);
+	if (unlikely(ret < 0)) {
+		RTE_LOG(ERR, SPP_COMMAND_PROC, "Unknown component name. val=%s\n",
+				arg_val);
+		return -1;
+	}
+
+	return decode_str_value(output, arg_val);
+}
+
 /* decoding procedure of mac address string */
 static int
 decode_mac_addr_str_value(void *output, const char *arg_val)
@@ -98,10 +332,10 @@ decode_mac_addr_str_value(void *output, const char *arg_val)
 	const char *str_val = arg_val;
 
 	/* if default specification, convert to internal dummy address */
-	if (unlikely(strcmp(str_val, SPP_CONFIG_DEFAULT_CLASSIFIED_SPEC_STR) == 0))
-		str_val = SPP_CONFIG_DEFAULT_CLASSIFIED_DMY_ADDR_STR;
+	if (unlikely(strcmp(str_val, SPP_DEFAULT_CLASSIFIED_SPEC_STR) == 0))
+		str_val = SPP_DEFAULT_CLASSIFIED_DMY_ADDR_STR;
 
-	ret = spp_config_change_mac_str_to_int64(str_val);
+	ret = spp_change_mac_str_to_int64(str_val);
 	if (unlikely(ret < 0)) {
 		RTE_LOG(ERR, SPP_COMMAND_PROC, "Bad mac address string. val=%s\n",
 				str_val);
@@ -112,26 +346,46 @@ decode_mac_addr_str_value(void *output, const char *arg_val)
 	return 0;
 }
 
-/* decoding procedure of classifier type */
+/* decoding procedure of action for classifier_table command */
+static int
+decode_classifier_action_value(void *output, const char *arg_val)
+{
+	int ret = 0;
+	ret = get_arrary_index(arg_val, COMMAND_ACTION_STRINGS);
+	if (unlikely(ret <= 0)) {
+		RTE_LOG(ERR, SPP_COMMAND_PROC, "Unknown port action. val=%s\n", arg_val);
+		return -1;
+	}
+
+	if (unlikely(ret != SPP_CMD_ACTION_ADD) && unlikely(ret != SPP_CMD_ACTION_DEL)) {
+		RTE_LOG(ERR, SPP_COMMAND_PROC, "Unknown port action. val=%s\n", arg_val);
+		return -1;
+	}
+
+	*(int *)output = ret;
+	return 0;
+}
+
+/* decoding procedure of type for classifier_table command */
 static int
 decode_classifier_type_value(void *output, const char *arg_val)
 {
-        int ret = 0;
+	int ret = 0;
 	ret = get_arrary_index(arg_val, CLASSIFILER_TYPE_STRINGS);
-        if (unlikely(ret <= 0)) {
-                RTE_LOG(ERR, SPP_COMMAND_PROC, "Unknown classifier type. val=%s\n", arg_val);
-                return -1;
-        }
+	if (unlikely(ret <= 0)) {
+		RTE_LOG(ERR, SPP_COMMAND_PROC, "Unknown classifier type. val=%s\n", arg_val);
+		return -1;
+	}
 
-        *(int *)output = ret;
-        return 0;
+	*(int *)output = ret;
+	return 0;
 }
 
-/* decode procedure for classifier value */
+/* decoding procedure of value for classifier_table command */
 static int
 decode_classifier_value_value(void *output, const char *arg_val)
 {
-        int ret = -1;
+	int ret = -1;
 	struct spp_command_classifier_table *classifier_table = output;
 	switch(classifier_table->type) {
 		case SPP_CLASSIFIER_TYPE_MAC:
@@ -140,37 +394,70 @@ decode_classifier_value_value(void *output, const char *arg_val)
 		default:
 			break;
 	}
-        return ret;
+	return ret;
 }
 
-/* decode procedure for classifier port */
+/* decoding procedure of port for classifier_table command */
 static int
 decode_classifier_port_value(void *output, const char *arg_val)
 {
-	struct spp_config_port_info *port = output;
+	int ret = 0;
+	struct spp_command_classifier_table *classifier_table = output;
+	struct spp_port_index tmp_port;
+	int64_t mac_addr = 0;
+
+	ret = decode_port_value(&tmp_port, arg_val);
+	if (ret < 0)
+		return -1;
+
+	if (spp_check_added_port(tmp_port.if_type, tmp_port.if_no) == 0) {
+		RTE_LOG(ERR, SPP_COMMAND_PROC, "Port not added. val=%s\n", arg_val);
+		return -1;
+	}
+
+	if (unlikely(classifier_table->action == SPP_CMD_ACTION_ADD)) {
+		if (!spp_check_mac_used_port(0, tmp_port.if_type, tmp_port.if_no)) {
+			RTE_LOG(ERR, SPP_COMMAND_PROC,
+					"Port in used. (classifier_table command) val=%s\n",
+					arg_val);
+			return -1;
+		}
+	} else if (unlikely(classifier_table->action == SPP_CMD_ACTION_DEL)) {
+		mac_addr = spp_change_mac_str_to_int64(classifier_table->value);
+		if (mac_addr < 0)
+			return -1;
 
-        if (strcmp(arg_val, SPP_CMD_UNUSE) == 0) {
-                port->if_type = UNDEF;
-                port->if_no = 0;
-                return 0;
-        }
+		if (!spp_check_mac_used_port((uint64_t)mac_addr, tmp_port.if_type, tmp_port.if_no)) {
+			RTE_LOG(ERR, SPP_COMMAND_PROC,
+					"Port in used. (classifier_table command) val=%s\n",
+					arg_val);
+			return -1;
+		}
+	}
 
-	return decode_port_value(port, arg_val);
+	classifier_table->port.if_type = tmp_port.if_type;
+	classifier_table->port.if_no   = tmp_port.if_no;
+	return 0;
 }
 
 #define DECODE_PARAMETER_LIST_EMPTY { NULL, 0, NULL }
 
 /* parameter list for decoding */
 struct decode_parameter_list {
-        const char *name;
-        size_t offset;
-        int (*func)(void *output, const char *arg_val);
+	const char *name;
+	size_t offset;
+	int (*func)(void *output, const char *arg_val);
 };
 
 /* parameter list for each command */
 static struct decode_parameter_list parameter_list[][SPP_CMD_MAX_PARAMETERS] = {
 	{                                /* classifier_table */
 		{
+			.name = "action",
+			.offset = offsetof(struct spp_command, spec.classifier_table.action),
+			.func = decode_classifier_action_value
+		},
+		{
 			.name = "type",
 			.offset = offsetof(struct spp_command, spec.classifier_table.type),
 			.func = decode_classifier_type_value
@@ -182,7 +469,7 @@ static struct decode_parameter_list parameter_list[][SPP_CMD_MAX_PARAMETERS] = {
 		},
 		{
 			.name = "port",
-			.offset = offsetof(struct spp_command, spec.classifier_table.port),
+			.offset = offsetof(struct spp_command, spec.classifier_table),
 			.func = decode_classifier_port_value
 		},
 		DECODE_PARAMETER_LIST_EMPTY,
@@ -190,6 +477,53 @@ static struct decode_parameter_list parameter_list[][SPP_CMD_MAX_PARAMETERS] = {
 	{ DECODE_PARAMETER_LIST_EMPTY }, /* flush            */
 	{ DECODE_PARAMETER_LIST_EMPTY }, /* _get_client_id   */
 	{ DECODE_PARAMETER_LIST_EMPTY }, /* status           */
+	{ DECODE_PARAMETER_LIST_EMPTY }, /* exit             */
+	{                                /* component        */
+		{
+			.name = "action",
+			.offset = offsetof(struct spp_command, spec.component.action),
+			.func = decode_component_action_value
+		},
+		{
+			.name = "component name",
+			.offset = offsetof(struct spp_command, spec.component),
+			.func = decode_component_name_value
+		},
+		{
+			.name = "core",
+			.offset = offsetof(struct spp_command, spec.component),
+			.func = decode_component_core_value
+		},
+		{
+			.name = "component type",
+			.offset = offsetof(struct spp_command, spec.component),
+			.func = decode_component_type_value
+		},
+		DECODE_PARAMETER_LIST_EMPTY,
+	},
+	{                                /* port             */
+		{
+			.name = "action",
+			.offset = offsetof(struct spp_command, spec.port.action),
+			.func = decode_port_action_value
+		},
+		{
+			.name = "port",
+			.offset = offsetof(struct spp_command, spec.port),
+			.func = decode_port_port_value
+		},
+		{
+			.name = "port rxtx",
+			.offset = offsetof(struct spp_command, spec.port),
+			.func = decode_port_rxtx_value
+		},
+		{
+			.name = "component name",
+			.offset = offsetof(struct spp_command, spec.port.name),
+			.func = decode_port_name_value
+		},
+		DECODE_PARAMETER_LIST_EMPTY,
+	},
 	{ DECODE_PARAMETER_LIST_EMPTY }, /* termination      */
 };
 
@@ -227,10 +561,13 @@ struct decode_command_list {
 
 /* command list */
 static struct decode_command_list command_list[] = {
-	{ "classifier_table", 4, 4, decode_comand_parameter_in_list }, /* classifier_table */
+	{ "classifier_table", 5, 5, decode_comand_parameter_in_list }, /* classifier_table */
 	{ "flush",            1, 1, NULL                            }, /* flush            */
 	{ "_get_client_id",   1, 1, NULL                            }, /* _get_client_id   */
 	{ "status",           1, 1, NULL                            }, /* status           */
+	{ "exit",             1, 1, NULL                            }, /* exit             */
+	{ "component",        3, 5, decode_comand_parameter_in_list }, /* port             */
+	{ "port",             5, 5, decode_comand_parameter_in_list }, /* port             */
 	{ "",                 0, 0, NULL                            }  /* termination      */
 };
 
@@ -310,6 +647,9 @@ spp_command_decode_request(struct spp_command_request *request, const char *requ
 		case SPP_CMDTYPE_STATUS:
 			request->is_requested_status = 1;
 			break;
+		case SPP_CMDTYPE_EXIT:
+			request->is_requested_exit = 1;
+			break;
 		default:
 			/* nothing to do */
 			break;
diff --git a/src/vf/command_dec.h b/src/vf/command_dec.h
index 8850485..359f5e5 100644
--- a/src/vf/command_dec.h
+++ b/src/vf/command_dec.h
@@ -1,6 +1,8 @@
 #ifndef _COMMAND_DEC_H_
 #define _COMMAND_DEC_H_
 
+//#include "spp_vf.h"
+
 /* max number of command per request */
 #define SPP_CMD_MAX_COMMANDS 32
 
@@ -16,9 +18,6 @@
 /* string that specify unused */
 #define SPP_CMD_UNUSE "unuse"
 
-/* component type */
-#define spp_component_type spp_core_type
-
 /* decode error code */
 enum spp_command_decode_error_code {
 	/* not use 0, in general 0 is ok */
@@ -36,31 +35,17 @@ enum spp_command_type {
 	SPP_CMDTYPE_FLUSH,
 	SPP_CMDTYPE_CLIENT_ID,
 	SPP_CMDTYPE_STATUS,
+	SPP_CMDTYPE_EXIT,
+	SPP_CMDTYPE_COMPONENT,
+	SPP_CMDTYPE_PORT,
 };
 
-#if 0 /* not supported yet */
-/* "add" command parameters */
-struct spp_command_add {
-	int num_port;
-	struct spp_config_port_info ports[RTE_MAX_ETHPORTS];
-};
-
-/* "component" command specific parameters */
-struct spp_command_component {
-	enum spp_component_type type;
-	unsigned int core_id;
-	int num_rx_port;
-	int num_tx_port;
-	struct spp_config_port_info rx_ports[RTE_MAX_ETHPORTS];
-	struct spp_config_port_info tx_ports[RTE_MAX_ETHPORTS];
-};
-#endif
-
 /* "classifier_table" command specific parameters */
 struct spp_command_classifier_table {
+	enum spp_command_action action;
 	enum spp_classifier_type type;
 	char value[SPP_CMD_VALUE_BUFSZ];
-	struct spp_config_port_info port;
+	struct spp_port_index port;
 };
 
 /* "flush" command specific parameters */
@@ -68,17 +53,31 @@ struct spp_command_flush {
 	/* nothing specific */
 };
 
+/* "component" command parameters */
+struct spp_command_component {
+	enum spp_command_action action;
+	char name[SPP_CMD_NAME_BUFSZ];
+	unsigned int core;
+	enum spp_component_type type;
+};
+
+/* "port" command parameters */
+struct spp_command_port {
+	enum spp_command_action action;
+	struct spp_port_index port;
+	enum spp_port_rxtx rxtx;
+	char name[SPP_CMD_NAME_BUFSZ];
+};
+
 /* command parameters */
 struct spp_command {
 	enum spp_command_type type;
 
 	union {
-#if 0 /* not supported yet */
-		struct spp_command_add add;
-		struct spp_command_component component;
-#endif
 		struct spp_command_classifier_table classifier_table;
 		struct spp_command_flush flush;
+		struct spp_command_component component;
+		struct spp_command_port port;
 	} spec;
 };
 
@@ -90,6 +89,7 @@ struct spp_command_request {
 
 	int is_requested_client_id;
 	int is_requested_status;
+	int is_requested_exit;
 };
 
 /* decode error information */
diff --git a/src/vf/command_proc.c b/src/vf/command_proc.c
index ef1ae81..0a45874 100644
--- a/src/vf/command_proc.c
+++ b/src/vf/command_proc.c
@@ -7,7 +7,6 @@
 #include <jansson.h>
 
 #include "spp_vf.h"
-#include "spp_config.h"
 #include "string_buffer.h"
 #include "command_conn.h"
 #include "command_dec.h"
@@ -40,6 +39,7 @@ execute_command(const struct spp_command *command)
 	case SPP_CMDTYPE_CLASSIFIER_TABLE:
 		RTE_LOG(INFO, SPP_COMMAND_PROC, "Execute classifier_table command.\n");
 		ret = spp_update_classifier_table(
+				command->spec.classifier_table.action,
 				command->spec.classifier_table.type,
 				command->spec.classifier_table.value,
 				&command->spec.classifier_table.port);
@@ -50,6 +50,25 @@ execute_command(const struct spp_command *command)
 		ret = spp_flush();
 		break;
 
+	case SPP_CMDTYPE_COMPONENT:
+		RTE_LOG(INFO, SPP_COMMAND_PROC, "Execute component command.\n");
+		ret = spp_update_component(
+				command->spec.component.action,
+				command->spec.component.name,
+				command->spec.component.core,
+				command->spec.component.type);
+		break;
+
+	case SPP_CMDTYPE_PORT:
+		RTE_LOG(INFO, SPP_COMMAND_PROC, "Execute port command. (act = %d)\n",
+				command->spec.port.action);
+		ret = spp_update_port(
+				command->spec.port.action,
+				&command->spec.port.port,
+				command->spec.port.rxtx,
+				command->spec.port.name);
+		break;
+
 	default:
 		RTE_LOG(INFO, SPP_COMMAND_PROC, "Execute other command. type=%d\n", command->type);
 		/* nothing to do here */
@@ -230,12 +249,12 @@ int append_classifier_element_value(
 		void *opaque,
 		__rte_unused enum spp_classifier_type type,
 		const char *data,
-		const struct spp_config_port_info *port)
+		const struct spp_port_index *port)
 {
 	json_t *parent_obj = (json_t *)opaque;
 
 	char port_str[64];
-	spp_config_format_port_string(port_str, port->if_type, port->if_no);
+	spp_format_port_string(port_str, port->if_type, port->if_no);
 
 	json_array_append_new(parent_obj, json_pack(
 			"{ssssss}",
@@ -416,7 +435,7 @@ process_request(int *sock, const char *request_str, size_t request_str_len)
 		/* send error response */
 		send_decode_error_response(sock, &request, &decode_error);
 		RTE_LOG(DEBUG, SPP_COMMAND_PROC, "End command request processing.\n");
-		return ret;
+		return 0;
 	}
 
 	RTE_LOG(DEBUG, SPP_COMMAND_PROC, "Command request is valid. "
@@ -438,6 +457,13 @@ process_request(int *sock, const char *request_str, size_t request_str_len)
 		command_results[i].code = CRES_SUCCESS;
 	}
 
+	if (request.is_requested_exit) {
+		/* Terminated by process exit command.                       */
+		/* Other route is normal end because it responds to command. */
+		RTE_LOG(INFO, SPP_COMMAND_PROC, "No response with process exit command.");
+		return -1;
+	}
+
 	/* send response */
 	send_command_result_response(sock, &request, command_results);
 
@@ -489,5 +515,5 @@ spp_command_proc_do(void)
 	ret = process_request(&sock, msgbuf, msg_ret);
 	spp_strbuf_remove_front(msgbuf, msg_ret);
 
-	return 0;
+	return ret;
 }
diff --git a/src/vf/command_proc.h b/src/vf/command_proc.h
index 37e55ad..05cb1f1 100644
--- a/src/vf/command_proc.h
+++ b/src/vf/command_proc.h
@@ -20,7 +20,8 @@ spp_command_proc_init(const char *controller_ip, int controller_port);
  * process command from controller.
  *
  * @retval 0  succeeded.
- * @retval -1 failed.
+ * @retval -1 process termination is required.
+ *            (occurred connection failure, or received exit command)
  */
 int
 spp_command_proc_do(void);
diff --git a/src/vf/spp_config.c b/src/vf/spp_config.c
index 55129ac..9170281 100644
--- a/src/vf/spp_config.c
+++ b/src/vf/spp_config.c
@@ -136,11 +136,11 @@ config_get_str_value(const json_t *obj, const char *path, char *value)
 static void
 config_init_data(struct spp_config_area *config)
 {
-  /* Clear config area with zero */
+	/* Clear config area with zero */
 	memset(config, 0x00, sizeof(struct spp_config_area));
 	int core_cnt, port_cnt, table_cnt;
 
-  /* Set all of interface type of ports and mac tables to UNDEF */
+	/* Set all of interface type of ports and mac tables to UNDEF */
 	for (core_cnt = 0; core_cnt < SPP_CONFIG_CORE_MAX; core_cnt++) {
 		for (port_cnt = 0; port_cnt < RTE_MAX_ETHPORTS; port_cnt++) {
 			config->proc.functions[core_cnt].rx_ports[port_cnt].if_type = UNDEF;
@@ -188,7 +188,7 @@ spp_config_get_if_info(const char *port, enum port_type *if_type, int *if_no)
 		return -1;
 	}
 
-  /* Change type of number of interface */
+	/* Change type of number of interface */
 	int ret_no = strtol(no_str, &endptr, 0);
 	if (unlikely(no_str == endptr) || unlikely(*endptr != '\0')) { 
 		/* No IF number */
@@ -321,7 +321,7 @@ config_load_classifier_table(const json_t *obj,
 	}
 	classifier_table->num_table = array_num;
 
-  /* Setup for each of mac tables */
+	/* Setup for each of mac tables */
 	struct spp_config_mac_table_element *tmp_table = NULL;
 	char if_str[SPP_CONFIG_STR_LEN];
 	int table_cnt = 0;
@@ -346,10 +346,10 @@ config_load_classifier_table(const json_t *obj,
 			return -1;
 		}
 
-    /**
-     * If mac address is set to 'default', replace it to reserved
-     * dummy address for validation.
-     */
+		/**
+		  * If mac address is set to 'default', replace it to reserved
+		  * dummy address for validation.
+		  */
 		if (unlikely(strcmp(tmp_table->mac_addr_str,
 				SPP_CONFIG_DEFAULT_CLASSIFIED_SPEC_STR) == 0))
 			strcpy(tmp_table->mac_addr_str,
@@ -375,7 +375,7 @@ config_load_classifier_table(const json_t *obj,
 				table_cnt, JSONPATH_PORT);
 			return -1;
 		}
-    /* And separate it to type and number */
+		/* And separate it to type and number */
 		int ret_if = spp_config_get_if_info(if_str, &tmp_table->port.if_type,
 				&tmp_table->port.if_no);
 		if (unlikely(ret_if != 0)) {
@@ -433,7 +433,7 @@ config_set_rx_port(enum spp_core_type type, json_t *obj,
 			return -1;
 		}
 
-	  /* Check if the size of array is not over RTE_MAX_ETHPORTS */
+		/* Check if the size of array is not over RTE_MAX_ETHPORTS */
 		int port_num = json_array_size(array_obj);
 		if (unlikely(port_num <= 0) ||
 				unlikely(port_num > RTE_MAX_ETHPORTS)) {
@@ -557,7 +557,7 @@ config_set_tx_port(enum spp_core_type type, json_t *obj,
 				return -1;
 			}
 
-	    /* Check if the size of array is not over RTE_MAX_ETHPORTS */
+			/* Check if the size of array is not over RTE_MAX_ETHPORTS */
 			int port_num = json_array_size(array_obj);
 			if (unlikely(port_num <= 0) ||
 					unlikely(port_num > RTE_MAX_ETHPORTS)) {
@@ -579,7 +579,7 @@ config_set_tx_port(enum spp_core_type type, json_t *obj,
 					return -1;
 				}
 
-        /* Get sending port */
+				/* Get sending port */
 				if (unlikely(!json_is_string(elements_obj))) {
 					RTE_LOG(ERR, APP, "Not a string. (path = %s, No = %d, route = classifier)\n",
 							JSONPATH_TX_PORT, array_cnt);
@@ -587,7 +587,7 @@ config_set_tx_port(enum spp_core_type type, json_t *obj,
 				}
 				strcpy(if_str, json_string_value(elements_obj));
 
-		    /* Separate it to interface type and number */
+				/* Separate it to interface type and number */
 				int ret_if = spp_config_get_if_info(if_str, &tmp_tx_port->if_type,
 						&tmp_tx_port->if_no);
 				if (unlikely(ret_if != 0)) {
diff --git a/src/vf/spp_forward.c b/src/vf/spp_forward.c
index afe7c03..8a0980a 100644
--- a/src/vf/spp_forward.c
+++ b/src/vf/spp_forward.c
@@ -1,3 +1,5 @@
+#include <rte_cycles.h>
+
 #include "spp_vf.h"
 #include "ringlatencystats.h"
 #include "spp_forward.h"
@@ -5,21 +7,106 @@
 #define RTE_LOGTYPE_FORWARD RTE_LOGTYPE_USER1
 
 /* A set of port info of rx and tx */
-struct rxtx {
-	struct spp_core_port_info rx;
-	struct spp_core_port_info tx;
+struct forward_rxtx {
+	struct spp_port_info rx;
+	struct spp_port_info tx;
+};
+
+struct forward_path {
+	int num;
+	struct forward_rxtx ports[RTE_MAX_ETHPORTS];
+};
+
+struct forward_info {
+	enum spp_component_type type;
+	volatile int ref_index;
+	volatile int upd_index;
+	struct forward_path path[SPP_INFO_AREA_MAX];
 };
 
-/* Set destination port as source */
+struct forward_info g_forward_info[RTE_MAX_LCORE];
+
+/* Clear info */
+void
+spp_forward_init(void)
+{
+	int cnt = 0;
+	memset(&g_forward_info, 0x00, sizeof(g_forward_info));
+	for (cnt = 0; cnt < RTE_MAX_LCORE; cnt++) {
+		g_forward_info[cnt].ref_index = 0;
+		g_forward_info[cnt].upd_index = 1;
+	}
+}
+
+/* Clear info for one element. */
 static void
-set_use_interface(struct spp_core_port_info *dst,
-		struct spp_core_port_info *src)
+clear_forward_info(int id)
 {
-	dst->if_type   = src->if_type;
-	dst->if_no     = src->if_no;
-	dst->dpdk_port = src->dpdk_port;
+	struct forward_info *info = &g_forward_info[id];
+	info->type = SPP_COMPONENT_UNUSE;
+	memset(&g_forward_info[id].path, 0x00, sizeof(struct forward_path));
 }
 
+/* Update forward info */
+int
+spp_forward_update(struct spp_component_info *component)
+{
+	int cnt = 0;
+	int num_rx = component->num_rx_port;
+	int num_tx = component->num_tx_port;
+	int max = (num_rx > num_tx)?num_rx*num_tx:num_tx;
+	struct forward_info *info = &g_forward_info[component->component_id];
+	struct forward_path *path = &info->path[info->upd_index];
+
+	/* Forward component allows only one receiving port. */
+	if ((component->type == SPP_COMPONENT_FORWARD) && unlikely(num_rx > 1)) {
+		RTE_LOG(ERR, FORWARD, "Component[%d] Setting error. (type = %d, rx = %d)\n",
+			component->component_id, component->type, num_rx);
+		return -1;
+	}
+
+	/* Component allows only one transmit port. */
+	if (unlikely(num_tx != 0) && unlikely(num_tx != 1)) {
+		RTE_LOG(ERR, FORWARD, "Component[%d] Setting error. (type = %d, tx = %d)\n",
+			component->component_id, component->type, num_tx);
+		return -1;
+	}
+
+	clear_forward_info(component->component_id);
+
+	RTE_LOG(INFO, FORWARD,
+			"Component[%d] Start update component. (type = %d)\n",
+			component->component_id, component->type);
+
+	info->type = component->type;
+	path->num = component->num_rx_port;
+	for (cnt = 0; cnt < num_rx; cnt++)
+		memcpy(&path->ports[cnt].rx, component->rx_ports[cnt],
+				sizeof(struct spp_port_info));
+
+	/* Transmit port is set according with larger num_rx / num_tx. */
+	for (cnt = 0; cnt < max; cnt++)
+		memcpy(&path->ports[cnt].tx, component->tx_ports[0],
+				sizeof(struct spp_port_info));
+
+	info->upd_index = info->ref_index;
+	while(likely(info->ref_index == info->upd_index))
+		rte_delay_us_block(SPP_CHANGE_UPDATE_INTERVAL);
+
+	RTE_LOG(INFO, FORWARD, "Component[%d] Complete update component. (type = %d)\n",
+			component->component_id, component->type);
+
+	return 0;
+}
+
+/* Change index of forward info */
+static inline void
+change_forward_index(int id)
+{
+	struct forward_info *info = &g_forward_info[id];
+	if (info->ref_index == info->upd_index)
+		info->ref_index = (info->upd_index+1)%SPP_INFO_AREA_MAX;
+}
 /**
  * Forwarding packets as forwarder or merger
  *
@@ -27,75 +114,49 @@ set_use_interface(struct spp_core_port_info *dst,
  * as an argument of void and typecasted to spp_config_info.
  */
 int
-spp_forward(void *arg)
+spp_forward(int id)
 {
-	unsigned int lcore_id = rte_lcore_id();
-	struct spp_core_info *core_info = (struct spp_core_info *)arg;
-	int if_cnt, rxtx_num = 0;
-	struct rxtx patch[RTE_MAX_ETHPORTS];
-
-  /* Decide the destination of forwarding */
-	rxtx_num = core_info->num_rx_port;
-	for (if_cnt = 0; if_cnt < rxtx_num; if_cnt++) {
-		set_use_interface(&patch[if_cnt].rx,
-				&core_info->rx_ports[if_cnt]);
-    /* Forwarding type is supposed to forwarder or merger */
-		if (core_info->type == SPP_CONFIG_FORWARD) {
-			set_use_interface(&patch[if_cnt].tx,
-					&core_info->tx_ports[if_cnt]);
-		} else {
-			set_use_interface(&patch[if_cnt].tx,
-					&core_info->tx_ports[0]);
-		}
-	}
+	int cnt, num, buf;
+	int nb_rx = 0;
+	int nb_tx = 0;
+	struct forward_info *info = &g_forward_info[id];
+	struct forward_path *path = NULL;
+	struct spp_port_info *rx;
+	struct spp_port_info *tx;
+	struct rte_mbuf *bufs[MAX_PKT_BURST];
 
-	core_info->status = SPP_CORE_IDLE;
-	RTE_LOG(INFO, FORWARD, "Core[%d] Start. (type = %d)\n", lcore_id,
-			core_info->type);
+	change_forward_index(id);
+	path = &info->path[info->ref_index];
+	num = path->num;
 
-	int cnt, nb_rx, nb_tx, buf;
-	struct spp_core_port_info *rx;
-	struct spp_core_port_info *tx;
-	struct rte_mbuf *bufs[MAX_PKT_BURST];
-	while (likely(core_info->status == SPP_CORE_IDLE) ||
-			likely(core_info->status == SPP_CORE_FORWARD)) {
-		while (likely(core_info->status == SPP_CORE_FORWARD)) {
-			for (cnt = 0; cnt < rxtx_num; cnt++) {
-				rx = &patch[cnt].rx;
-				tx = &patch[cnt].tx;
-
-				/* Receive packets */
-				nb_rx = rte_eth_rx_burst(rx->dpdk_port, 0, bufs, MAX_PKT_BURST);
-				if (unlikely(nb_rx == 0)) {
-					continue;
-				}
+	for (cnt = 0; cnt < num; cnt++) {
+		rx = &path->ports[cnt].rx;
+		tx = &path->ports[cnt].tx;
+
+		/* Receive packets */
+		nb_rx = rte_eth_rx_burst(rx->dpdk_port, 0, bufs, MAX_PKT_BURST);
+		if (unlikely(nb_rx == 0))
+			continue;
 
 #ifdef SPP_RINGLATENCYSTATS_ENABLE
-				if (rx->if_type == RING) {
-					spp_ringlatencystats_calculate_latency(rx->if_no,
-							bufs, nb_rx);
-				}
-				if (tx->if_type == RING) {
-					spp_ringlatencystats_add_time_stamp(tx->if_no,
-							bufs, nb_rx);
-				}
+		if (rx->if_type == RING)
+			spp_ringlatencystats_calculate_latency(rx->if_no,
+					bufs, nb_rx);
+
+		if (tx->if_type == RING)
+			spp_ringlatencystats_add_time_stamp(tx->if_no,
+					bufs, nb_rx);
 #endif /* SPP_RINGLATENCYSTATS_ENABLE */
 
-				/* Send packets */
-				nb_tx = rte_eth_tx_burst(tx->dpdk_port, 0, bufs, nb_rx);
+		/* Send packets */
+		if (tx->dpdk_port >= 0)
+			nb_tx = rte_eth_tx_burst(tx->dpdk_port, 0, bufs, nb_rx);
 
-				/* Discard remained packets to release mbuf */
-				if (unlikely(nb_tx < nb_rx)) {
-					for (buf = nb_tx; buf < nb_rx; buf++) {
-						rte_pktmbuf_free(bufs[buf]);
-					}
-				}
-			}
+		/* Discard remained packets to release mbuf */
+		if (unlikely(nb_tx < nb_rx)) {
+			for (buf = nb_tx; buf < nb_rx; buf++)
+				rte_pktmbuf_free(bufs[buf]);
 		}
 	}
-
-	RTE_LOG(INFO, FORWARD, "Core[%d] End. (type = %d)\n", lcore_id,
-			core_info->type);
-	core_info->status = SPP_CORE_STOP;
 	return 0;
 }
diff --git a/src/vf/spp_forward.h b/src/vf/spp_forward.h
index 33208bf..729dbe8 100644
--- a/src/vf/spp_forward.h
+++ b/src/vf/spp_forward.h
@@ -1,9 +1,16 @@
 #ifndef __SPP_FORWARD_H__
 #define __SPP_FORWARD_H__
 
+
+void spp_forward_init(void);
+
+void spp_forward_init_info(int id);
+
+int spp_forward_update(struct spp_component_info *component);
+
 /*
  * Merge/Forward
  */
-int spp_forward(void *arg);
+int spp_forward(int id);
 
 #endif /* __SPP_FORWARD_H__ */
diff --git a/src/vf/spp_vf.c b/src/vf/spp_vf.c
index c7268e5..d6eb7b2 100644
--- a/src/vf/spp_vf.c
+++ b/src/vf/spp_vf.c
@@ -5,6 +5,7 @@
 #include <rte_eth_ring.h>
 #include <rte_eth_vhost.h>
 #include <rte_memzone.h>
+#include <rte_cycles.h>
 
 #include "spp_vf.h"
 #include "ringlatencystats.h"
@@ -16,13 +17,16 @@
 #define SPP_CORE_STATUS_CHECK_MAX 5
 #define SPP_RING_LATENCY_STATS_SAMPLING_INTERVAL 1000000
 
+#define CORE_TYPE_CLASSIFIER_MAC_STR "classifier_mac"
+#define CORE_TYPE_MERGE_STR          "merge"
+#define CORE_TYPE_FORWARD_STR        "forward"
+
 /* getopt_long return value for long option */
 enum SPP_LONGOPT_RETVAL {
 	SPP_LONGOPT_RETVAL__ = 127,
 
 	/* add below */
 	/* TODO(yasufum) add description what and why add below */
-	SPP_LONGOPT_RETVAL_CONFIG,
 	SPP_LONGOPT_RETVAL_CLIENT_ID,
 	SPP_LONGOPT_RETVAL_VHOST_CLIENT
 };
@@ -35,37 +39,41 @@ struct startup_param {
 	int vhost_client;
 };
 
-/* Status of patch and its cores, mac address assinged for it and port info */
-struct patch_info {
-	int      use_flg;
-	int      dpdk_port;  /* TODO(yasufum) add desc for what is this */
-	int      rx_core_no;
-	int      tx_core_no;
-	char     mac_addr_str[SPP_CONFIG_STR_LEN];
-	uint64_t mac_addr;
-	struct   spp_core_port_info *rx_core;
-	struct   spp_core_port_info *tx_core;
-};
-
-/* Manage number of interfaces and patch information  as global variable */
+/* Manage number of interfaces  and port information as global variable */
 /* TODO(yasufum) refactor, change if to iface */
 struct if_info {
 	int num_nic;
 	int num_vhost;
 	int num_ring;
-	struct patch_info nic_patchs[RTE_MAX_ETHPORTS];
-	struct patch_info vhost_patchs[RTE_MAX_ETHPORTS];
-	struct patch_info ring_patchs[RTE_MAX_ETHPORTS];
+	struct spp_port_info nic[RTE_MAX_ETHPORTS];
+	struct spp_port_info vhost[RTE_MAX_ETHPORTS];
+	struct spp_port_info ring[RTE_MAX_ETHPORTS];
+};
+
+/* Manage component running in core as global variable */
+struct core_info {
+	volatile enum spp_component_type type;
+	int num;
+	int id[RTE_MAX_LCORE];
+};
+
+/* Manage core status and component information as global variable */
+struct core_mng_info {
+	volatile enum spp_core_status status;
+	volatile int ref_index;
+	volatile int upd_index;
+	struct core_info core[SPP_INFO_AREA_MAX];
 };
 
 /* Declare global variables */
-static struct spp_config_area	g_config;
-static struct startup_param	g_startup_param;
-static struct if_info		g_if_info;
-static struct spp_core_info	g_core_info[SPP_CONFIG_CORE_MAX];
-static int 			g_change_core[SPP_CONFIG_CORE_MAX];  /* TODO(yasufum) add desc how it is used and why changed core is kept */
+static unsigned int g_main_lcore_id = 0xffffffff;
+static struct startup_param		g_startup_param;
+static struct if_info			g_if_info;
+static struct spp_component_info	g_component_info[RTE_MAX_LCORE];
+static struct core_mng_info		g_core_info[RTE_MAX_LCORE];
 
-static char config_file_path[PATH_MAX];
+static int 				g_change_core[RTE_MAX_LCORE];  /* TODO(yasufum) add desc how it is used and why changed component is kept */
+static int 				g_change_component[RTE_MAX_LCORE];
 
 /* Print help message */
 static void
@@ -73,11 +81,9 @@ usage(const char *progname)
 {
 	RTE_LOG(INFO, APP, "Usage: %s [EAL args] --"
 			" --client-id CLIENT_ID"
-			" [--config CONFIG_FILE_PATH]"
 			" -s SERVER_IP:SERVER_PORT"
 			" [--vhost-client]\n"
 			" --client-id CLIENT_ID   : My client ID\n"
-			" --config CONFIG_FILE_PATH : specific config file path\n"
 			" -s SERVER_IP:SERVER_PORT  : Access information to the server\n"
 			" --vhost-client            : Run vhost on client\n"
 			, progname);
@@ -99,8 +105,8 @@ add_ring_pmd(int ring_id)
 
 	/* Create ring pmd */
 	ring_port_id = rte_eth_from_ring(ring);
-	RTE_LOG(DEBUG, APP, "ring port id %d\n", ring_port_id);
-
+	RTE_LOG(INFO, APP, "ring port add. (no = %d / port = %d)\n",
+			ring_id, ring_port_id);
 	return ring_port_id;
 }
 
@@ -178,26 +184,30 @@ add_vhost_pmd(int index, int client)
 		return ret;
 	}
 
-	RTE_LOG(DEBUG, APP, "vhost port id %d\n", vhost_port_id);
-
+	RTE_LOG(INFO, APP, "vhost port add. (no = %d / port = %d)\n",
+			index, vhost_port_id);
 	return vhost_port_id;
 }
 
+/* Get core status */
+enum spp_core_status
+spp_get_core_status(unsigned int lcore_id)
+{
+	return g_core_info[lcore_id].status;
+}
+
 /**
  * Check status of all of cores is same as given
  *
  * It returns -1 as status mismatch if status is not same.
- * If status is SPP_CONFIG_UNUSE, check is skipped.
+ * If core is in use, status will be checked.
  */
 static int
 check_core_status(enum spp_core_status status)
 {
-	int cnt;  /* increment core id */
-	for (cnt = 0; cnt < SPP_CONFIG_CORE_MAX; cnt++) {
-		if (g_core_info[cnt].type == SPP_CONFIG_UNUSE) {
-			continue;
-		}
-		if (g_core_info[cnt].status != status) {
+	unsigned int lcore_id = 0;
+	RTE_LCORE_FOREACH_SLAVE(lcore_id) {
+		if (g_core_info[lcore_id].status != status) {
 			/* Status is mismatched */
 			return -1;
 		}
@@ -225,18 +235,26 @@ check_core_status_wait(enum spp_core_status status)
 	return -1;
 }
 
+/* Set core status */
+static void
+set_core_status(unsigned int lcore_id,
+		enum spp_core_status status)
+{
+	g_core_info[lcore_id].status = status;
+}
+
 /* Set all core to given status */
 static void
-set_core_status(enum spp_core_status status)
+set_all_core_status(enum spp_core_status status)
 {
-	int core_cnt = 0;  /* increment core id */
-	for(core_cnt = 0; core_cnt < SPP_CONFIG_CORE_MAX; core_cnt++) {
-		g_core_info[core_cnt].status = status;
+	unsigned int lcore_id = 0;
+	RTE_LCORE_FOREACH_SLAVE(lcore_id) {
+		g_core_info[lcore_id].status = status;
 	}
 }
 
 /**
- * Set all of core status to SPP_CORE_STOP_REQUEST if received signal
+ * Set all of component status to SPP_CORE_STOP_REQUEST if received signal
  * is SIGTERM or SIGINT
  */
 static void
@@ -246,7 +264,8 @@ stop_process(int signal) {
 		return;
 	}
 
-	set_core_status(SPP_CORE_STOP_REQUEST);
+	g_core_info[g_main_lcore_id].status = SPP_CORE_STOP_REQUEST;
+	set_all_core_status(SPP_CORE_STOP_REQUEST);
 }
 
 /**
@@ -265,7 +284,7 @@ parse_app_client_id(const char *client_id_str, int *client_id)
 	if (unlikely(client_id_str == endptr) || unlikely(*endptr != '\0'))
 		return -1;
 
-	if (id >= SPP_CLIENT_MAX)
+	if (id >= RTE_MAX_LCORE)
 		return -1;
 
 	*client_id = id;
@@ -310,7 +329,6 @@ parse_app_args(int argc, char *argv[])
 	char *argvopt[argcopt];
 	const char *progname = argv[0];
 	static struct option lgopts[] = { 
-			{ "config", required_argument, NULL, SPP_LONGOPT_RETVAL_CONFIG },
 			{ "client-id", required_argument, NULL, SPP_LONGOPT_RETVAL_CLIENT_ID },
 			{ "vhost-client", no_argument, NULL, SPP_LONGOPT_RETVAL_VHOST_CLIENT },
 			{ 0 },
@@ -333,13 +351,6 @@ parse_app_args(int argc, char *argv[])
 	while ((opt = getopt_long(argc, argvopt, "s:", lgopts,
 			&option_index)) != EOF) {
 		switch (opt) {
-		case SPP_LONGOPT_RETVAL_CONFIG:
-			if (optarg[0] == '\0' || strlen(optarg) >= sizeof(config_file_path)) {
-				usage(progname);
-				return -1;
-			}
-			strcpy(config_file_path, optarg);
-			break;
 		case SPP_LONGOPT_RETVAL_CLIENT_ID:
 			if (parse_app_client_id(optarg, &g_startup_param.client_id) != 0) {
 				usage(progname);
@@ -371,9 +382,8 @@ parse_app_args(int argc, char *argv[])
 		return -1;
 	}
 	RTE_LOG(INFO, APP,
-			"app opts (client_id=%d,config=%s,server=%s:%d,vhost_client=%d)\n",
+			"app opts (client_id=%d,server=%s:%d,vhost_client=%d)\n",
 			g_startup_param.client_id,
-			config_file_path,
 			g_startup_param.server_ip,
 			g_startup_param.server_port,
 			g_startup_param.vhost_client);
@@ -381,25 +391,25 @@ parse_app_args(int argc, char *argv[])
 }
 
 /**
- * Return patch info of given type and num of interface
+ * Return port info of given type and num of interface
  *
  * It returns NULL value if given type is invalid.
  *
  * TODO(yasufum) refactor name of func to be more understandable (area?)
  * TODO(yasufum) refactor, change if to iface.
  */
-static struct patch_info *
+static struct spp_port_info *
 get_if_area(enum port_type if_type, int if_no)
 {
 	switch (if_type) {
 	case PHY:
-		return &g_if_info.nic_patchs[if_no];
+		return &g_if_info.nic[if_no];
 		break;
 	case VHOST:
-		return &g_if_info.vhost_patchs[if_no];
+		return &g_if_info.vhost[if_no];
 		break;
 	case RING:
-		return &g_if_info.ring_patchs[if_no];
+		return &g_if_info.ring[if_no];
 		break;
 	default:
 		return NULL;
@@ -408,8 +418,9 @@ get_if_area(enum port_type if_type, int if_no)
 }
 
 /**
- * Initialize all of patch info by assingning -1
+ * Initialize g_if_info
  *
+ * Clear g_if_info and set initial value.
  * TODO(yasufum) refactor, change if to iface.
  */
 static void
@@ -418,336 +429,90 @@ init_if_info(void)
 	int port_cnt;  /* increment ether ports */
 	memset(&g_if_info, 0x00, sizeof(g_if_info));
 	for (port_cnt = 0; port_cnt < RTE_MAX_ETHPORTS; port_cnt++) {
-		g_if_info.nic_patchs[port_cnt].rx_core_no   = -1;
-		g_if_info.nic_patchs[port_cnt].tx_core_no   = -1;
-		g_if_info.vhost_patchs[port_cnt].rx_core_no = -1;
-		g_if_info.vhost_patchs[port_cnt].tx_core_no = -1;
-		g_if_info.ring_patchs[port_cnt].rx_core_no  = -1;
-		g_if_info.ring_patchs[port_cnt].tx_core_no  = -1;
+		g_if_info.nic[port_cnt].if_type   = UNDEF;
+		g_if_info.nic[port_cnt].if_no     = port_cnt;
+		g_if_info.nic[port_cnt].dpdk_port = -1;
+		g_if_info.vhost[port_cnt].if_type   = UNDEF;
+		g_if_info.vhost[port_cnt].if_no     = port_cnt;
+		g_if_info.vhost[port_cnt].dpdk_port = -1;
+		g_if_info.ring[port_cnt].if_type   = UNDEF;
+		g_if_info.ring[port_cnt].if_no     = port_cnt;
+		g_if_info.ring[port_cnt].dpdk_port = -1;
 	}
 }
 
 /**
- * Initialize g_core_info and its port info
- *
- * Clear g_core_info and set interface type of its port info to UNDEF.
- * TODO(yasufum) refactor, change if to iface.
+ * Initialize g_component_info
  */
 static void
-init_core_info(void)
+init_component_info(void)
 {
-	memset(&g_core_info, 0x00, sizeof(g_core_info));
-	int core_cnt, port_cnt;
-	for (core_cnt = 0; core_cnt < SPP_CONFIG_CORE_MAX; core_cnt++) {
-		g_core_info[core_cnt].lcore_id = core_cnt;
-		for (port_cnt = 0; port_cnt < RTE_MAX_ETHPORTS; port_cnt++) {
-			g_core_info[core_cnt].rx_ports[port_cnt].if_type = UNDEF;
-			g_core_info[core_cnt].tx_ports[port_cnt].if_type = UNDEF;
-		}
+	int cnt;
+	memset(&g_component_info, 0x00, sizeof(g_component_info));
+	for (cnt = 0; cnt < RTE_MAX_LCORE; cnt++) {
+		g_component_info[cnt].component_id = cnt;
 	}
-	memset(g_change_core, 0x00, sizeof(g_change_core));
+	memset(g_change_component, 0x00, sizeof(g_change_component));
 }
 
 /**
- * Set properties of g_core_info from config
- *
- * TODO(yasufum) refactor, change if to iface.
+ * Initialize g_core_info
  */
-static int
-set_from_proc_info(struct spp_config_area *config)
+static void
+init_core_info(void)
 {
-	int core_cnt, rx_start, rx_cnt, tx_start, tx_cnt;
-	enum port_type if_type;
-	int if_no;
-	struct spp_config_functions *core_func = NULL;
-	struct spp_core_info *core_info = NULL;
-	struct patch_info *patch_info = NULL;
-	for (core_cnt = 0; core_cnt < config->proc.num_func; core_cnt++) {
-		core_func = &config->proc.functions[core_cnt];
-		core_info = &g_core_info[core_func->core_no];
-
-		if (core_func->type == SPP_CONFIG_UNUSE) {
-			continue;
-		}
-
-    /* Check if type of core_info is SPP_CONFIG_FORWARD because this
-     * this type is only available for several settings.
-     */
-    if ((core_info->type != SPP_CONFIG_UNUSE) &&
-        ((core_info->type != SPP_CONFIG_FORWARD) ||
-         (core_func->type != SPP_CONFIG_FORWARD))) {
-      RTE_LOG(ERR, APP, "Core in use. (core = %d, type = %d/%d)\n",
-          core_func->core_no,
-          core_func->type, core_info->type);
-      return -1;
-    }
-
-		core_info->type = core_func->type;
-		if (!rte_lcore_is_enabled(core_func->core_no)) {
-			/* CPU mismatch */
-			RTE_LOG(ERR, APP, "CPU mismatch (cpu = %u)\n",
-					core_func->core_no);
-			return -1;
-		}
-
-		rx_start = core_info->num_rx_port;
-		core_info->num_rx_port += core_func->num_rx_port;
-		for (rx_cnt = 0; rx_cnt < core_func->num_rx_port; rx_cnt++) {
-			if_type = core_func->rx_ports[rx_cnt].if_type;
-			if_no   = core_func->rx_ports[rx_cnt].if_no;
-
-			core_info->rx_ports[rx_start + rx_cnt].if_type = if_type;
-			core_info->rx_ports[rx_start + rx_cnt].if_no   = if_no;
-
-			/* Retrieve patch corresponding to type and number of the interface */
-			patch_info = get_if_area(if_type, if_no);
-
-			patch_info->use_flg = 1;
-			if (unlikely(patch_info->rx_core != NULL)) {
-				RTE_LOG(ERR, APP, "Used RX port (core = %d, if_type = %d, if_no = %d)\n",
-						core_func->core_no, if_type, if_no);
-				return -1;
-			}
-
-			/* Hold core info is to be referred for updating this information */
-			patch_info->rx_core_no = core_func->core_no;
-			patch_info->rx_core    = &core_info->rx_ports[rx_start + rx_cnt];
-		}
-
-		/* Set TX port */
-		tx_start = core_info->num_tx_port;
-		core_info->num_tx_port += core_func->num_tx_port;
-		for (tx_cnt = 0; tx_cnt < core_func->num_tx_port; tx_cnt++) {
-			if_type = core_func->tx_ports[tx_cnt].if_type;
-			if_no   = core_func->tx_ports[tx_cnt].if_no;
-
-			core_info->tx_ports[tx_start + tx_cnt].if_type = if_type;
-			core_info->tx_ports[tx_start + tx_cnt].if_no   = if_no;
-
-			patch_info = get_if_area(if_type, if_no);
-
-			patch_info->use_flg = 1;
-			if (unlikely(patch_info->tx_core != NULL)) {
-				RTE_LOG(ERR, APP, "Used TX port (core = %d, if_type = %d, if_no = %d)\n",
-						core_func->core_no, if_type, if_no);
-				return -1;
-			}
-
-			/* Hold core info is to be referred for updating this information */
-			patch_info->tx_core_no = core_func->core_no;
-			patch_info->tx_core    = &core_info->tx_ports[tx_start + tx_cnt];
-		}
+	int cnt = 0;
+	memset(&g_core_info, 0x00, sizeof(g_core_info));
+	set_all_core_status(SPP_CORE_STOP);
+	for (cnt = 0; cnt < RTE_MAX_LCORE; cnt++) {
+		g_core_info[cnt].ref_index = 0;
+		g_core_info[cnt].upd_index = 1;
 	}
-
-	return 0;
+	memset(g_change_core, 0x00, sizeof(g_change_core));
 }
 
 /**
- * Load mac table entries from config and setup patches
+ * Setup port info of port on host
  *
  * TODO(yasufum) refactor, change if to iface.
  */
 static int
-set_from_classifier_table(struct spp_config_area *config)
+set_nic_interface(void)
 {
-	enum port_type if_type;
-	int if_no = 0;
-	int mac_cnt = 0;
-	struct spp_config_mac_table_element *mac_table = NULL;
-	struct patch_info *patch_info = NULL;
-	for (mac_cnt = 0; mac_cnt < config->classifier_table.num_table; mac_cnt++) {
-		mac_table = &config->classifier_table.mac_tables[mac_cnt];
-
-		if_type = mac_table->port.if_type;
-		if_no   = mac_table->port.if_no;
-
-    /* Retrieve patch corresponding to type and number of the interface */
-		patch_info = get_if_area(if_type, if_no);
-
-		if (unlikely(patch_info->use_flg == 0)) {
-			RTE_LOG(ERR, APP, "Not used interface (if_type = %d, if_no = %d)\n",
-					if_type, if_no);
-			return -1;
-		}
+	int nic_cnt = 0;
 
-    /* Set mac address from the table for destination tx, not need for rx */
-		patch_info->mac_addr = mac_table->mac_addr;
-		strcpy(patch_info->mac_addr_str, mac_table->mac_addr_str);
-		if (unlikely(patch_info->tx_core != NULL)) {
-			patch_info->tx_core->mac_addr = mac_table->mac_addr;
-			strcpy(patch_info->tx_core->mac_addr_str, mac_table->mac_addr_str);
-		}
-	}
-	return 0;
-}
-
-/**
- * Setup patch info of port on host
- *
- * TODO(yasufum) refactor, change if to iface.
- */
-static int
-set_nic_interface(struct spp_config_area *config __attribute__ ((unused)))
-{
 	/* NIC Setting */
 	g_if_info.num_nic = rte_eth_dev_count();
 	if (g_if_info.num_nic > RTE_MAX_ETHPORTS) {
 		g_if_info.num_nic = RTE_MAX_ETHPORTS;
 	}
 
-	int nic_cnt, nic_num = 0;
-	struct patch_info *patch_info = NULL;
-	for (nic_cnt = 0; nic_cnt < RTE_MAX_ETHPORTS; nic_cnt++) {
-		patch_info = &g_if_info.nic_patchs[nic_cnt];
-		patch_info->dpdk_port = nic_cnt;
-
-    /* Skip for no used nic */
-		if (patch_info->use_flg == 0) {
-			continue;
-		}
-
-		if (patch_info->rx_core != NULL) {
-			patch_info->rx_core->dpdk_port = nic_cnt;
-		}
-		if (patch_info->tx_core != NULL) {
-			patch_info->tx_core->dpdk_port = nic_cnt;
-		}
-
-		nic_num++;
-	}
-
-	if (unlikely(nic_num > g_if_info.num_nic)) {
-		RTE_LOG(ERR, APP, "NIC Setting mismatch. (IF = %d, config = %d)\n",
-				nic_num, g_if_info.num_nic);
-		return -1;
+	for (nic_cnt = 0; nic_cnt < g_if_info.num_nic; nic_cnt++) {
+		g_if_info.nic[nic_cnt].dpdk_port = nic_cnt;
 	}
 
 	return 0;
 }
 
 /**
- * Setup vhost interfaces from config
- *
- * TODO(yasufum) refactor, change if to iface.
- */
-static int
-set_vhost_interface(struct spp_config_area *config)
-{
-	int vhost_cnt, vhost_num = 0;
-	g_if_info.num_vhost = config->proc.num_vhost;
-	struct patch_info *patch_info = NULL;
-	for (vhost_cnt = 0; vhost_cnt < RTE_MAX_ETHPORTS; vhost_cnt++) {
-		patch_info = &g_if_info.vhost_patchs[vhost_cnt];
-		if (patch_info->use_flg == 0) {
-			/* Not Used */
-			continue;
-		}
-
-		int dpdk_port = add_vhost_pmd(vhost_cnt, g_startup_param.vhost_client);
-		if (unlikely(dpdk_port < 0)) {
-			RTE_LOG(ERR, APP, "VHOST add failed. (no = %d)\n",
-					vhost_cnt);
-			return -1;
-		}
-		patch_info->dpdk_port = dpdk_port;
-
-		if (patch_info->rx_core != NULL) {
-			patch_info->rx_core->dpdk_port = dpdk_port;
-		}
-		if (patch_info->tx_core != NULL) {
-			patch_info->tx_core->dpdk_port = dpdk_port;
-		}
-		vhost_num++;
-	}
-	if (unlikely(vhost_num > g_if_info.num_vhost)) {
-		RTE_LOG(ERR, APP, "VHOST Setting mismatch. (IF = %d, config = %d)\n",
-				vhost_num, g_if_info.num_vhost);
-		return -1;
-	}
-	return 0;
-}
-
-/**
- * Setup ring interfaces from config
- *
- * TODO(yasufum) refactor, change if to iface.
- */
-static int
-set_ring_interface(struct spp_config_area *config)
-{
-	int ring_cnt, ring_num = 0;
-	g_if_info.num_ring = config->proc.num_ring;
-	struct patch_info *patch_info = NULL;
-	for (ring_cnt = 0; ring_cnt < RTE_MAX_ETHPORTS; ring_cnt++) {
-		patch_info = &g_if_info.ring_patchs[ring_cnt];
-
-		if (patch_info->use_flg == 0) {
-      /* Skip for no used nic */
-			continue;
-		}
-
-		int dpdk_port = add_ring_pmd(ring_cnt);
-		if (unlikely(dpdk_port < 0)) {
-			RTE_LOG(ERR, APP, "RING add failed. (no = %d)\n",
-					ring_cnt);
-			return -1;
-		}
-		patch_info->dpdk_port = dpdk_port;
-
-		if (patch_info->rx_core != NULL) {
-			patch_info->rx_core->dpdk_port = dpdk_port;
-		}
-		if (patch_info->tx_core != NULL) {
-			patch_info->tx_core->dpdk_port = dpdk_port;
-		}
-		ring_num++;
-	}
-	if (unlikely(ring_num > g_if_info.num_ring)) {
-		RTE_LOG(ERR, APP, "RING Setting mismatch. (IF = %d, config = %d)\n",
-				ring_num, g_if_info.num_ring);
-		return -1;
-	}
-	return 0;
-}
-
-/**
  * Setup management info for spp_vf
  *
  * TODO(yasufum) refactor, change if to iface.
  * TODO(yasufum) refactor, change function name from manage to mng or management
  */
 static int
-init_manage_data(struct spp_config_area *config)
+init_manage_data(void)
 {
 	/* Initialize interface and core infomation */
 	init_if_info();
 	init_core_info();
+	init_component_info();
 
-  /* Load config for resource assingment and network configuration */
-	int ret_proc = set_from_proc_info(config);
-	if (unlikely(ret_proc != 0)) {
-		return -1;
-	}
-	int ret_classifier = set_from_classifier_table(config);
-	if (unlikely(ret_classifier != 0)) {
-		return -1;
-	}
-
-	int ret_nic = set_nic_interface(config);
+	int ret_nic = set_nic_interface();
 	if (unlikely(ret_nic != 0)) {
 		return -1;
 	}
 
-	int ret_vhost = set_vhost_interface(config);
-	if (unlikely(ret_vhost != 0)) {
-		return -1;
-	}
-
-	int ret_ring = set_ring_interface(config);
-	if (unlikely(ret_ring != 0)) {
-		return -1;
-	}
-
 	return 0;
 }
 
@@ -772,7 +537,7 @@ print_ring_latency_stats(void)
 	printf("RING Latency\n");
 	printf(" RING");
 	for (ring_cnt = 0; ring_cnt < RTE_MAX_ETHPORTS; ring_cnt++) {
-		if (g_if_info.ring_patchs[ring_cnt].use_flg == 0) {
+		if (g_if_info.ring[ring_cnt].if_type == UNDEF) {
 			continue;
 		}
 		spp_ringlatencystats_get_stats(ring_cnt, &stats[ring_cnt]);
@@ -783,7 +548,7 @@ print_ring_latency_stats(void)
 	for (stats_cnt = 0; stats_cnt < SPP_RINGLATENCYSTATS_STATS_SLOT_COUNT; stats_cnt++) {
 		printf("%3dns", stats_cnt);
 		for (ring_cnt = 0; ring_cnt < RTE_MAX_ETHPORTS; ring_cnt++) {
-			if (g_if_info.ring_patchs[ring_cnt].use_flg == 0) {
+			if (g_if_info.ring[ring_cnt].if_type == UNDEF) {
 				continue;
 			}
 
@@ -800,7 +565,7 @@ print_ring_latency_stats(void)
  * Remove sock file
  */
 static void
-del_vhost_sockfile(struct patch_info *vhost_patchs)
+del_vhost_sockfile(struct spp_port_info *vhost)
 {
 	int cnt;
 
@@ -809,7 +574,7 @@ del_vhost_sockfile(struct patch_info *vhost_patchs)
 		return;
 
 	for (cnt = 0; cnt < RTE_MAX_ETHPORTS; cnt++) {
-		if (likely(vhost_patchs[cnt].use_flg == 0)) {
+		if (likely(vhost[cnt].if_type == UNDEF)) {
 			/* Skip removing if it is not using vhost */
 			continue;
 		}
@@ -818,6 +583,95 @@ del_vhost_sockfile(struct patch_info *vhost_patchs)
 	}
 }
 
+/* Get component type of target core */
+enum spp_component_type
+spp_get_component_type(unsigned int lcore_id)
+{
+	struct core_mng_info *info = &g_core_info[lcore_id];
+	return info->core[info->ref_index].type;
+}
+
+/* Get component type being updated on target core */
+enum spp_component_type
+spp_get_component_type_update(unsigned int lcore_id)
+{
+	struct core_mng_info *info = &g_core_info[lcore_id];
+	return info->core[info->upd_index].type;
+}
+
+/* Get core ID of target component */
+unsigned int
+spp_get_component_core(int component_id)
+{
+	struct spp_component_info *info = &g_component_info[component_id];
+	return info->lcore_id;
+}
+
+/* Get usage area of target core */
+static struct core_info *
+get_core_info(unsigned int lcore_id)
+{
+	struct core_mng_info *info = &g_core_info[lcore_id];
+	return &(info->core[info->ref_index]);
+}
+
+/* Check core index change */
+int
+spp_check_core_index(unsigned int lcore_id)
+{
+	struct core_mng_info *info = &g_core_info[lcore_id];
+	return info->ref_index == info->upd_index;
+}
+
+/* Main process of slave core */
+static int
+slave_main(void *arg __attribute__ ((unused)))
+{
+	int ret = 0;
+	int cnt = 0;
+	unsigned int lcore_id = rte_lcore_id();
+	enum spp_core_status status = SPP_CORE_STOP;
+	struct core_mng_info *info = &g_core_info[lcore_id];
+	struct core_info *core = get_core_info(lcore_id);
+
+	RTE_LOG(INFO, APP, "Core[%d] Start.\n", lcore_id);
+	set_core_status(lcore_id, SPP_CORE_IDLE);
+
+	while((status = spp_get_core_status(lcore_id)) != SPP_CORE_STOP_REQUEST) {
+		if (status != SPP_CORE_FORWARD)
+			continue;
+
+		if (spp_check_core_index(lcore_id)) {
+			/* Setting with the flush command trigger. */
+			info->ref_index = (info->upd_index+1)%SPP_INFO_AREA_MAX;
+			core = get_core_info(lcore_id);
+		}
+
+		for (cnt = 0; cnt < core->num; cnt++) {
+			if (spp_get_component_type(lcore_id) == SPP_COMPONENT_CLASSIFIER_MAC) {
+				/* Classifier loops inside the function. */
+				ret = spp_classifier_mac_do(core->id[cnt]);
+				break;
+			} else {
+				/* Forward / Merge returns at once.          */
+				/* It is for processing multiple components. */
+				ret = spp_forward(core->id[cnt]);
+				if (unlikely(ret != 0))
+					break;
+			}
+		}
+		if (unlikely(ret != 0)) {
+			RTE_LOG(ERR, APP, "Core[%d] Component Error. (id = %d)\n",
+					lcore_id, core->id[cnt]);
+			break;
+		}
+	}
+
+	set_core_status(lcore_id, SPP_CORE_STOP);
+	RTE_LOG(INFO, APP, "Core[%d] End.\n", lcore_id);
+	return ret;
+}
+
 /* TODO(yasufum) refactor, change if to iface. */
 /* TODO(yasufum) change test using ut_main(), or add desccription for what and why use it */
 /* TODO(yasufum) change to return -1 explicity if error is occured. */
@@ -842,10 +696,6 @@ ut_main(int argc, char *argv[])
 	signal(SIGTERM, stop_process);
 	signal(SIGINT,  stop_process);
 
-	/* Setup config wiht default file path */
-	strcpy(config_file_path, SPP_CONFIG_FILE_PATH);
-
-	unsigned int main_lcore_id = 0xffffffff;
 	while(1) {
 		int ret_dpdk = rte_eal_init(argc, argv);
 		if (unlikely(ret_dpdk < 0)) {
@@ -864,17 +714,10 @@ ut_main(int argc, char *argv[])
 			break;
 		}
 
-		RTE_LOG(INFO, APP, "Load config file(%s)\n", config_file_path);
-
-		int ret_config = spp_config_load_file(config_file_path, 0, &g_config);
-		if (unlikely(ret_config != 0)) {
-			break;
-		}
-
 		/* Get lcore id of main thread to set its status after */
-		main_lcore_id = rte_lcore_id();
+		g_main_lcore_id = rte_lcore_id();
 
-		int ret_manage = init_manage_data(&g_config);
+		int ret_manage = init_manage_data();
 		if (unlikely(ret_manage != 0)) {
 			break;
 		}
@@ -884,7 +727,9 @@ ut_main(int argc, char *argv[])
 			break;
 		}
 
-    /* Setup connection for accepting commands from controller */
+		spp_forward_init();
+
+		/* Setup connection for accepting commands from controller */
 		int ret_command_init = spp_command_proc_init(
 				g_startup_param.server_ip,
 				g_startup_param.server_port);
@@ -903,37 +748,29 @@ ut_main(int argc, char *argv[])
 		/* Start worker threads of classifier and forwarder */
 		unsigned int lcore_id = 0;
 		RTE_LCORE_FOREACH_SLAVE(lcore_id) {
-			if (g_core_info[lcore_id].type == SPP_CONFIG_CLASSIFIER_MAC) {
-				rte_eal_remote_launch(spp_classifier_mac_do,
-						(void *)&g_core_info[lcore_id],
-						lcore_id);
-			} else {
-				rte_eal_remote_launch(spp_forward,
-						(void *)&g_core_info[lcore_id],
-						lcore_id);
-			}
+			rte_eal_remote_launch(slave_main, NULL, lcore_id);
 		}
 
-    /* Set the status of main thread to idle */
-		g_core_info[main_lcore_id].status = SPP_CORE_IDLE;
+		/* Set the status of main thread to idle */
+		g_core_info[g_main_lcore_id].status = SPP_CORE_IDLE;
 		int ret_wait = check_core_status_wait(SPP_CORE_IDLE);
 		if (unlikely(ret_wait != 0)) {
 			break;
 		}
 
 		/* Start forwarding */
-		set_core_status(SPP_CORE_FORWARD);
+		set_all_core_status(SPP_CORE_FORWARD);
 		RTE_LOG(INFO, APP, "My ID %d start handling message\n", 0);
 		RTE_LOG(INFO, APP, "[Press Ctrl-C to quit ...]\n");
 
 		/* Enter loop for accepting commands */
 		int ret_do = 0;
 #ifndef USE_UT_SPP_VF
-		while(likely(g_core_info[main_lcore_id].status != SPP_CORE_STOP_REQUEST)) {
+		while(likely(g_core_info[g_main_lcore_id].status != SPP_CORE_STOP_REQUEST)) {
 #else
 		{
 #endif
-      /* Receive command */
+			/* Receive command */
 			ret_do = spp_command_proc_do();
 			if (unlikely(ret_do != 0)) {
 				break;
@@ -947,6 +784,7 @@ ut_main(int argc, char *argv[])
 		}
 
 		if (unlikely(ret_do != 0)) {
+			set_all_core_status(SPP_CORE_STOP_REQUEST);
 			break;
 		}
 
@@ -955,16 +793,16 @@ ut_main(int argc, char *argv[])
 	}
 
 	/* Finalize to exit */
-	if (main_lcore_id == rte_lcore_id())
+	if (g_main_lcore_id == rte_lcore_id())
 	{
-		g_core_info[main_lcore_id].status = SPP_CORE_STOP;
+		g_core_info[g_main_lcore_id].status = SPP_CORE_STOP;
 		int ret_core_end = check_core_status_wait(SPP_CORE_STOP);
 		if (unlikely(ret_core_end != 0)) {
 			RTE_LOG(ERR, APP, "Core did not stop.\n");
 		}
 
 		/* Remove vhost sock file if it is not running in vhost-client mode */
-		del_vhost_sockfile(g_if_info.vhost_patchs);
+		del_vhost_sockfile(g_if_info.vhost);
 	}
 
 #ifdef SPP_RINGLATENCYSTATS_ENABLE
@@ -982,123 +820,478 @@ spp_get_client_id(void)
 }
 
 /**
- * Check mac address used on the interface for registering or removing
+ * Check mac address used on the port for registering or removing
  *
  * TODO(yasufum) refactor, change if to iface.
  */
-static int
-check_mac_used_interface(uint64_t mac_addr, enum port_type *if_type, int *if_no)
+int
+spp_check_mac_used_port(uint64_t mac_addr, enum port_type if_type, int if_no)
 {
-	int cnt = 0;
-	for (cnt = 0; cnt < RTE_MAX_ETHPORTS; cnt++) {
-		if (unlikely(g_if_info.nic_patchs[cnt].mac_addr == mac_addr)) {
-			*if_type = PHY;
-			*if_no = cnt;
-			return 0;
-		}
-		if (unlikely(g_if_info.vhost_patchs[cnt].mac_addr == mac_addr)) {
-			*if_type = VHOST;
-			*if_no = cnt;
-			return 0;
+	struct spp_port_info *port_info = get_if_area(if_type, if_no);
+	return (mac_addr == port_info->mac_addr);
+}
+
+/*
+ * Check if port has been added.
+ */
+int
+spp_check_added_port(enum port_type if_type, int if_no)
+{
+	struct spp_port_info *port = get_if_area(if_type, if_no);
+	return port->if_type != UNDEF;
+}
+
+/*
+ * Check if component is using port.
+ */
+int
+spp_check_used_port(enum port_type if_type, int if_no, enum spp_port_rxtx rxtx)
+{
+	int cnt, port_cnt, max = 0;
+	struct spp_component_info *component = NULL;
+	struct spp_port_info **port_array = NULL;
+	struct spp_port_info *port = get_if_area(if_type, if_no);
+
+	if (port == NULL)
+		return SPP_RET_NG;
+
+	for (cnt = 0; cnt < RTE_MAX_LCORE; cnt++) {
+		component = &g_component_info[cnt];
+		if (component->type == SPP_COMPONENT_UNUSE)
+			continue;
+
+		if (rxtx == SPP_PORT_RXTX_RX) {
+			max = component->num_rx_port;
+			port_array = component->rx_ports;
+		} else if (rxtx == SPP_PORT_RXTX_TX) {
+			max = component->num_tx_port;
+			port_array = component->tx_ports;
 		}
-		if (unlikely(g_if_info.ring_patchs[cnt].mac_addr == mac_addr)) {
-			*if_type = RING;
-			*if_no = cnt;
-			return 0;
+		for (port_cnt = 0; port_cnt < max; port_cnt++) {
+			if (unlikely(port_array[port_cnt] == port))
+				return cnt;
 		}
 	}
-	return -1;
+
+	return SPP_RET_NG;
+}
+
+/*
+ * Set port change to component.
+ */
+static void
+set_component_change_port(struct spp_port_info *port, enum spp_port_rxtx rxtx)
+{
+	int ret = 0;
+	if ((rxtx == SPP_PORT_RXTX_RX) || (rxtx == SPP_PORT_RXTX_ALL)) {
+		ret = spp_check_used_port(port->if_type, port->if_no, SPP_PORT_RXTX_RX);
+		if (ret >= 0)
+			g_change_component[ret] = 1;
+	}
+
+	if ((rxtx == SPP_PORT_RXTX_TX) || (rxtx == SPP_PORT_RXTX_ALL)) {
+		ret = spp_check_used_port(port->if_type, port->if_no, SPP_PORT_RXTX_TX);
+		if (ret >= 0)
+			g_change_component[ret] = 1;
+	}
 }
 
 int
 spp_update_classifier_table(
+		enum spp_command_action action,
 		enum spp_classifier_type type,
 		const char *data,
-		const struct spp_config_port_info *port)
+		const struct spp_port_index *port)
 {
-	enum port_type if_type = UNDEF;
-        int if_no = 0;
-	struct patch_info *patch_info = NULL;
+	struct spp_port_info *port_info = NULL;
 	int64_t ret_mac = 0;
 	uint64_t mac_addr = 0;
-	int ret_used = 0;
 
 	if (type == SPP_CLASSIFIER_TYPE_MAC) {
 		RTE_LOG(DEBUG, APP, "update_classifier_table ( type = mac, data = %s, port = %d:%d )\n",
 				data, port->if_type, port->if_no);
 
-		ret_mac = spp_config_change_mac_str_to_int64(data);
+		ret_mac = spp_change_mac_str_to_int64(data);
 		if (unlikely(ret_mac == -1)) {
 			RTE_LOG(ERR, APP, "MAC address format error. ( mac = %s )\n", data);
 			return SPP_RET_NG;
 		}
-
 		mac_addr = (uint64_t)ret_mac;
 
-		ret_used = check_mac_used_interface(mac_addr, &if_type, &if_no);
-		if (port->if_type == UNDEF) {
-			/* Delete(unuse) */
-			if (ret_used < 0) {
-				RTE_LOG(DEBUG, APP, "No MAC address. ( mac = %s )\n", data);
-				return SPP_RET_OK;
-			}
+		port_info = get_if_area(port->if_type, port->if_no);
+		if (unlikely(port_info == NULL)) {
+			RTE_LOG(ERR, APP, "No port. ( port = %d:%d )\n",
+					port->if_type, port->if_no);
+			return SPP_RET_NG;
+		}
+		if (unlikely(port_info->if_type == UNDEF)) {
+			RTE_LOG(ERR, APP, "Port not added. ( port = %d:%d )\n",
+					port->if_type, port->if_no);
+			return SPP_RET_NG;
+		}
 
-			patch_info = get_if_area(if_type, if_no);
-			if (unlikely(patch_info == NULL)) {
-				RTE_LOG(ERR, APP, "No port. ( port = %d:%d )\n", port->if_type, port->if_no);
+		if (action == SPP_CMD_ACTION_DEL) {
+			/* Delete */
+			if ((port_info->mac_addr != 0) &&
+					unlikely(port_info->mac_addr != mac_addr)) {
+				RTE_LOG(ERR, APP, "MAC address is different. ( mac = %s )\n",
+						data);
 				return SPP_RET_NG;
 			}
 
-			patch_info->mac_addr = 0;
-			memset(patch_info->mac_addr_str, 0x00, SPP_CONFIG_STR_LEN);
-			if (patch_info->tx_core != NULL) {
-				patch_info->tx_core->mac_addr = 0;
-				memset(patch_info->tx_core->mac_addr_str, 0x00, SPP_CONFIG_STR_LEN);
-			}
+			port_info->mac_addr = 0;
+			memset(port_info->mac_addr_str, 0x00, SPP_MIN_STR_LEN);
 		}
-		else
-		{
+		else if (action == SPP_CMD_ACTION_ADD) {
 			/* Setting */
-			if (unlikely(ret_used == 0)) {
-				if (likely(port->if_type == if_type) && likely(port->if_no == if_no)) {
-					RTE_LOG(DEBUG, APP, "Same MAC address and port. ( mac = %s, port = %d:%d )\n",
-							data, if_type, if_no);
-					return SPP_RET_OK;
-				}
-				else
-				{
-					RTE_LOG(ERR, APP, "MAC address in used. ( mac = %s )\n", data);
-					return SPP_RET_USED_MAC;
-				}
+			if (unlikely(port_info->mac_addr != 0)) {
+				RTE_LOG(ERR, APP, "Port in used. ( port = %d:%d )\n",
+						 port->if_type, port->if_no);
+				return SPP_RET_NG;
 			}
 
-			patch_info = get_if_area(port->if_type, port->if_no);
-			if (unlikely(patch_info == NULL)) {
-				RTE_LOG(ERR, APP, "No port. ( port = %d:%d )\n", port->if_type, port->if_no);
+			port_info->mac_addr = mac_addr;
+			strcpy(port_info->mac_addr_str, data);
+		}
+	}
+
+	/* TODO(yasufum) add desc how it is used and why changed core is kept */
+	set_component_change_port(port_info, SPP_PORT_RXTX_TX);
+	return SPP_RET_OK;
+}
+
+/* Get free component */
+static int
+get_free_component(void)
+{
+	int cnt = 0;
+	for (cnt = 0; cnt < RTE_MAX_LCORE; cnt++) {
+		if (g_component_info[cnt].type == SPP_COMPONENT_UNUSE)
+			return cnt;
+	}
+	return -1;
+}
+
+/* Get name matching component */
+int
+spp_get_component_id(const char *name)
+{
+	int cnt = 0;
+	if (name[0] == '\0')
+		return SPP_RET_NG;
+
+	for (cnt = 0; cnt < RTE_MAX_LCORE; cnt++) {
+		if (strcmp(name, g_component_info[cnt].name) == 0)
+			return cnt;
+	}
+	return SPP_RET_NG;
+}
+
+static int
+get_del_core_element(int info, int num, int *array)
+{
+	int cnt;
+	int match = -1;
+	int max = num;
+
+	for (cnt = 0; cnt < max; cnt++) {
+		if (info == array[cnt])
+			match = cnt;
+	}
+
+	if (match < 0)
+		return -1;
+
+	/* Last element is excluded from movement. */
+	max--;
+
+	for (cnt = match; cnt < max; cnt++) {
+		array[cnt] = array[cnt+1];
+	}
+
+	/* Last element is cleared. */
+	array[cnt] = 0;
+	return 0;
+}
+
+/* Component command to execute it */
+int
+spp_update_component(
+		enum spp_command_action action,
+		const char *name,
+		unsigned int lcore_id,
+		enum spp_component_type type)
+{
+	int ret = SPP_RET_NG;
+	int ret_del = -1;
+	int component_id = 0;
+	unsigned int tmp_lcore_id = 0;
+	struct spp_component_info *component = NULL;
+	struct core_info *core = NULL;
+	struct core_mng_info *info = NULL;
+
+	switch (action) {
+	case SPP_CMD_ACTION_START:
+		info = &g_core_info[lcore_id];
+		if (info->status == SPP_CORE_UNUSE) {
+			RTE_LOG(ERR, APP, "Core unavailable.\n");
+			return SPP_RET_NG;
+		}
+
+		component_id = spp_get_component_id(name);
+		if (component_id >= 0) {
+			RTE_LOG(ERR, APP, "Component name in used.\n");
+			return SPP_RET_NG;
+		}
+
+		component_id = get_free_component();
+		if (component_id < 0) {
+			RTE_LOG(ERR, APP, "Component upper limit is over.\n");
+			return SPP_RET_NG;
+		}
+
+		core = &info->core[info->upd_index];
+		if ((core->type != SPP_COMPONENT_UNUSE) && (core->type != type)) {
+			RTE_LOG(ERR, APP, "Component type is error.\n");
+			return SPP_RET_NG;
+		}
+
+		component = &g_component_info[component_id];
+		memset(component, 0x00, sizeof(struct spp_component_info));
+		strcpy(component->name, name);
+		component->type         = type;
+		component->lcore_id     = lcore_id;
+		component->component_id = component_id;
+
+		core->type = type;
+		core->id[core->num] = component_id;
+		core->num++;
+		ret = SPP_RET_OK;
+		tmp_lcore_id = lcore_id;
+		break;
+
+	case SPP_CMD_ACTION_STOP:
+		component_id = spp_get_component_id(name);
+		if (component_id < 0)
+			return SPP_RET_OK;
+
+		component = &g_component_info[component_id];
+		tmp_lcore_id = component->lcore_id;
+		memset(component, 0x00, sizeof(struct spp_component_info));
+
+		info = &g_core_info[tmp_lcore_id];
+		core = &info->core[info->upd_index];
+		ret_del = get_del_core_element(component_id,
+				core->num, core->id);
+		if (ret_del >= 0)
+			/* If deleted, decrement number. */
+			core->num--;
+
+		if (core->num == 0)
+			core->type = SPP_COMPONENT_UNUSE;
+
+		ret = SPP_RET_OK;
+		break;
+
+	default:
+		break;
+	}
+
+	g_change_core[tmp_lcore_id] = 1;
+	return ret;
+}
+
+static int
+check_port_element(
+		struct spp_port_info *info,
+		int num,
+		struct spp_port_info *array[])
+{
+	int cnt = 0;
+	int match = -1;
+	for (cnt = 0; cnt < num; cnt++) {
+		if (info == array[cnt])
+			match = cnt;
+	}
+	return match;
+}
+
+static int
+get_del_port_element(
+		struct spp_port_info *info,
+		int num,
+		struct spp_port_info *array[])
+{
+	int cnt = 0;
+	int match = -1;
+	int max = num;
+
+	match = check_port_element(info, num, array);
+	if (match < 0)
+		return -1;
+
+	/* Last element is excluded from movement. */
+	max--;
+
+	for (cnt = match; cnt < max; cnt++) {
+		array[cnt] = array[cnt+1];
+	}
+
+	/* Last element is cleared. */
+	array[cnt] = NULL;
+	return 0;
+}
+
+/* Port add or del to execute it */
+int
+spp_update_port(enum spp_command_action action,
+		const struct spp_port_index *port,
+		enum spp_port_rxtx rxtx,
+		const char *name)
+{
+	int ret = SPP_RET_NG;
+	int ret_check = -1;
+	int ret_del = -1;
+	int component_id = 0;
+	struct spp_component_info *component = NULL;
+	struct spp_port_info *port_info = NULL;
+	int *num = NULL;
+	struct spp_port_info **ports = NULL;
+
+	component_id = spp_get_component_id(name);
+	if (component_id < 0) {
+		RTE_LOG(ERR, APP, "Unknown component by port command. (component = %s)\n",
+				name);
+		return SPP_RET_NG;
+	}
+
+	component = &g_component_info[component_id];
+	port_info = get_if_area(port->if_type, port->if_no);
+	if (rxtx == SPP_PORT_RXTX_RX) {
+		num = &component->num_rx_port;
+		ports = component->rx_ports;
+	} else {
+		num = &component->num_tx_port;
+		ports = component->tx_ports;
+	}
+
+	switch (action) {
+	case SPP_CMD_ACTION_ADD:
+		ret_check = check_port_element(port_info, *num, ports);
+		if (ret_check >= 0)
+			return SPP_RET_OK;
+
+		if (*num >= RTE_MAX_ETHPORTS) {
+			RTE_LOG(ERR, APP, "Port upper limit is over.\n");
+			break;
+		}
+
+		port_info->if_type = port->if_type;
+		ports[*num] = port_info;
+		(*num)++;
+
+		ret = SPP_RET_OK;
+		break;
+
+	case SPP_CMD_ACTION_DEL:
+		ret_del = get_del_port_element(port_info, *num, ports);
+		if (ret_del == 0)
+			(*num)--; /* If deleted, decrement number. */
+		ret = SPP_RET_OK;
+		break;
+	default:
+		break;
+	}
+
+	g_change_component[component_id] = 1;
+	return ret;
+}
+
+/* Flush initial setting of each interface. */
+static int
+flush_port(void)
+{
+	int ret = 0;
+	int cnt = 0;
+	struct spp_port_info *port = NULL;
+
+	/* Initialize added vhost. */
+	for (cnt = 0; cnt < RTE_MAX_ETHPORTS; cnt++) {
+		port = &g_if_info.vhost[cnt];
+		if ((port->if_type != UNDEF) && (port->dpdk_port < 0)) {
+			ret = add_vhost_pmd(port->if_no, g_startup_param.vhost_client);
+			if (ret < 0)
 				return SPP_RET_NG;
-			}
+			port->dpdk_port = ret;
+		}
+	}
 
-			if (unlikely(patch_info->use_flg == 0)) {
-				RTE_LOG(ERR, APP, "Port not added. ( port = %d:%d )\n", port->if_type, port->if_no);
-				return SPP_RET_NOT_ADD_PORT;
-			}
+	/* Initialize added ring. */
+	for (cnt = 0; cnt < RTE_MAX_ETHPORTS; cnt++) {
+		port = &g_if_info.ring[cnt];
+		if ((port->if_type != UNDEF) && (port->dpdk_port < 0)) {
+			ret = add_ring_pmd(port->if_no);
+			if (ret < 0)
+				return SPP_RET_NG;
+			port->dpdk_port = ret;
+		}
+	}
+	return SPP_RET_OK;
+}
 
-			if (unlikely(patch_info->mac_addr != 0)) {
-				RTE_LOG(ERR, APP, "Port in used. ( port = %d:%d )\n", port->if_type, port->if_no);
-				return SPP_RET_USED_PORT;
-			}
+/* Flush changed core. */
+static void
+flush_core(void)
+{
+	int cnt = 0;
+	struct core_mng_info *info = NULL;
 
-			patch_info->mac_addr = mac_addr;
-			strcpy(patch_info->mac_addr_str, data);
-			if (patch_info->tx_core != NULL) {
-				patch_info->tx_core->mac_addr = mac_addr;
-				strcpy(patch_info->tx_core->mac_addr_str, data);
-			}
+	/* Changed core has changed index. */
+	for (cnt = 0; cnt < RTE_MAX_LCORE; cnt++) {
+		if (g_change_core[cnt] != 0) {
+			info = &g_core_info[cnt];
+			info->upd_index = info->ref_index;
+		}
+	}
+
+	/* Waiting for changed core change. */
+	for (cnt = 0; cnt < RTE_MAX_LCORE; cnt++) {
+		if (g_change_core[cnt] != 0) {
+			info = &g_core_info[cnt];
+			while(likely(info->ref_index == info->upd_index))
+				rte_delay_us_block(SPP_CHANGE_UPDATE_INTERVAL);
+
+			memcpy(&info->core[info->upd_index],
+					&info->core[info->ref_index],
+					sizeof(struct core_info)); 
 		}
 	}
+}
 
-  /* TODO(yasufum) add desc how it is used and why changed core is kept */
-	g_change_core[patch_info->tx_core_no] = 1;
+/* Flush chagned component */
+static int
+flush_component(void)
+{
+	int ret = 0;
+	int cnt = 0;
+	struct spp_component_info *component_info = NULL;
+
+	for(cnt = 0; cnt < RTE_MAX_LCORE; cnt++) {
+		if (g_change_component[cnt] == 0)
+			continue;
+
+		component_info = &g_component_info[cnt];
+		if (component_info->type == SPP_COMPONENT_CLASSIFIER_MAC) {
+			ret = spp_classifier_mac_update(component_info);
+		} else {
+			ret = spp_forward_update(component_info);
+		}
+		if (unlikely(ret < 0)) {
+			RTE_LOG(ERR, APP, "Flush error. ( component = %s, type = %d)\n",
+					component_info->name, component_info->type);
+			return SPP_RET_NG;
+		}
+	}
 	return SPP_RET_OK;
 }
 
@@ -1106,26 +1299,24 @@ spp_update_classifier_table(
 int
 spp_flush(void)
 {
-	int core_cnt = 0;  /* increment core id */
-	int ret_classifier = 0;
-	struct spp_core_info *core_info = NULL;
+	int ret = -1;
 
-	for(core_cnt = 0; core_cnt < SPP_CONFIG_CORE_MAX; core_cnt++) {
-		if (g_change_core[core_cnt] == 0)
-			continue;
+	/* Initial setting of each interface. */
+	ret = flush_port();
+	if (ret < 0)
+		return ret;
 
-		core_info = &g_core_info[core_cnt];
-		if (core_info->type == SPP_CONFIG_CLASSIFIER_MAC) {
-			ret_classifier = spp_classifier_mac_update(core_info);
-			if (unlikely(ret_classifier < 0)) {
-				RTE_LOG(ERR, APP, "Flush error. ( component = classifier_mac)\n");
-				return SPP_RET_NG;
-			}
-		}
-	}
+	/* Flush of core index. */
+	flush_core();
+	memset(g_change_core, 0x00, sizeof(g_change_core));
+
+	/* Flush of component */
+	ret = flush_component();
+	if (ret < 0)
+		return ret;
 
 	/* Finally, zero-clear g_change_core */
-	memset(g_change_core, 0x00, sizeof(g_change_core));
+	memset(g_change_component, 0x00, sizeof(g_change_component));
 	return SPP_RET_OK;
 }
 
@@ -1143,3 +1334,151 @@ spp_iterate_classifier_table(
 
 	return SPP_RET_OK;
 }
+
+/**
+ * Sepeparate port id of combination of iface type and number and
+ * assign to given argment, if_type and if_no.
+ *
+ * For instance, 'ring:0' is separated to 'ring' and '0'.
+ *
+ * TODO(yasufum) change if to iface
+ */
+int
+spp_get_if_info(const char *port, enum port_type *if_type, int *if_no)
+{
+	enum port_type type = UNDEF;
+	const char *no_str = NULL;
+	char *endptr = NULL;
+
+	/* Find out which type of interface from port */
+	if (strncmp(port, SPP_IFTYPE_NIC_STR ":", strlen(SPP_IFTYPE_NIC_STR)+1) == 0) {
+		/* NIC */
+		type = PHY;
+		no_str = &port[strlen(SPP_IFTYPE_NIC_STR)+1];
+	} else if (strncmp(port, SPP_IFTYPE_VHOST_STR ":", strlen(SPP_IFTYPE_VHOST_STR)+1) == 0) {
+		/* VHOST */
+		type = VHOST;
+		no_str = &port[strlen(SPP_IFTYPE_VHOST_STR)+1];
+	} else if (strncmp(port, SPP_IFTYPE_RING_STR ":", strlen(SPP_IFTYPE_RING_STR)+1) == 0) {
+		/* RING */
+		type = RING;
+		no_str = &port[strlen(SPP_IFTYPE_RING_STR)+1];
+	} else {
+		/* OTHER */
+		RTE_LOG(ERR, APP, "Unknown interface type. (port = %s)\n", port);
+		return -1;
+	}
+
+	/* Change type of number of interface */
+	int ret_no = strtol(no_str, &endptr, 0);
+	if (unlikely(no_str == endptr) || unlikely(*endptr != '\0')) {
+		/* No IF number */
+		RTE_LOG(ERR, APP, "No interface number. (port = %s)\n", port);
+		return -1;
+	}
+
+	*if_type = type;
+	*if_no = ret_no;
+
+	RTE_LOG(DEBUG, APP, "Port = %s => Type = %d No = %d\n",
+			port, *if_type, *if_no);
+	return 0;
+}
+
+/**
+ * Generate a formatted string of conbination from interface type and
+ * number and assign to given 'port'
+ */
+int spp_format_port_string(char *port, enum port_type if_type, int if_no)
+{
+	const char* if_type_str;
+
+	switch (if_type) {
+	case PHY:
+		if_type_str = SPP_IFTYPE_NIC_STR;
+		break;
+	case RING:
+		if_type_str = SPP_IFTYPE_RING_STR;
+		break;
+	case VHOST:
+		if_type_str = SPP_IFTYPE_VHOST_STR;
+		break;
+	default:
+		return -1;
+	}
+
+	sprintf(port, "%s:%d", if_type_str, if_no);
+
+	return 0;
+}
+
+/**
+ * Change mac address of 'aa:bb:cc:dd:ee:ff' to int64 and return it
+ */
+int64_t
+spp_change_mac_str_to_int64(const char *mac)
+{
+	int64_t ret_mac = 0;
+	int64_t token_val = 0;
+	int token_cnt = 0;
+	char tmp_mac[SPP_MIN_STR_LEN];
+	char *str = tmp_mac;
+	char *saveptr = NULL;
+	char *endptr = NULL;
+
+	RTE_LOG(DEBUG, APP, "MAC address change. (mac = %s)\n", mac);
+
+	strcpy(tmp_mac, mac);
+	while(1) {
+		/* Split by colon(':') */
+		char *ret_tok = strtok_r(str, ":", &saveptr);
+		if (unlikely(ret_tok == NULL)) {
+			break;
+		}
+
+		/* Check for mal-formatted address */
+		if (unlikely(token_cnt >= ETHER_ADDR_LEN)) {
+			RTE_LOG(ERR, APP, "MAC address format error. (mac = %s)\n",
+					 mac);
+			return -1;
+		}
+
+		/* Convert string to hex value */
+		int ret_tol = strtol(ret_tok, &endptr, 16);
+		if (unlikely(ret_tok == endptr) || unlikely(*endptr != '\0')) {
+			break;
+		}
+
+		/* Append separated value to the result */
+		token_val = (int64_t)ret_tol;
+		ret_mac |= token_val << (token_cnt * 8);
+		token_cnt++;
+		str = NULL;
+	}
+
+	RTE_LOG(DEBUG, APP, "MAC address change. (mac = %s => 0x%08lx)\n",
+			 mac, ret_mac);
+	return ret_mac;
+}
+
+/**
+ * Return the type of forwarder as a member of enum of spp_component_type
+ */
+enum spp_component_type
+spp_change_component_type(const char *type_str)
+{
+	if(strncmp(type_str, CORE_TYPE_CLASSIFIER_MAC_STR,
+			 strlen(CORE_TYPE_CLASSIFIER_MAC_STR)+1) == 0) {
+		/* Classifier */
+		return SPP_COMPONENT_CLASSIFIER_MAC;
+	} else if (strncmp(type_str, CORE_TYPE_MERGE_STR,
+			 strlen(CORE_TYPE_MERGE_STR)+1) == 0) {
+		/* Merger */
+		return SPP_COMPONENT_MERGE;
+	} else if (strncmp(type_str, CORE_TYPE_FORWARD_STR,
+			 strlen(CORE_TYPE_FORWARD_STR)+1) == 0) {
+		/* Forwarder */
+		return SPP_COMPONENT_FORWARD;
+	}
+	return SPP_COMPONENT_UNUSE;
+}
diff --git a/src/vf/spp_vf.h b/src/vf/spp_vf.h
index b0da048..90a2886 100644
--- a/src/vf/spp_vf.h
+++ b/src/vf/spp_vf.h
@@ -2,18 +2,42 @@
 #define __SPP_VF_H__
 
 #include "common.h"
-#include "spp_config.h"
 
-#define SPP_CLIENT_MAX 128
+#define SPP_IFTYPE_NIC_STR   "phy"
+#define SPP_IFTYPE_VHOST_STR "vhost"
+#define SPP_IFTYPE_RING_STR  "ring"
+
+#define SPP_CLIENT_MAX    128
+#define SPP_INFO_AREA_MAX 2
+#define SPP_MIN_STR_LEN   32
+#define SPP_NAME_STR_LEN  128
+
+#define SPP_CHANGE_UPDATE_INTERVAL 10
+
+#define SPP_DEFAULT_CLASSIFIED_SPEC_STR     "default"
+#define SPP_DEFAULT_CLASSIFIED_DMY_ADDR_STR "00:00:00:00:00:01"
+#define SPP_DEFAULT_CLASSIFIED_DMY_ADDR     0x010000000000
 
 /*
- * State on core
+ * State on component
  */
 enum spp_core_status {
+	SPP_CORE_UNUSE,
 	SPP_CORE_STOP,
 	SPP_CORE_IDLE,
 	SPP_CORE_FORWARD,
-	SPP_CORE_STOP_REQUEST
+	SPP_CORE_STOP_REQUEST,
+	SPP_CORE_IDLE_REQUEST
+};
+
+/*
+ * Process type for each component
+ */
+enum spp_component_type {
+	SPP_COMPONENT_UNUSE,
+	SPP_COMPONENT_CLASSIFIER_MAC,
+	SPP_COMPONENT_MERGE,
+	SPP_COMPONENT_FORWARD,
 };
 
 /*
@@ -30,34 +54,68 @@ enum spp_classifier_type {
 enum spp_return_value {
 	SPP_RET_OK = 0,
 	SPP_RET_NG = -1,
-	SPP_RET_USED_MAC = -2,
-	SPP_RET_NOT_ADD_PORT = -3,
-	SPP_RET_USED_PORT = -4
+};
+
+/* Port type (rx or tx) */
+enum spp_port_rxtx {
+	SPP_PORT_RXTX_NONE,
+	SPP_PORT_RXTX_RX,
+	SPP_PORT_RXTX_TX,
+	SPP_PORT_RXTX_ALL,
+};
+
+/* command setting type */
+enum spp_command_action {
+	SPP_CMD_ACTION_NONE,
+	SPP_CMD_ACTION_START,
+	SPP_CMD_ACTION_STOP,
+	SPP_CMD_ACTION_ADD,
+	SPP_CMD_ACTION_DEL,
+};
+
+/*
+ * Interface information structure
+ */
+struct spp_port_index {
+	enum port_type  if_type;
+	int             if_no;
 };
 
 /*
- * Port info on core
+ * Port info
  */
-struct spp_core_port_info {
+struct spp_port_info {
 	enum port_type	if_type;
 	int		if_no;
 	int		dpdk_port;
 	uint64_t	mac_addr;
-	char		mac_addr_str[SPP_CONFIG_STR_LEN];
+	char		mac_addr_str[SPP_MIN_STR_LEN];
 };
 
 /*
+ * Component info
+ */
+struct spp_component_info {
+	char name[SPP_NAME_STR_LEN];
+	enum spp_component_type type;
+	unsigned int lcore_id;
+	int component_id;
+	int num_rx_port;
+	int num_tx_port;
+	struct spp_port_info *rx_ports[RTE_MAX_ETHPORTS];
+	struct spp_port_info *tx_ports[RTE_MAX_ETHPORTS];
+};
+
+#if 0
+/*
  * Core info
  */
 struct spp_core_info {
-	unsigned int lcore_id;
-	volatile enum spp_core_status status;
-	enum spp_core_type type;
-	int	num_rx_port;
-	int	num_tx_port;
-	struct spp_core_port_info rx_ports[RTE_MAX_ETHPORTS];
-	struct spp_core_port_info tx_ports[RTE_MAX_ETHPORTS];
+	enum spp_core_status status;
+	int num_component;
+	int component_id[SPP_CONFIG_CORE_MAX];
 };
+#endif
 
 /*
  * Get client ID
@@ -69,11 +127,33 @@ int spp_get_client_id(void);
  * Update Classifier_table
  * OK : SPP_RET_OK(0)
  * NG : SPP_RET_NG(-1)
- *    : SPP_RET_USED_MAC(-2)
- *    : SPP_RET_NOT_ADD_PORT(-3)
- *    : SPP_RET_USED_PORT(-4)
  */
-int spp_update_classifier_table(enum spp_classifier_type type, const char *data, const struct spp_config_port_info *port);
+int spp_update_classifier_table(
+		enum spp_command_action action,
+		enum spp_classifier_type type,
+		const char *data,
+		const struct spp_port_index *port);
+
+/*
+ * Update component
+ * OK : SPP_RET_OK(0)
+ * NG : SPP_RET_NG(-1)
+ */
+int spp_update_component(
+		enum spp_command_action action,
+		const char *name, unsigned int lcore_id,
+		enum spp_component_type type);
+
+/*
+ * Update port
+ * OK : SPP_RET_OK(0)
+ * NG : SPP_RET_NG(-1)
+ */
+int spp_update_port(
+		enum spp_command_action action,
+		const struct spp_port_index *port,
+		enum spp_port_rxtx rxtx,
+		const char *name);
 
 /*
  * Flush SPP component
@@ -87,7 +167,7 @@ typedef int (*spp_iterate_classifier_element_proc)(
 		void *opaque,
 		enum spp_classifier_type type,
 		const char *data,
-		const struct spp_config_port_info *port);
+		const struct spp_port_index *port);
 
 /* iterate classifier table parameters */
 struct spp_iterate_classifier_table_params {
@@ -100,4 +180,79 @@ struct spp_iterate_classifier_table_params {
  */
 int spp_iterate_classifier_table(struct spp_iterate_classifier_table_params *params);
 
+/* Get core status */
+enum spp_core_status spp_get_core_status(unsigned int lcore_id);
+
+/* Get component type of target core */
+enum spp_component_type spp_get_component_type(unsigned int lcore_id);
+
+/* Get component type being updated on target core */
+enum spp_component_type spp_get_component_type_update(unsigned int lcore_id);
+
+/*
+ * Get core ID of target component
+ * RETURN : core ID
+ */
+unsigned int spp_get_component_core(int component_id);
+
+/*
+ * Check core index change
+ * RETURN : True if index has changed.
+ */
+int spp_check_core_index(unsigned int lcore_id);
+
+/*
+ * Get name matching component ID
+ * OK : component ID
+ * NG : SPP_RET_NG
+ */
+int spp_get_component_id(const char *name);
+
+/**
+ * Check mac address used on the port for registering or removing
+ * RETURN : True if target MAC address matches MAC address of port.
+ */
+int spp_check_mac_used_port(uint64_t mac_addr, enum port_type if_type, int if_no);
+
+/*
+ * Check if port has been added.
+ * RETURN : True if port has been added.
+ */
+int spp_check_added_port(enum port_type if_type, int if_no);
+
+/*
+ * Check if component is using port.
+ * OK : match component ID
+ * NG : SPP_RET_NG
+ */
+int spp_check_used_port(enum port_type if_type, int if_no, enum spp_port_rxtx rxtx);
+
+/*
+ * Change mac address string to int64
+ * OK : int64 that store mac address
+ * NG : -1
+ */
+int64_t spp_change_mac_str_to_int64(const char *mac);
+
+/*
+ * Extract if-type/if-number from port string
+ *
+ * OK : 0
+ * NG : -1
+ */
+int spp_get_if_info(const char *port, enum port_type *if_type, int *if_no);
+
+/*
+ * Format port string form if-type/if-number
+ *
+ * OK : 0
+ * NG : -1
+ */
+int spp_format_port_string(char *port, enum port_type if_type, int if_no);
+
+/*
+ * Change component type from string to type value.
+ */
+enum spp_component_type spp_change_component_type(const char *type_str);
+
 #endif /* __SPP_VF_H__ */
-- 
1.9.1

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

* [spp] [PATCH 55/57] spp_vf: add display of status command
  2017-12-26  1:54 ` Yasufumi Ogawa
                     ` (53 preceding siblings ...)
  2017-12-28  4:56   ` [spp] [PATCH 54/57] spp_vf: support new command x-fn-spp
@ 2017-12-28  4:56   ` x-fn-spp
  2017-12-28  4:56   ` [spp] [PATCH 56/57] spp_vf: fix " x-fn-spp
  2017-12-28  4:56   ` [spp] [PATCH 57/57] spp_vf: fix l2 multicast packet forwarding x-fn-spp
  56 siblings, 0 replies; 97+ messages in thread
From: x-fn-spp @ 2017-12-28  4:56 UTC (permalink / raw)
  To: spp

From: Hiroyuki Nakamura <nakamura.hioryuki@po.ntt-tx.co.jp>

* Display client ID.
* Display information for each port.
* Display information for each core.

Signed-off-by: Kentaro Watanabe <watanabe.kentaro.z01@as.ntt-tx.co.jp>
Signed-off-by: Yasufum Ogawa <ogawa.yasufumi@lab.ntt.co.jp>
---
 src/spp_vf.py           |  25 ++++--
 src/vf/classifier_mac.c |  86 +++++++++++++++---
 src/vf/classifier_mac.h |  10 +++
 src/vf/command_dec.c    |   2 +-
 src/vf/command_proc.c   | 232 ++++++++++++++++++++++++++++++++++++++++++++++--
 src/vf/spp_forward.c    |  73 ++++++++++++---
 src/vf/spp_forward.h    |   8 +-
 src/vf/spp_vf.c         |  51 +++++++++++
 src/vf/spp_vf.h         |  30 +++++++
 9 files changed, 479 insertions(+), 38 deletions(-)

diff --git a/src/spp_vf.py b/src/spp_vf.py
index 505a142..a96b987 100755
--- a/src/spp_vf.py
+++ b/src/spp_vf.py
@@ -40,6 +40,7 @@ def connectionthread(name, client_id, conn, m2s, s2m):
     """Manage secondary process connections"""
 
     cmd_str = 'hello'
+    recv_str = 'recv'
 
     #infinite loop so that function do not terminate and thread do not end.
     while True:
@@ -60,12 +61,24 @@ def connectionthread(name, client_id, conn, m2s, s2m):
 
         #Receiving from secondary
         try:
-            data = conn.recv(2048) # 2048 stands for bytes of data to be received
-            if data:
-                s2m.put("recv:" + str(conn.fileno()) + ":" + "{" + data + "}")
-            else:
-                s2m.put("closing:" + str(conn))
+            recv_str = ""
+            while True:
+                data = conn.recv(1024) # 1024 stands for bytes of data to be received
+                if data:
+                    recv_str = recv_str + data
+                    if len(data) < 1024:
+                        break
+                else:
+                    break
+            if len(recv_str) > 0:
+                recv_str = "recv:" + str(conn.fileno()) + ":len:" + str(len(recv_str)) + ":\n{" + recv_str + "}\n"
+
+            if not data:
+                s2m.put(recv_str + "closing:" + str(conn))
                 break
+
+            #s2m.put("recv:" + str(conn.fileno()) + ":{" + recv_str + "}")
+            s2m.put(recv_str)
         except Exception, excep:
             print (str(excep))
             break
@@ -212,7 +225,7 @@ def primarythread(sock, main2primary, primary2main):
 
             #Receiving from primary
             try:
-                data = conn.recv(2048) # 2048 stands for bytes of data to be received
+                data = conn.recv(1024) # 1024 stands for bytes of data to be received
                 if data:
                     primary2main.put("recv:" + str(addr) + ":" + "{" + data + "}")
                 else:
diff --git a/src/vf/classifier_mac.c b/src/vf/classifier_mac.c
index 937a8c0..2dc6071 100644
--- a/src/vf/classifier_mac.c
+++ b/src/vf/classifier_mac.c
@@ -67,21 +67,23 @@ static const size_t ETHER_ADDR_STR_BUF_SZ =
 struct classified_data {
 	enum port_type  if_type;              /* interface type (see "enum port_type") */
 	int             if_no;                /* index of ports handled by classifier  */
-	int             if_no_global;         /* interface number                      */
-	uint8_t         port;                 /* port number used by dpdk              */
+	int             if_no_global;         /* id for interface generated by spp_vf  */
+	uint8_t         port;                 /* id for port generated by DPDK         */
 	uint16_t        num_pkt;              /* the number of packets in pkts[]       */
 	struct rte_mbuf *pkts[MAX_PKT_BURST]; /* packet array to be classified         */
 };
 
 /* classifier information */
 struct classifier_mac_info {
-	struct rte_hash *classifier_table;
-	int num_active_classified;
-	int active_classifieds[RTE_MAX_ETHPORTS];
-	int default_classified;
-	int n_classified_data_tx;
-	struct classified_data classified_data_rx;
+	char name[SPP_NAME_STR_LEN];               /* component name                    */
+	struct rte_hash *classifier_table;         /* hash table keeps classifier_table */
+	int num_active_classified;                 /* number of valid classification    */
+	int active_classifieds[RTE_MAX_ETHPORTS];  /* index of valid classification     */
+	int default_classified;                    /* index of default classification   */
+	int n_classified_data_tx;                  /* number of transmission ports      */
+	struct classified_data classified_data_rx; /* recive port handled by classifier */
 	struct classified_data classified_data_tx[RTE_MAX_ETHPORTS];
+						/* transmission ports handled by classifier */
 };
 
 /* classifier management information */
@@ -126,7 +128,13 @@ init_classifier_info(struct classifier_mac_info *classifier_info,
 	classifier_info->num_active_classified = 0;
 	classifier_info->default_classified = -1;
 	classifier_info->n_classified_data_tx = component_info->num_tx_port;
-	if (component_info->num_rx_port != 0) {
+	if (component_info->num_rx_port == 0) {
+		classified_data_rx->if_type      = UNDEF;
+		classified_data_rx->if_no        = 0;
+		classified_data_rx->if_no_global = 0;
+		classified_data_rx->port         = 0;
+		classified_data_rx->num_pkt      = 0;
+	} else {
 		classified_data_rx->if_type      = component_info->rx_ports[0]->if_type;
 		classified_data_rx->if_no        = 0;
 		classified_data_rx->if_no_global = component_info->rx_ports[0]->if_no;
@@ -273,6 +281,8 @@ uninit_classifier(struct classifier_mac_mng_info *classifier_mng_info)
 		if (classifier_mng_info->info[i].classifier_table != NULL){
 			rte_hash_free(classifier_mng_info->info[i].classifier_table);
 			classifier_mng_info->info[i].classifier_table = NULL;
+			classifier_mng_info->ref_index = 0;
+			classifier_mng_info->upd_index = 0;
 		}
 	}
 }
@@ -478,6 +488,7 @@ spp_classifier_mac_update(struct spp_component_info *component_info)
 				"Cannot update classifer mac. ret=%d\n", ret);
 		return ret;
 	}
+	memcpy(classifier_info->name, component_info->name, SPP_NAME_STR_LEN);
 
 	/* change index of reference side */
 	classifier_mng_info->upd_index = classifier_mng_info->ref_index;
@@ -548,6 +559,9 @@ spp_classifier_mac_do(int id)
 			prev_tsc = cur_tsc;
 		}
 
+		if (classified_data_rx->if_type == UNDEF)
+			continue;
+
 		/* retrieve packets */
 		n_rx = rte_eth_rx_burst(classified_data_rx->port, 0,
 				rx_pkts, MAX_PKT_BURST);
@@ -573,8 +587,60 @@ spp_classifier_mac_do(int id)
 	return 0;
 }
 
+/* classifier iterate component information */
+int
+spp_classifier_component_info_iterate(unsigned int lcore_id, int id,
+		struct spp_iterate_core_params *params)
+{
+	int ret = -1;
+	int i, num_tx, num_rx = 0;
+	struct classifier_mac_mng_info *classifier_mng_info;
+	struct classifier_mac_info *classifier_info;
+	struct classified_data *classified_data;
+	struct spp_port_index rx_ports[RTE_MAX_ETHPORTS];
+	struct spp_port_index tx_ports[RTE_MAX_ETHPORTS];
+
+	classifier_mng_info = g_classifier_mng_info + id;
+	if (! is_used_mng_info(classifier_mng_info)) {
+		RTE_LOG(ERR, SPP_CLASSIFIER_MAC,
+				"Component[%d] Not used. (status)(core = %d, type = %d)\n",
+				id, lcore_id, SPP_COMPONENT_CLASSIFIER_MAC);
+		return -1;
+	}
+
+	classifier_info = classifier_mng_info->info + 
+			classifier_mng_info->ref_index;
+
+	classified_data = classifier_info->classified_data_tx;
+
+	memset(rx_ports, 0x00, sizeof(rx_ports));
+	if (classifier_info->classified_data_rx.if_type != UNDEF) {
+		num_rx = 1;
+		rx_ports[0].if_type = classifier_info->classified_data_rx.if_type;
+		rx_ports[0].if_no   = classifier_info->classified_data_rx.if_no_global;
+	}
+
+	memset(tx_ports, 0x00, sizeof(tx_ports));
+	num_tx = classifier_info->n_classified_data_tx;
+	for (i = 0; i < num_tx; i++) {
+		tx_ports[i].if_type = classified_data[i].if_type;
+		tx_ports[i].if_no   = classified_data[i].if_no_global;
+	}
+
+	/* Set the information with the function specified by the command. */
+	ret = (*params->element_proc)(
+		params->opaque, lcore_id,
+		classifier_info->name, SPP_TYPE_CLASSIFIER_MAC_STR,
+		num_rx, rx_ports, num_tx, tx_ports);
+	if (unlikely(ret != 0))
+		return -1;
+
+	return 0;
+}
+
 /* classifier(mac address) iterate classifier table. */
-int spp_classifier_mac_iterate_table(
+int
+spp_classifier_mac_iterate_table(
 		struct spp_iterate_classifier_table_params *params)
 {
 	int ret, i;
diff --git a/src/vf/classifier_mac.h b/src/vf/classifier_mac.h
index f182668..b38ce70 100644
--- a/src/vf/classifier_mac.h
+++ b/src/vf/classifier_mac.h
@@ -29,6 +29,16 @@ int spp_classifier_mac_update(struct spp_component_info *component_info);
  */
 int spp_classifier_mac_do(int id);
 
+/*
+ * classifier iterate component information
+ *
+ * @ret_val 0  succeeded.
+ * @ret_val -1 failed.
+ */
+int
+spp_classifier_component_info_iterate(unsigned int lcore_id, int id,
+		struct spp_iterate_core_params *params);
+
 /**
  * classifier(mac address) iterate classifier table.
  */
diff --git a/src/vf/command_dec.c b/src/vf/command_dec.c
index 166901c..56360e9 100644
--- a/src/vf/command_dec.c
+++ b/src/vf/command_dec.c
@@ -566,7 +566,7 @@ static struct decode_command_list command_list[] = {
 	{ "_get_client_id",   1, 1, NULL                            }, /* _get_client_id   */
 	{ "status",           1, 1, NULL                            }, /* status           */
 	{ "exit",             1, 1, NULL                            }, /* exit             */
-	{ "component",        3, 5, decode_comand_parameter_in_list }, /* port             */
+	{ "component",        3, 5, decode_comand_parameter_in_list }, /* component        */
 	{ "port",             5, 5, decode_comand_parameter_in_list }, /* port             */
 	{ "",                 0, 0, NULL                            }  /* termination      */
 };
diff --git a/src/vf/command_proc.c b/src/vf/command_proc.c
index 0a45874..6159e87 100644
--- a/src/vf/command_proc.c
+++ b/src/vf/command_proc.c
@@ -243,9 +243,191 @@ append_response_client_id_value(json_t *parent_obj)
 	return 0;
 }
 
+/* append client-id value */
+static int
+append_client_id_value(json_t *parent_obj)
+{
+	int ret = -1;
+	ret = json_object_set_new(parent_obj, "client-id",
+			json_integer(spp_get_client_id()));
+	if (unlikely(ret != 0))
+		return -1;
+
+	return 0;
+}
+
+/* append interface array */
+static int
+append_interface_array(json_t *parent_obj, const char *name,
+		const enum port_type type)
+{
+	int ret = -1;
+	int i = 0;
+	json_t *array_obj;
+	array_obj = json_array();
+	if (unlikely(array_obj == NULL))
+		return -1;
+
+	for (i = 0; i < RTE_MAX_ETHPORTS; i++) {
+		if (!spp_check_flush_port(type, i))
+			continue;
+
+		ret = json_array_append_new(array_obj, json_integer(i));
+		if (unlikely(ret != 0)) {
+			json_decref(array_obj);
+			return -1;
+		}
+	}
+
+	ret = json_object_set_new(parent_obj, name, array_obj);
+	if (unlikely(ret != 0)) {
+		json_decref(array_obj);
+		return -1;
+	}
+
+	return 0;
+}
+
+/* append interface value */
+static int
+append_interface_value(json_t *parent_obj)
+{
+	int ret = -1;
+	ret = append_interface_array(parent_obj, "phy", PHY);
+	if (unlikely(ret != 0))
+		return -1;
+
+	ret = append_interface_array(parent_obj, "vhost", VHOST);
+	if (unlikely(ret != 0))
+		return -1;
+
+	ret = append_interface_array(parent_obj, "ring", RING);
+	if (unlikely(ret != 0))
+		return -1;
+
+	return 0;
+}
+
+/* append port array */
+static int
+apeend_port_array(json_t *parent_obj, const char *name,
+		const int num, const struct spp_port_index *ports)
+{
+	int ret = -1;
+	int i = 0;
+	char port_str[64];
+	json_t *array_obj;
+	array_obj = json_array();
+	if (unlikely(array_obj == NULL))
+		return -1;
+
+	for (i = 0; i < num; i++) {
+		spp_format_port_string(port_str, ports[i].if_type,
+				ports[i].if_no);
+		ret = json_array_append_new(array_obj, json_string(port_str));
+		if (unlikely(ret != 0)) {
+			json_decref(array_obj);
+			return -1;
+		}
+	}
+
+	ret = json_object_set_new(parent_obj, name, array_obj);
+	if (unlikely(ret != 0)) {
+		json_decref(array_obj);
+		return -1;
+	}
+
+	return 0;
+}
+
+/* append core element value */
+static int
+append_core_element_value(
+		void *opaque, const unsigned int lcore_id,
+		const char *name, const char *type,
+		const int num_rx, const struct spp_port_index *rx_ports,
+		const int num_tx, const struct spp_port_index *tx_ports)
+{
+	int ret = -1;
+	json_t *parent_obj = (json_t *)opaque;
+	json_t *tab_obj;
+
+	tab_obj = json_object();
+	if (unlikely(tab_obj == NULL))
+		return -1;
+
+	ret = json_object_set_new(tab_obj, "core", json_integer(lcore_id));
+	if (unlikely(ret != 0)) {
+		json_decref(tab_obj);
+		return -1;
+	}
+
+	ret = json_object_set_new(tab_obj, "name", json_string(name));
+	if (unlikely(ret != 0)) {
+		json_decref(tab_obj);
+		return -1;
+	}
+
+	ret = json_object_set_new(tab_obj, "type", json_string(type));
+	if (unlikely(ret != 0)) {
+		json_decref(tab_obj);
+		return -1;
+	}
+
+	ret = apeend_port_array(tab_obj, "rx_port", num_rx, rx_ports);
+	if (unlikely(ret != 0)) {
+		json_decref(tab_obj);
+		return -1;
+	}
+
+	ret = apeend_port_array(tab_obj, "tx_port", num_tx, tx_ports);
+	if (unlikely(ret != 0)) {
+		json_decref(tab_obj);
+		return -1;
+	}
+
+	ret = json_array_append_new(parent_obj, tab_obj);
+	if (unlikely(ret != 0)) {
+		json_decref(tab_obj);
+		return -1;
+	}
+
+	return 0;
+}
+
+/* append core value */
+static int
+append_response_core_value(json_t *parent_obj)
+{
+	int ret = -1;
+	json_t *tab_obj;
+	struct spp_iterate_core_params itr_params;
+
+	tab_obj = json_array();
+	if (unlikely(tab_obj == NULL))
+		return -1;
+
+	itr_params.opaque = tab_obj;
+	itr_params.element_proc = append_core_element_value;
+
+	ret = spp_iterate_core_info(&itr_params);
+	if (unlikely(ret != 0)) {
+		json_decref(tab_obj);
+		return -1;
+	}
+
+	ret = json_object_set_new(parent_obj, "core", tab_obj);
+	if (unlikely(ret != 0)) {
+		json_decref(tab_obj);
+		return -1;
+	}
+
+	return 0;
+}
+
 /* append classifier element value */
-static
-int append_classifier_element_value(
+static int
+append_classifier_element_value(
 		void *opaque,
 		__rte_unused enum spp_classifier_type type,
 		const char *data,
@@ -265,12 +447,12 @@ int append_classifier_element_value(
 	return 0;
 }
 
-/* append info value(status response) to specified json object */
+/* append classifier_table value */
 static int 
-append_response_info_value(json_t *parent_obj)
+append_response_classifier_value(json_t *parent_obj)
 {
 	int ret = -1;
-	json_t *info_obj, *tab_obj;
+	json_t *tab_obj;
 	struct spp_iterate_classifier_table_params itr_params;
 
 	/* create classifier_table array */
@@ -287,16 +469,48 @@ append_response_info_value(json_t *parent_obj)
 		return -1;
 	}
 
+	ret = json_object_set_new(parent_obj, "classifier_table", tab_obj);
+	if (unlikely(ret != 0)) {
+		json_decref(tab_obj);
+		return -1;
+	}
+
+	return 0;
+}
+
+/* append info value(status response) to specified json object */
+static int 
+append_response_info_value(json_t *parent_obj)
+{
+	int ret = -1;
+	json_t *info_obj;
+
 	/* set classifier_table object in info object */
 	info_obj = json_object();
-	if (unlikely(info_obj == NULL)) {
-		json_decref(tab_obj);
+	if (unlikely(info_obj == NULL))
+		return -1;
+
+	ret = append_client_id_value(info_obj);
+	if (unlikely(ret != 0)) {
+		json_decref(info_obj);
 		return -1;
 	}
 
-	ret = json_object_set_new(info_obj, "classifier_table", tab_obj);
+	ret = append_interface_value(info_obj);
 	if (unlikely(ret != 0)) {
-		json_decref(tab_obj);
+		json_decref(info_obj);
+		return -1;
+	}
+
+	ret = append_response_core_value(info_obj);
+	if (unlikely(ret != 0)) {
+		json_decref(info_obj);
+		return -1;
+	}
+
+	ret = append_response_classifier_value(info_obj);
+	if (unlikely(ret != 0)) {
+		json_decref(info_obj);
 		return -1;
 	}
 
diff --git a/src/vf/spp_forward.c b/src/vf/spp_forward.c
index 8a0980a..dbe96dc 100644
--- a/src/vf/spp_forward.c
+++ b/src/vf/spp_forward.c
@@ -12,15 +12,19 @@ struct forward_rxtx {
 	struct spp_port_info tx;
 };
 
+/* Information on the path used for forward. */
 struct forward_path {
-	int num;
+	char name[SPP_NAME_STR_LEN];	/* component name          */
+	volatile enum spp_component_type type;	/* component type          */
+	int num;			/* number of receive ports */
 	struct forward_rxtx ports[RTE_MAX_ETHPORTS];
+					/* port used for transfer  */
 };
 
+/* Information for forward. */
 struct forward_info {
-	enum spp_component_type type;
-	volatile int ref_index;
-	volatile int upd_index;
+	volatile int ref_index;		/* index to reference area */
+	volatile int upd_index;		/* index to update area    */
 	struct forward_path path[SPP_INFO_AREA_MAX];
 };
 
@@ -42,8 +46,6 @@ spp_forward_init(void)
 static void
 clear_forward_info(int id)
 {
-	struct forward_info *info = &g_forward_info[id];
-	info->type = SPP_COMPONENT_UNUSE;
 	memset(&g_forward_info[id].path, 0x00, sizeof(struct forward_path));
 }
 
@@ -75,10 +77,11 @@ spp_forward_update(struct spp_component_info *component)
 	clear_forward_info(component->component_id);
 
 	RTE_LOG(INFO, FORWARD,
-			"Component[%d] Start update component. (type = %d)\n",
-			component->component_id, component->type);
+			"Component[%d] Start update component. (name = %s, type = %d)\n",
+			component->component_id, component->name, component->type);
 
-	info->type = component->type;
+	memcpy(&path->name, component->name, SPP_NAME_STR_LEN);
+	path->type = component->type;
 	path->num = component->num_rx_port;
 	for (cnt = 0; cnt < num_rx; cnt++)
 		memcpy(&path->ports[cnt].rx, component->rx_ports[cnt],
@@ -93,8 +96,9 @@ spp_forward_update(struct spp_component_info *component)
 	while(likely(info->ref_index == info->upd_index))
 		rte_delay_us_block(SPP_CHANGE_UPDATE_INTERVAL);
 
-	RTE_LOG(INFO, FORWARD, "Component[%d] Complete update component. (type = %d)\n",
-			component->component_id, component->type);
+	RTE_LOG(INFO, FORWARD,
+			"Component[%d] Complete update component. (name = %s, type = %d)\n",
+			component->component_id, component->name, component->type);
 
 	return 0;
 }
@@ -160,3 +164,50 @@ spp_forward(int id)
 	}
 	return 0;
 }
+
+/* Merge/Forward iterate component information */
+int
+spp_forward_core_info_iterate(unsigned int lcore_id, int id,
+		struct spp_iterate_core_params *params)
+{
+	int ret = -1;
+	int cnt, num_tx;
+	const char *component_type = NULL;
+	struct forward_info *info = &g_forward_info[id];
+	struct forward_path *path = &info->path[info->ref_index];
+	struct spp_port_index rx_ports[RTE_MAX_ETHPORTS];
+	struct spp_port_index tx_ports[RTE_MAX_ETHPORTS];
+
+	if (unlikely(path->type == SPP_COMPONENT_UNUSE)) {
+		RTE_LOG(ERR, FORWARD,
+				"Component[%d] Not used. (status)(core = %d, type = %d)\n",
+				id, lcore_id, path->type);
+		return -1;
+	}
+
+	if (path->type == SPP_COMPONENT_MERGE)
+		component_type = SPP_TYPE_MERGE_STR;
+	else
+		component_type = SPP_TYPE_FORWARD_STR;
+
+	memset(rx_ports, 0x00, sizeof(rx_ports));
+	for (cnt = 0; cnt < path->num; cnt++) {
+		rx_ports[cnt].if_type = path->ports[cnt].rx.if_type;
+		rx_ports[cnt].if_no   = path->ports[cnt].rx.if_no;
+	}
+
+	memset(tx_ports, 0x00, sizeof(tx_ports));
+	num_tx = (path->num > 0)?1:0;
+	tx_ports[0].if_type = path->ports[0].tx.if_type;
+	tx_ports[0].if_no   = path->ports[0].tx.if_no;
+
+	/* Set the information with the function specified by the command. */
+	ret = (*params->element_proc)(
+		params->opaque, lcore_id,
+		path->name, component_type,
+		path->num, rx_ports, num_tx, tx_ports);
+	if (unlikely(ret != 0))
+		return -1;
+
+	return 0;
+}
diff --git a/src/vf/spp_forward.h b/src/vf/spp_forward.h
index 729dbe8..ed0744d 100644
--- a/src/vf/spp_forward.h
+++ b/src/vf/spp_forward.h
@@ -1,11 +1,13 @@
 #ifndef __SPP_FORWARD_H__
 #define __SPP_FORWARD_H__
 
-
+/* Clear info */
 void spp_forward_init(void);
 
+/* Clear info for one element. */
 void spp_forward_init_info(int id);
 
+/* Update forward info */
 int spp_forward_update(struct spp_component_info *component);
 
 /*
@@ -13,4 +15,8 @@ int spp_forward_update(struct spp_component_info *component);
  */
 int spp_forward(int id);
 
+/* Merge/Forward iterate component information */
+int spp_forward_core_info_iterate(unsigned int lcore_id, int id,
+		struct spp_iterate_core_params *params);
+
 #endif /* __SPP_FORWARD_H__ */
diff --git a/src/vf/spp_vf.c b/src/vf/spp_vf.c
index d6eb7b2..f97c348 100644
--- a/src/vf/spp_vf.c
+++ b/src/vf/spp_vf.c
@@ -488,6 +488,7 @@ set_nic_interface(void)
 	}
 
 	for (nic_cnt = 0; nic_cnt < g_if_info.num_nic; nic_cnt++) {
+		g_if_info.nic[nic_cnt].if_type   = PHY;
 		g_if_info.nic[nic_cnt].dpdk_port = nic_cnt;
 	}
 
@@ -842,6 +843,16 @@ spp_check_added_port(enum port_type if_type, int if_no)
 }
 
 /*
+ * Check if port has been flushed.
+ */
+int
+spp_check_flush_port(enum port_type if_type, int if_no)
+{
+	struct spp_port_info *port = get_if_area(if_type, if_no);
+	return port->dpdk_port >= 0;
+}
+
+/*
  * Check if component is using port.
  */
 int
@@ -1068,6 +1079,7 @@ spp_update_component(
 		core->num++;
 		ret = SPP_RET_OK;
 		tmp_lcore_id = lcore_id;
+		g_change_component[component_id] = 1;
 		break;
 
 	case SPP_CMD_ACTION_STOP:
@@ -1091,6 +1103,7 @@ spp_update_component(
 			core->type = SPP_COMPONENT_UNUSE;
 
 		ret = SPP_RET_OK;
+		g_change_component[component_id] = 0;
 		break;
 
 	default:
@@ -1320,6 +1333,44 @@ spp_flush(void)
 	return SPP_RET_OK;
 }
 
+/* Iterate core infomartion */
+int
+spp_iterate_core_info(struct spp_iterate_core_params *params)
+{
+	int ret;
+	int core_cnt, cnt;
+	struct core_info *core = NULL;
+
+	for (core_cnt = 0; core_cnt < RTE_MAX_LCORE; core_cnt++) {
+		if (spp_get_core_status(core_cnt) == SPP_CORE_UNUSE)
+			continue;
+
+		core = get_core_info(core_cnt);
+		for (cnt = 0; cnt < core->num; cnt++) {
+			if (core->type == SPP_COMPONENT_CLASSIFIER_MAC) {
+				ret = spp_classifier_component_info_iterate(
+						core_cnt,
+						core->id[cnt],
+						params);
+			} else {
+				ret = spp_forward_core_info_iterate(
+						core_cnt,
+						core->id[cnt],
+						params);
+			}
+			if (unlikely(ret != 0)) {
+				RTE_LOG(ERR, APP, "Cannot iterate core information. "
+						"(core = %d, type = %d)\n",
+						core_cnt, core->type);
+				return SPP_RET_NG;
+			}
+		}
+	}
+
+	return SPP_RET_OK;
+}
+
+/* Iterate Classifier_table */
 int
 spp_iterate_classifier_table(
 		struct spp_iterate_classifier_table_params *params)
diff --git a/src/vf/spp_vf.h b/src/vf/spp_vf.h
index 90a2886..9e846ef 100644
--- a/src/vf/spp_vf.h
+++ b/src/vf/spp_vf.h
@@ -3,6 +3,10 @@
 
 #include "common.h"
 
+#define SPP_TYPE_CLASSIFIER_MAC_STR "classifier_mac"
+#define SPP_TYPE_MERGE_STR          "merge"
+#define SPP_TYPE_FORWARD_STR        "forward"
+
 #define SPP_IFTYPE_NIC_STR   "phy"
 #define SPP_IFTYPE_VHOST_STR "vhost"
 #define SPP_IFTYPE_RING_STR  "ring"
@@ -162,6 +166,26 @@ int spp_update_port(
  */
 int spp_flush(void);
 
+/* definition of iterated core element procedure function */
+typedef int (*spp_iterate_core_element_proc)(
+		void *opaque,
+		const unsigned int lcore_id,
+		const char *name,
+		const char *type,
+		const int num_rx,
+		const struct spp_port_index *rx_ports,
+		const int num_tx,
+		const struct spp_port_index *tx_ports);
+
+/* iterate core information  parameters */
+struct spp_iterate_core_params {
+	void *opaque;
+	spp_iterate_core_element_proc element_proc;
+};
+
+/* Iterate core infomartion */
+int spp_iterate_core_info(struct spp_iterate_core_params *params);
+
 /* definition of iterated classifier element procedure function */
 typedef int (*spp_iterate_classifier_element_proc)(
 		void *opaque,
@@ -221,6 +245,12 @@ int spp_check_mac_used_port(uint64_t mac_addr, enum port_type if_type, int if_no
 int spp_check_added_port(enum port_type if_type, int if_no);
 
 /*
+ * Check if port has been flushed.
+ * RETURN : True if port has been flushed.
+ */
+int spp_check_flush_port(enum port_type if_type, int if_no);
+
+/*
  * Check if component is using port.
  * OK : match component ID
  * NG : SPP_RET_NG
-- 
1.9.1

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

* [spp] [PATCH 56/57] spp_vf: fix status command
  2017-12-26  1:54 ` Yasufumi Ogawa
                     ` (54 preceding siblings ...)
  2017-12-28  4:56   ` [spp] [PATCH 55/57] spp_vf: add display of status command x-fn-spp
@ 2017-12-28  4:56   ` x-fn-spp
  2017-12-28  4:56   ` [spp] [PATCH 57/57] spp_vf: fix l2 multicast packet forwarding x-fn-spp
  56 siblings, 0 replies; 97+ messages in thread
From: x-fn-spp @ 2017-12-28  4:56 UTC (permalink / raw)
  To: spp

From: Hiroyuki Nakamura <nakamura.hioryuki@po.ntt-tx.co.jp>

Fix to display "unuse" even when the core is unused.

Signed-off-by: Kentaro Watanabe <watanabe.kentaro.z01@as.ntt-tx.co.jp>
Signed-off-by: Yasufum Ogawa <ogawa.yasufumi@lab.ntt.co.jp>
---
 src/vf/command_proc.c | 33 ++++++++++++++++++++-------------
 src/vf/spp_vf.c       | 28 +++++++++++++++++++++-------
 src/vf/spp_vf.h       |  1 +
 3 files changed, 42 insertions(+), 20 deletions(-)

diff --git a/src/vf/command_proc.c b/src/vf/command_proc.c
index 6159e87..ec2da51 100644
--- a/src/vf/command_proc.c
+++ b/src/vf/command_proc.c
@@ -349,6 +349,7 @@ append_core_element_value(
 		const int num_tx, const struct spp_port_index *tx_ports)
 {
 	int ret = -1;
+	int unuse_flg = 0;
 	json_t *parent_obj = (json_t *)opaque;
 	json_t *tab_obj;
 
@@ -356,16 +357,20 @@ append_core_element_value(
 	if (unlikely(tab_obj == NULL))
 		return -1;
 
+	unuse_flg = strcmp(type, SPP_TYPE_UNUSE_STR);
+
 	ret = json_object_set_new(tab_obj, "core", json_integer(lcore_id));
 	if (unlikely(ret != 0)) {
 		json_decref(tab_obj);
 		return -1;
 	}
 
-	ret = json_object_set_new(tab_obj, "name", json_string(name));
-	if (unlikely(ret != 0)) {
-		json_decref(tab_obj);
-		return -1;
+	if (unuse_flg) {
+		ret = json_object_set_new(tab_obj, "name", json_string(name));
+		if (unlikely(ret != 0)) {
+			json_decref(tab_obj);
+			return -1;
+		}
 	}
 
 	ret = json_object_set_new(tab_obj, "type", json_string(type));
@@ -374,16 +379,18 @@ append_core_element_value(
 		return -1;
 	}
 
-	ret = apeend_port_array(tab_obj, "rx_port", num_rx, rx_ports);
-	if (unlikely(ret != 0)) {
-		json_decref(tab_obj);
-		return -1;
-	}
+	if (unuse_flg) {
+		ret = apeend_port_array(tab_obj, "rx_port", num_rx, rx_ports);
+		if (unlikely(ret != 0)) {
+			json_decref(tab_obj);
+			return -1;
+		}
 
-	ret = apeend_port_array(tab_obj, "tx_port", num_tx, tx_ports);
-	if (unlikely(ret != 0)) {
-		json_decref(tab_obj);
-		return -1;
+		ret = apeend_port_array(tab_obj, "tx_port", num_tx, tx_ports);
+		if (unlikely(ret != 0)) {
+			json_decref(tab_obj);
+			return -1;
+		}
 	}
 
 	ret = json_array_append_new(parent_obj, tab_obj);
diff --git a/src/vf/spp_vf.c b/src/vf/spp_vf.c
index f97c348..7626ba7 100644
--- a/src/vf/spp_vf.c
+++ b/src/vf/spp_vf.c
@@ -1338,30 +1338,44 @@ int
 spp_iterate_core_info(struct spp_iterate_core_params *params)
 {
 	int ret;
-	int core_cnt, cnt;
+	int lcore_id, cnt;
 	struct core_info *core = NULL;
 
-	for (core_cnt = 0; core_cnt < RTE_MAX_LCORE; core_cnt++) {
-		if (spp_get_core_status(core_cnt) == SPP_CORE_UNUSE)
+	RTE_LCORE_FOREACH_SLAVE(lcore_id) {
+		if (spp_get_core_status(lcore_id) == SPP_CORE_UNUSE)
 			continue;
 
-		core = get_core_info(core_cnt);
+		core = get_core_info(lcore_id);
+		if (core->num == 0) {
+			ret = (*params->element_proc)(
+				params->opaque, lcore_id,
+				"", SPP_TYPE_UNUSE_STR,
+				0, NULL, 0, NULL);
+			if (unlikely(ret != 0)) {
+				RTE_LOG(ERR, APP, "Cannot iterate core information. "
+						"(core = %d, type = %d)\n",
+						lcore_id, SPP_COMPONENT_UNUSE);
+				return SPP_RET_NG;
+			}
+			continue;
+		}
+
 		for (cnt = 0; cnt < core->num; cnt++) {
 			if (core->type == SPP_COMPONENT_CLASSIFIER_MAC) {
 				ret = spp_classifier_component_info_iterate(
-						core_cnt,
+						lcore_id,
 						core->id[cnt],
 						params);
 			} else {
 				ret = spp_forward_core_info_iterate(
-						core_cnt,
+						lcore_id,
 						core->id[cnt],
 						params);
 			}
 			if (unlikely(ret != 0)) {
 				RTE_LOG(ERR, APP, "Cannot iterate core information. "
 						"(core = %d, type = %d)\n",
-						core_cnt, core->type);
+						lcore_id, core->type);
 				return SPP_RET_NG;
 			}
 		}
diff --git a/src/vf/spp_vf.h b/src/vf/spp_vf.h
index 9e846ef..ea2baf1 100644
--- a/src/vf/spp_vf.h
+++ b/src/vf/spp_vf.h
@@ -6,6 +6,7 @@
 #define SPP_TYPE_CLASSIFIER_MAC_STR "classifier_mac"
 #define SPP_TYPE_MERGE_STR          "merge"
 #define SPP_TYPE_FORWARD_STR        "forward"
+#define SPP_TYPE_UNUSE_STR          "unuse"
 
 #define SPP_IFTYPE_NIC_STR   "phy"
 #define SPP_IFTYPE_VHOST_STR "vhost"
-- 
1.9.1

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

* [spp] [PATCH 57/57] spp_vf: fix l2 multicast packet forwarding
  2017-12-26  1:54 ` Yasufumi Ogawa
                     ` (55 preceding siblings ...)
  2017-12-28  4:56   ` [spp] [PATCH 56/57] spp_vf: fix " x-fn-spp
@ 2017-12-28  4:56   ` x-fn-spp
  56 siblings, 0 replies; 97+ messages in thread
From: x-fn-spp @ 2017-12-28  4:56 UTC (permalink / raw)
  To: spp

From: Hiroyuki Nakamura <nakamura.hioryuki@po.ntt-tx.co.jp>

Since ref_cnt was added extra when sending the multicast packet,
it is fixed so as to subtract the extra.

Signed-off-by: Kentaro Watanabe <watanabe.kentaro.z01@as.ntt-tx.co.jp>
Signed-off-by: Yasufum Ogawa <ogawa.yasufumi@lab.ntt.co.jp>
---
 src/vf/classifier_mac.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/src/vf/classifier_mac.c b/src/vf/classifier_mac.c
index 2dc6071..333b581 100644
--- a/src/vf/classifier_mac.c
+++ b/src/vf/classifier_mac.c
@@ -372,7 +372,7 @@ handle_l2multicast_packet(struct rte_mbuf *pkt,
 		return;
 	}
 
-	rte_mbuf_refcnt_update(pkt, classifier_info->num_active_classified);
+	rte_mbuf_refcnt_update(pkt, (classifier_info->num_active_classified - 1));
 
 	for (i= 0; i < classifier_info->num_active_classified; i++) {
 		push_packet(pkt, classified_data + 
-- 
1.9.1

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

* Re: [spp] [PATCH 01/57] spp_vf: add vf functions
  2017-12-28  4:55   ` [spp] [PATCH 01/57] spp_vf: add vf functions x-fn-spp
@ 2017-12-28  8:49     ` Yasufumi Ogawa
  0 siblings, 0 replies; 97+ messages in thread
From: Yasufumi Ogawa @ 2017-12-28  8:49 UTC (permalink / raw)
  To: x-fn-spp, spp

Hi Hiroyuki,

Thank you for your contribution! I would like to review your patches for 
merging.

Thanks,
Yasufumi

On 2017/12/28 13:55, x-fn-spp@sl.ntt-tx.co.jp wrote:
> From: Hiroyuki Nakamura <nakamura.hioryuki@po.ntt-tx.co.jp>
> 
> Hi everyone,
> 
> This the first patch of series for spp_vf. Some of them might not comply
> with coding style for whitespace or indenting and I would like to send
> patches to fix it later.
> 
> I also would like to send another series of patches for documentation after
> you accept first series.
> 
> Thanks,
> 
> * Classifier by MAC address
> * Forwarder
> * Merger
> 
> Signed-off-by: Tomoyuki Mizuguchi <mizuguchi.tomoyuki@po.ntt-tx.co.jp>
> Signed-off-by: Yasufum Ogawa <ogawa.yasufumi@lab.ntt.co.jp>
> ---
>   src/Makefile              |   1 +
>   src/vf/Makefile           |  56 ++++
>   src/vf/classifier_mac.c   | 233 ++++++++++++++
>   src/vf/classifier_mac.h   |  12 +
>   src/vf/ringlatencystats.c | 147 +++++++++
>   src/vf/ringlatencystats.h |  69 ++++
>   src/vf/spp_config.c       | 669 ++++++++++++++++++++++++++++++++++++++
>   src/vf/spp_config.h       |  90 ++++++
>   src/vf/spp_forward.c      | 106 +++++++
>   src/vf/spp_forward.h      |   9 +
>   src/vf/spp_vf.c           | 794 ++++++++++++++++++++++++++++++++++++++++++++++
>   src/vf/spp_vf.h           |  40 +++
>   12 files changed, 2226 insertions(+)
>   create mode 100644 src/vf/Makefile
>   create mode 100644 src/vf/classifier_mac.c
>   create mode 100644 src/vf/classifier_mac.h
>   create mode 100644 src/vf/ringlatencystats.c
>   create mode 100644 src/vf/ringlatencystats.h
>   create mode 100644 src/vf/spp_config.c
>   create mode 100644 src/vf/spp_config.h
>   create mode 100644 src/vf/spp_forward.c
>   create mode 100644 src/vf/spp_forward.h
>   create mode 100644 src/vf/spp_vf.c
>   create mode 100644 src/vf/spp_vf.h
> 
> diff --git a/src/Makefile b/src/Makefile
> index 6fd24b8..d2eb9b6 100644
> --- a/src/Makefile
> +++ b/src/Makefile
> @@ -41,5 +41,6 @@ include $(RTE_SDK)/mk/rte.vars.mk
>   DIRS-$(CONFIG_RTE_EXEC_ENV_LINUXAPP) += nfv
>   DIRS-$(CONFIG_RTE_EXEC_ENV_LINUXAPP) += primary
>   DIRS-$(CONFIG_RTE_EXEC_ENV_LINUXAPP) += vm
> +DIRS-$(CONFIG_RTE_EXEC_ENV_LINUXAPP) += vf
>   
>   include $(RTE_SDK)/mk/rte.extsubdir.mk
> diff --git a/src/vf/Makefile b/src/vf/Makefile
> new file mode 100644
> index 0000000..4961d2e
> --- /dev/null
> +++ b/src/vf/Makefile
> @@ -0,0 +1,56 @@
> +#   BSD LICENSE
> +#
> +#   Copyright(c) 2015-2016 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 overriden by command line or environment
> +include $(RTE_SDK)/mk/rte.vars.mk
> +
> +# binary name
> +APP = spp_vf
> +
> +# all source are stored in SRCS-y
> +SRCS-y := spp_vf.c spp_config.c classifier_mac.c spp_forward.c ringlatencystats.c ../shared/common.c
> +
> +CFLAGS += $(WERROR_FLAGS) -O3
> +CFLAGS += -I$(SRCDIR)/../shared
> +#CFLAGS += -DSPP_DEMONIZE
> +#CFLAGS += -DSPP_RINGLATENCYSTATS_ENABLE
> +
> +LDLIBS += -ljansson
> +ifeq ($(CONFIG_RTE_BUILD_SHARED_LIB),y)
> +LDLIBS += -lrte_pmd_ring
> +LDLIBS += -lrte_pmd_vhost
> +endif
> +
> +include $(RTE_SDK)/mk/rte.extapp.mk
> diff --git a/src/vf/classifier_mac.c b/src/vf/classifier_mac.c
> new file mode 100644
> index 0000000..da03905
> --- /dev/null
> +++ b/src/vf/classifier_mac.c
> @@ -0,0 +1,233 @@
> +#include <unistd.h>
> +#include <sys/types.h>
> +#include <stdio.h>
> +#include <stdint.h>
> +#include <stddef.h>
> +#include <math.h>
> +
> +#include <rte_mbuf.h>
> +#include <rte_log.h>
> +#include <rte_cycles.h>
> +#include <rte_malloc.h>
> +#include <rte_memcpy.h>
> +#include <rte_random.h>
> +#include <rte_byteorder.h>
> +#include <rte_per_lcore.h>
> +#include <rte_eal.h>
> +#include <rte_launch.h>
> +#include <rte_hash.h>
> +
> +#include "spp_vf.h"
> +#include "ringlatencystats.h"
> +#include "classifier_mac.h"
> +
> +#define RTE_LOGTYPE_SPP_CLASSIFIER_MAC RTE_LOGTYPE_USER1
> +
> +#ifdef RTE_MACHINE_CPUFLAG_SSE4_2
> +#include <rte_hash_crc.h>
> +#define DEFAULT_HASH_FUNC rte_hash_crc
> +#else
> +#include <rte_jhash.h>
> +#define DEFAULT_HASH_FUNC rte_jhash
> +#endif
> +
> +/* number of classifier mac table entry */
> +#define NUM_CLASSIFIER_MAC_TABLE_ENTRY 128
> +
> +/* interval that transmit burst packet, if buffer is not filled.
> +		nano second */
> +#define DRAIN_TX_PACKET_INTERVAL 100
> +
> +/* mac address string(xx:xx:xx:xx:xx:xx) buffer size */
> +static const size_t ETHER_ADDR_STR_BUF_SZ =
> +		ETHER_ADDR_LEN * 2 + (ETHER_ADDR_LEN - 1) + 1;
> +
> +/* classified data (destination port, target packets, etc) */
> +struct classified_data {
> +	int      if_no;
> +	uint8_t  tx_port;
> +	uint16_t num_pkt;
> +	struct rte_mbuf *pkts[MAX_PKT_BURST];
> +};
> +
> +/* initialize classifier. */
> +static int
> +init_classifier(const struct spp_core_info *core_info,
> +		struct rte_hash **classifier_mac_table, struct classified_data *classified_data)
> +{
> +	int ret = -1;
> +	int i;
> +	struct ether_addr eth_addr;
> +	char mac_addr_str[ETHER_ADDR_STR_BUF_SZ];
> +
> +	/* set hash creating parameters */
> +	struct rte_hash_parameters hash_params = {
> +			.name      = "classifier_mac_table",
> +			.entries   = NUM_CLASSIFIER_MAC_TABLE_ENTRY,
> +			.key_len   = sizeof(struct ether_addr),
> +			.hash_func = DEFAULT_HASH_FUNC,
> +			.hash_func_init_val = 0,
> +			.socket_id = rte_socket_id(),
> +	};
> +
> +#ifdef RTE_MACHINE_CPUFLAG_SSE4_2
> +	RTE_LOG(DEBUG, SPP_CLASSIFIER_MAC, "Enabled SSE4.2. use crc hash.\n");
> +#else
> +	RTE_LOG(DEBUG, SPP_CLASSIFIER_MAC, "Disabled SSE4.2. use jenkins hash.\n");
> +#endif
> +
> +	/* create classifier mac table (hash table) */
> +	*classifier_mac_table = rte_hash_create(&hash_params);
> +	if (unlikely(*classifier_mac_table == NULL)) {
> +		RTE_LOG(ERR, SPP_CLASSIFIER_MAC, "Cannot create classifier mac table\n");
> +		return -1;
> +	}
> +
> +	/* populate the hash */
> +	for (i = 0; i < core_info->num_tx_port; i++) {
> +		rte_memcpy(&eth_addr, &core_info->tx_ports[i].mac_addr, ETHER_ADDR_LEN);
> +
> +		/* add entry to classifier mac table */
> +		ret = rte_hash_add_key_data(*classifier_mac_table, (void*)&eth_addr, (void*)(long)i);
> +		if (unlikely(ret < 0)) {
> +			ether_format_addr(mac_addr_str, sizeof(mac_addr_str), &eth_addr);
> +			RTE_LOG(ERR, SPP_CLASSIFIER_MAC,
> +					"Cannot add entry to classifier mac table. "
> +					"ret=%d, mac_addr=%s\n", ret, mac_addr_str);
> +			rte_hash_free(*classifier_mac_table);
> +			*classifier_mac_table = NULL;
> +			return -1;
> +		}
> +
> +		/* set value */
> +		classified_data[i].if_no   = i;
> +		classified_data[i].tx_port = core_info->tx_ports[i].dpdk_port;
> +		classified_data[i].num_pkt = 0;
> +	}
> +
> +	return 0;
> +}
> +
> +/* transimit packet to one destination. */
> +static inline void
> +transimit_packet(struct classified_data *classified_data)
> +{
> +	int i;
> +	uint16_t n_tx;
> +
> +	/* set ringlatencystats */
> +	spp_ringlatencystats_add_time_stamp(classified_data->if_no,
> +			classified_data->pkts, classified_data->num_pkt);
> +
> +	/* transimit packets */
> +	n_tx = rte_eth_tx_burst(classified_data->tx_port, 0,
> +			classified_data->pkts, classified_data->num_pkt);
> +
> +	/* free cannnot transiit packets */
> +	if (unlikely(n_tx != classified_data->num_pkt)) {
> +		for (i = n_tx; i < classified_data->num_pkt; i++)
> +			rte_pktmbuf_free(classified_data->pkts[i]);
> +		RTE_LOG(DEBUG, SPP_CLASSIFIER_MAC,
> +				"drop packets(tx). num=%hu, dpdk_port=%hhu\n",
> +				classified_data->num_pkt - n_tx, classified_data->tx_port);
> +	}
> +
> +	classified_data->num_pkt = 0;
> +}
> +
> +/* classify packet by destination mac address,
> +		and transimit packet (conditional). */
> +static inline void
> +classify_packet(struct rte_mbuf **rx_pkts, uint16_t n_rx,
> +		struct rte_hash *classifier_mac_table, struct classified_data *classified_data)
> +{
> +	int ret;
> +	int i;
> +	struct ether_hdr *eth;
> +	struct classified_data *cd;
> +	void *lookup_data;
> +	char mac_addr_str[ETHER_ADDR_STR_BUF_SZ];
> +
> +	for (i = 0; i < n_rx; i++) {
> +		eth = rte_pktmbuf_mtod(rx_pkts[i], struct ether_hdr *);
> +
> +		/* find in table (by destination mac address)*/
> +		ret = rte_hash_lookup_data(classifier_mac_table,
> +				(const void*)&eth->d_addr, &lookup_data);
> +		if (unlikely(ret < 0)) {
> +			ether_format_addr(mac_addr_str, sizeof(mac_addr_str), &eth->d_addr);
> +			RTE_LOG(ERR, SPP_CLASSIFIER_MAC,
> +					"unknown mac address. ret=%d, mac_addr=%s\n", ret, mac_addr_str);
> +			rte_pktmbuf_free(rx_pkts[i]);
> +			continue;
> +		}
> +
> +		/* set mbuf pointer to tx buffer */
> +		cd = classified_data + (long)lookup_data;
> +		cd->pkts[cd->num_pkt++] = rx_pkts[i];
> +
> +		/* transimit packet, if buffer is filled */
> +		if (unlikely(cd->num_pkt == MAX_PKT_BURST))
> +			transimit_packet(cd);
> +	}
> +}
> +
> +/* classifier(mac address) thread function. */
> +int
> +spp_classifier_mac_do(void *arg)
> +{
> +	int ret = -1;
> +	int i;
> +	int n_rx;
> +	struct spp_core_info *core_info = (struct spp_core_info *)arg;
> +	struct rte_mbuf *rx_pkts[MAX_PKT_BURST];
> +
> +	struct rte_hash *classifier_mac_table = NULL;
> +	const int n_classified_data = core_info->num_tx_port;
> +	struct classified_data classified_data[n_classified_data];
> +
> +	uint64_t cur_tsc, prev_tsc = 0;
> +	const uint64_t drain_tsc = (rte_get_tsc_hz() + US_PER_S - 1) /
> +			US_PER_S * DRAIN_TX_PACKET_INTERVAL;
> +
> +	/* initialize */
> +	ret = init_classifier(core_info, &classifier_mac_table, classified_data);
> +	if (unlikely(ret != 0))
> +		return ret;
> +
> +	/* to idle  */
> +	core_info->status = SPP_CORE_IDLE;
> +	while(likely(core_info->status == SPP_CORE_IDLE) ||
> +			likely(core_info->status == SPP_CORE_FORWARD)) {
> +
> +		while(likely(core_info->status == SPP_CORE_FORWARD)) {
> +			/* drain tx packets, if buffer is not filled for interval */
> +			cur_tsc = rte_rdtsc();
> +			if (unlikely(cur_tsc - prev_tsc > drain_tsc)) {
> +				for (i = 0; i < n_classified_data; i++) {
> +					if (unlikely(classified_data[i].num_pkt != 0))
> +						transimit_packet(&classified_data[i]);
> +				}
> +				prev_tsc = cur_tsc;
> +			}
> +
> +			/* retrieve packets */
> +			n_rx = rte_eth_rx_burst(core_info->rx_ports[0].dpdk_port, 0,
> +					rx_pkts, MAX_PKT_BURST);
> +			if (unlikely(n_rx == 0))
> +				continue;
> +
> +			/* classify and transimit (filled) */
> +			classify_packet(rx_pkts, n_rx, classifier_mac_table, classified_data);
> +		}
> +	}
> +
> +	/* uninitialize */
> +	if (classifier_mac_table != NULL) {
> +		rte_hash_free(classifier_mac_table);
> +		classifier_mac_table = NULL;
> +	}
> +	core_info->status = SPP_CORE_STOP;
> +
> +	return 0;
> +}
> diff --git a/src/vf/classifier_mac.h b/src/vf/classifier_mac.h
> new file mode 100644
> index 0000000..2661206
> --- /dev/null
> +++ b/src/vf/classifier_mac.h
> @@ -0,0 +1,12 @@
> +#ifndef _CLASSIFIER_MAC_H_
> +#define _CLASSIFIER_MAC_H_
> +
> +/**
> + * classifier(mac address) thread function.
> + *
> + * @param arg
> + *  pointer to struct spp_core_info.
> + */
> +int spp_classifier_mac_do(void *arg);
> +
> +#endif /* _CLASSIFIER_MAC_H_ */
> diff --git a/src/vf/ringlatencystats.c b/src/vf/ringlatencystats.c
> new file mode 100644
> index 0000000..8f44020
> --- /dev/null
> +++ b/src/vf/ringlatencystats.c
> @@ -0,0 +1,147 @@
> +#include <unistd.h>
> +#include <sys/types.h>
> +#include <stdio.h>
> +#include <stddef.h>
> +#include <math.h>
> +
> +#include <rte_mbuf.h>
> +#include <rte_log.h>
> +#include <rte_cycles.h>
> +#include <rte_malloc.h>
> +#include <rte_memcpy.h>
> +
> +#include "ringlatencystats.h"
> +
> +#define NS_PER_SEC 1E9
> +
> +#define RTE_LOGTYPE_SPP_RING_LATENCY_STATS RTE_LOGTYPE_USER1
> +
> +#ifdef SPP_RINGLATENCYSTATS_ENABLE
> +
> +/** ring latency statistics information */
> +struct ring_latency_stats_info {
> +	uint64_t timer_tsc;   /**< sampling interval counter */
> +	uint64_t prev_tsc;    /**< previous time */
> +	struct spp_ringlatencystats_ring_latency_stats stats;  /**< ring latency statistics list */
> +};
> +
> +/** sampling interval */
> +static uint64_t g_samp_intvl = 0;
> +
> +/** ring latency statistics information instance */
> +static struct ring_latency_stats_info *g_stats_info = NULL;
> +
> +/** number of ring latency statisics */
> +static uint16_t g_stats_count = 0;
> +
> +/* clock cycles per nano second */
> +static inline uint64_t
> +cycles_per_ns(void)
> +{
> +	return rte_get_timer_hz() / NS_PER_SEC;
> +}
> +
> +int
> +spp_ringlatencystats_init(uint64_t samp_intvl, uint16_t stats_count)
> +{
> +	/* allocate memory for ring latency statisics infromation */
> +	g_stats_info = rte_zmalloc(
> +			"global ring_latency_stats_info",
> +			sizeof(struct ring_latency_stats_info) * stats_count, 0);
> +	if (unlikely(g_stats_info == NULL)) {
> +		RTE_LOG(ERR, SPP_RING_LATENCY_STATS,
> +				"Cannot allocate memory for ring latency stats info\n");
> +		return -1;
> +	}
> +
> +	/* store global information for ring latency statistics */
> +	g_samp_intvl = samp_intvl * cycles_per_ns();
> +	g_stats_count = stats_count;
> +
> +	RTE_LOG(DEBUG, SPP_RING_LATENCY_STATS,
> +			"g_samp_intvl=%lu, g_stats_count=%hu, cpns=%lu\n",
> +			g_samp_intvl, g_stats_count, cycles_per_ns());
> +
> +	return 0;
> +}
> +
> +void
> +spp_ringlatencystats_uninit(void)
> +{
> +	/* free memory for ring latency statisics infromation */
> +	if (likely(g_stats_info != NULL)) {
> +		rte_free(g_stats_info);
> +		g_stats_count = 0;
> +	}
> +}
> +
> +void
> +spp_ringlatencystats_add_time_stamp(int ring_id,
> +			struct rte_mbuf **pkts, uint16_t nb_pkts)
> +{
> +	unsigned int i;
> +	uint64_t diff_tsc, now;
> +	struct ring_latency_stats_info *stats_info = &g_stats_info[ring_id];
> +
> +	for (i = 0; i < nb_pkts; i++) {
> +
> +		/* get tsc now */
> +		now = rte_rdtsc();
> +
> +		/* calculate difference from the previous processing time */
> +		diff_tsc = now - stats_info->prev_tsc;
> +		stats_info->timer_tsc += diff_tsc;
> +
> +		/* when it is over sampling interval */
> +		/* set tsc to mbuf::timestamp */
> +		if (unlikely(stats_info->timer_tsc >= g_samp_intvl)) {
> +			pkts[i]->timestamp = now;
> +			stats_info->timer_tsc = 0;
> +		}
> +
> +		/* update previus tsc */
> +		stats_info->prev_tsc = now;
> +	}
> +}
> +
> +void
> +spp_ringlatencystats_calculate_latency(int ring_id,
> +			struct rte_mbuf **pkts, uint16_t nb_pkts)
> +{
> +	unsigned int i;
> +	uint64_t now;
> +	int64_t latency;
> +	struct ring_latency_stats_info *stats_info = &g_stats_info[ring_id];
> +
> +	now = rte_rdtsc();
> +	for (i = 0; i < nb_pkts; i++) {
> +		if (likely(pkts[i]->timestamp == 0))
> +			continue;
> +
> +		/* when mbuf::timestamp is not zero */
> +		/* calculate latency */
> +		latency = (uint64_t)floor((now - pkts[i]->timestamp) / cycles_per_ns());
> +		if (likely(latency < SPP_RINGLATENCYSTATS_STATS_SLOT_COUNT-1))
> +			stats_info->stats.slot[latency]++;
> +		else
> +			stats_info->stats.slot[SPP_RINGLATENCYSTATS_STATS_SLOT_COUNT-1]++;
> +	}
> +}
> +
> +int
> +spp_ringlatencystats_get_count(void)
> +{
> +	return g_stats_count;
> +}
> +
> +void
> +spp_ringlatencystats_get_stats(int ring_id,
> +		struct spp_ringlatencystats_ring_latency_stats *stats)
> +{
> +	struct ring_latency_stats_info *stats_info = &g_stats_info[ring_id];
> +
> +	rte_memcpy(stats, &stats_info->stats,
> +			sizeof(struct spp_ringlatencystats_ring_latency_stats));
> +}
> +
> +#endif /* SPP_RINGLATENCYSTATS_ENABLE */
> diff --git a/src/vf/ringlatencystats.h b/src/vf/ringlatencystats.h
> new file mode 100644
> index 0000000..bc47699
> --- /dev/null
> +++ b/src/vf/ringlatencystats.h
> @@ -0,0 +1,69 @@
> +#ifndef _RINGLATENCYSTATS_H_
> +#define _RINGLATENCYSTATS_H_
> +
> +#include <rte_mbuf.h>
> +
> +/** number of slots to save latency. 0ns~99ns and 100ns over */
> +#define SPP_RINGLATENCYSTATS_STATS_SLOT_COUNT 101
> +
> +/** ring latency statistics */
> +struct spp_ringlatencystats_ring_latency_stats {
> +	uint64_t slot[SPP_RINGLATENCYSTATS_STATS_SLOT_COUNT]; /**< slots to save latency */
> +};
> +
> +
> +#ifdef SPP_RINGLATENCYSTATS_ENABLE
> +/**
> + * initialize ring latency statisics.
> + *
> + * @retval 0: succeeded.
> + * @retval -1: failed.
> + */
> +int spp_ringlatencystats_init(uint64_t samp_intvl, uint16_t stats_count);
> +
> +/**
> + *uninitialize ring latency statisics.
> + */
> +void spp_ringlatencystats_uninit(void);
> +
> +/**
> + * add time-stamp to mbuf's member.
> + *
> + * call at enqueue.
> + */
> +void spp_ringlatencystats_add_time_stamp(int ring_id,
> +			struct rte_mbuf **pkts, uint16_t nb_pkts);
> +
> +/**
> + * calculate latency.
> + *
> + * call at dequeue.
> + */
> +void spp_ringlatencystats_calculate_latency(int ring_id,
> +			struct rte_mbuf **pkts, uint16_t nb_pkts);
> +
> +/**
> + * get number of ring latency statisics.
> + *
> + * @return spp_ringlatencystats_init's parameter "stats_count"
> + */
> +int spp_ringlatencystats_get_count(void);
> +
> +/**
> + *get specific ring latency statisics.
> + */
> +void spp_ringlatencystats_get_stats(int ring_id,
> +		struct spp_ringlatencystats_ring_latency_stats *stats);
> +
> +#else
> +
> +#define spp_ringlatencystats_init(arg1, arg2) 0
> +#define spp_ringlatencystats_uninit()
> +#define spp_ringlatencystats_add_time_stamp(arg1, arg2, arg3)
> +#define spp_ringlatencystats_calculate_latency(arg1, arg2, arg3)
> +#define spp_ringlatencystats_get_count() 0
> +#define spp_ringlatencystats_get_stats(arg1, arg2)
> +
> +#endif /* SPP_RINGLATENCYSTATS_ENABLE */
> +
> +#endif /* _RINGLATENCYSTATS_H_ */
> diff --git a/src/vf/spp_config.c b/src/vf/spp_config.c
> new file mode 100644
> index 0000000..63b85f2
> --- /dev/null
> +++ b/src/vf/spp_config.c
> @@ -0,0 +1,669 @@
> +#include <sys/types.h>
> +#include <jansson.h>
> +
> +#include <rte_log.h>
> +
> +#include "spp_config.h"
> +
> +#define CONFIG_CORE_TYPE_CLASSIFIER_MAC "classifier_mac"
> +#define CONFIG_CORE_TYPE_MERGE          "merge"
> +#define CONFIG_CORE_TYPE_FORWARD        "forward"
> +
> +#define JSONPATH_CLASSIFIER_TABLE "$.classifier_table"
> +#define JSONPATH_PROC_TABLE "$.vfs"
> +#define JSONPATH_NAME       "$.name"
> +#define JSONPATH_TABLE      "$.table"
> +#define JSONPATH_MAC        "$.mac"
> +#define JSONPATH_PORT       "$.port"
> +#define JSONPATH_NUM_VHOST  "$.num_vhost"
> +#define JSONPATH_NUM_RING   "$.num_ring"
> +#define JSONPATH_FUNCTIONS  "$.functions"
> +#define JSONPATH_CORE_NO    "$.core"
> +#define JSONPATH_CORE_TYPE  "$.type"
> +#define JSONPATH_RX_PORT    "$.rx_port"
> +#define JSONPATH_TX_PORT    "$.tx_port"
> +#define JSONPATH_TX_TABLE   "$.tx_port_table"
> +
> +/*
> + * Get integer data from config
> + */
> +static int
> +config_get_int_value(const json_t *obj, const char *path, int *value)
> +{
> +	/* 指定パラメータのJsonオブジェクト取得 */
> +	json_t *tmp_obj = json_path_get(obj, path);
> +	if (unlikely(tmp_obj == NULL)) {
> +		/* 必須でないデータを取得する場合を考慮し、DEBUGログとする。 */
> +		RTE_LOG(DEBUG, APP, "No parameter. (path = %s)\n", path);
> +		return -1;
> +	}
> +
> +	/* Integer type check */
> +	if (unlikely(!json_is_integer(tmp_obj))) {
> +		/* 必須でないデータを取得する場合を考慮し、DEBUGログとする。 */
> +		RTE_LOG(DEBUG, APP, "Not an integer. (path = %s)\n", path);
> +		return -1;
> +	}
> +
> +	/* Set to OUT parameter */
> +	*value = json_integer_value(tmp_obj);
> +	RTE_LOG(DEBUG, APP, "get value = %d\n", *value);
> +	return 0;
> +}
> +
> +/*
> + * Get String data from config
> + */
> +static int
> +config_get_str_value(const json_t *obj, const char *path, char *value)
> +{
> +	/* 指定パラメータのJsonオブジェクト取得 */
> +	json_t *tmp_obj = json_path_get(obj, path);
> +	if (unlikely(tmp_obj == NULL)) {
> +		RTE_LOG(DEBUG, APP, "No parameter. (path = %s)\n", path);
> +		return -1;
> +	}
> +
> +	/* String type check */
> +	if (unlikely(!json_is_string(tmp_obj))) {
> +		RTE_LOG(DEBUG, APP, "Not a string. (path = %s)\n", path);
> +		return -1;
> +	}
> +
> +	/* Set to OUT parameter */
> +	strcpy(value, json_string_value(tmp_obj));
> +	RTE_LOG(DEBUG, APP, "get value = %s\n", value);
> +	return 0;
> +}
> +
> +/*
> + * コンフィグ情報初期化
> + */
> +static void
> +config_init_data(struct spp_config_area *config)
> +{
> +	/* 0クリア */
> +	memset(config, 0x00, sizeof(struct spp_config_area));
> +	int core_cnt, port_cnt, table_cnt;
> +
> +	/* IF種別初期設定 */
> +	for (core_cnt = 0; core_cnt < SPP_CONFIG_CORE_MAX; core_cnt++) {
> +		for (port_cnt = 0; port_cnt < RTE_MAX_ETHPORTS; port_cnt++) {
> +			config->proc.functions[core_cnt].rx_ports[port_cnt].if_type = UNDEF;
> +			config->proc.functions[core_cnt].tx_ports[port_cnt].if_type = UNDEF;
> +		}
> +	}
> +	for (table_cnt = 0; table_cnt < SPP_CONFIG_MAC_TABLE_MAX; table_cnt++) {
> +		config->classifier_table.mac_tables[table_cnt].port.if_type = UNDEF;
> +	}
> +
> +	return;
> +}
> +
> +/*
> + * IFの情報からIF種別とIF番号を取得する
> + * ("ring0" -> 種別:"ring"、番号:0)
> + */
> +static int
> +config_get_if_info(const char *port, enum port_type *if_type, int *if_no)
> +{
> +	enum port_type type = UNDEF;
> +	const char *no_str = NULL;
> +	char *endptr = NULL;
> +
> +	/* IF type check */
> +	if (strncmp(port, SPP_CONFIG_IFTYPE_NIC, strlen(SPP_CONFIG_IFTYPE_NIC)) == 0) {
> +		/* NIC */
> +		type = PHY;
> +		no_str = &port[strlen(SPP_CONFIG_IFTYPE_NIC)];
> +	} else if (strncmp(port, SPP_CONFIG_IFTYPE_VHOST, strlen(SPP_CONFIG_IFTYPE_VHOST)) == 0) {
> +		/* VHOST */
> +		type = VHOST;
> +		no_str = &port[strlen(SPP_CONFIG_IFTYPE_VHOST)];
> +	} else if (strncmp(port, SPP_CONFIG_IFTYPE_RING, strlen(SPP_CONFIG_IFTYPE_RING)) == 0) {
> +		/* RING */
> +		type = RING;
> +		no_str = &port[strlen(SPP_CONFIG_IFTYPE_RING)];
> +	} else {
> +		/* OTHER */
> +		RTE_LOG(ERR, APP, "Unknown interface type. (port = %s)\n", port);
> +		return -1;
> +	}
> +
> +	/* IF番号を文字列から数値変換 */
> +	int ret_no = strtol(no_str, &endptr, 0);
> +	if (unlikely(no_str == endptr) || unlikely(*endptr != '\0')) {
> +		/* No IF number */
> +		RTE_LOG(ERR, APP, "No interface number. (port = %s)\n", port);
> +		return -1;
> +	}
> +
> +	/* Set OUT parameter */
> +	*if_type = type;
> +	*if_no = ret_no;
> +
> +	RTE_LOG(DEBUG, APP, "Port = %s => Type = %d No = %d\n",
> +			port, *if_type, *if_no);
> +	return 0;
> +}
> +
> +/*
> + * MAC addressを文字列から数値へ変換
> + */
> +int64_t
> +config_change_mac_str_to_int64(const char *mac)
> +{
> +	int64_t ret_mac = 0;
> +	int64_t token_val = 0;
> +	int token_cnt = 0;
> +	char tmp_mac[SPP_CONFIG_STR_LEN];
> +	char *str = tmp_mac;
> +	char *saveptr = NULL;
> +	char *endptr = NULL;
> +
> +	RTE_LOG(DEBUG, APP, "MAC address change. (mac = %s)\n", mac);
> +
> +	strcpy(tmp_mac, mac);
> +	while(1) {
> +		/* Split by clolon(':') */
> +		char *ret_tok = strtok_r(str, ":", &saveptr);
> +		if (unlikely(ret_tok == NULL)) {
> +			break;
> +		}
> +
> +		/* Convert string to hex value */
> +		int ret_tol = strtol(ret_tok, &endptr, 16);
> +		if (unlikely(ret_tok == endptr) || unlikely(*endptr != '\0')) {
> +			break;
> +		}
> +
> +		/* 各数値をまとめる */
> +		token_val = (int64_t)ret_tol;
> +		ret_mac |= token_val << (token_cnt * 8);
> +		token_cnt++;
> +		str = NULL;
> +	}
> +
> +	/* 区切り文字が5個以外 */
> +	if (unlikely(token_cnt != ETHER_ADDR_LEN)) {
> +		RTE_LOG(ERR, APP, "MAC address format error. (mac = %s)\n",
> +				 mac);
> +		return -1;
> +	}
> +
> +	RTE_LOG(DEBUG, APP, "MAC address change. (mac = %s => 0x%08lx)\n",
> +			 mac, ret_mac);
> +	return ret_mac;
> +}
> +
> +/*
> + * Classifier table読み込み
> + */
> +static int
> +config_load_classifier_table(const json_t *obj,
> +		struct spp_config_classifier_table *classifier_table)
> +{
> +	/* classifier_table用オブジェクト取得 */
> +	json_t *classifier_obj = json_path_get(obj, JSONPATH_CLASSIFIER_TABLE);
> +	if (unlikely(classifier_obj == NULL)) {
> +		RTE_LOG(ERR, APP, "Json object get failed. (path = %s)\n",
> +				JSONPATH_CLASSIFIER_TABLE);
> +		return -1;
> +	}
> +
> +	/* name取得 */
> +	int ret_name = config_get_str_value(classifier_obj, JSONPATH_NAME,
> +			classifier_table->name);
> +	if (unlikely(ret_name != 0)) {
> +		RTE_LOG(ERR, APP, "Classifier table name get failed.\n");
> +		return -1;
> +	}
> +
> +	/* table用オブジェクト取得 */
> +	json_t *array_obj = json_path_get(classifier_obj, JSONPATH_TABLE);
> +	if (unlikely(!array_obj)) {
> +		RTE_LOG(ERR, APP, "Json object get failed. (path = %s)\n",
> +				JSONPATH_TABLE);
> +		return -1;
> +	}
> +
> +	/* table用オブジェクトが配列かチェック */
> +	if (unlikely(!json_is_array(array_obj))) {
> +		RTE_LOG(ERR, APP, "Not an array. (path = %s)\n",
> +				JSONPATH_TABLE);
> +		return -1;
> +	}
> +
> +	/* table用オブジェクトの要素数取得 */
> +	int array_num = json_array_size(array_obj);
> +	if (unlikely(array_num <= 0) ||
> +			unlikely(array_num >= SPP_CONFIG_MAC_TABLE_MAX)) {
> +		RTE_LOG(ERR, APP, "Table size out of range. (path = %s, size = %d)\n",
> +				JSONPATH_TABLE, array_num);
> +		return -1;
> +	}
> +	classifier_table->num_table = array_num;
> +
> +	/* テーブルの各要素毎にデータ取得 */
> +	struct spp_config_mac_table_element *tmp_table = NULL;
> +	char if_str[SPP_CONFIG_STR_LEN];
> +	int table_cnt = 0;
> +	for (table_cnt = 0; table_cnt < array_num; table_cnt++) {
> +		tmp_table = &classifier_table->mac_tables[table_cnt];
> +
> +		/* 要素取得 */
> +		json_t *elements_obj = json_array_get(array_obj, table_cnt);
> +		if (unlikely(elements_obj == NULL)) {
> +			RTE_LOG(ERR, APP,
> +				"Element get failed. (No = %d, path = %s)\n",
> +				table_cnt, JSONPATH_TABLE);
> +			return -1;
> +		}
> +
> +		/* MACアドレス(文字列)取得 */
> +		int ret_mac = config_get_str_value(elements_obj, JSONPATH_MAC,
> +				tmp_table->mac_addr_str);
> +		if (unlikely(ret_mac != 0)) {
> +			RTE_LOG(ERR, APP,
> +				"MAC address get failed. (No = %d, path = %s)\n",
> +				table_cnt, JSONPATH_MAC);
> +			return -1;
> +		}
> +
> +		/* MACアドレス数値変換 */
> +		int64_t ret_mac64 = config_change_mac_str_to_int64(
> +				tmp_table->mac_addr_str);
> +		if (unlikely(ret_mac64 == -1)) {
> +			RTE_LOG(ERR, APP,
> +				"MAC address change failed. (No = %d, mac = %s)\n",
> +				table_cnt, tmp_table->mac_addr_str);
> +			return -1;
> +		}
> +		tmp_table->mac_addr = ret_mac64;
> +
> +		/* IF情報取得 */
> +		int ret_if_str = config_get_str_value(elements_obj,
> +				JSONPATH_PORT, if_str);
> +		if (unlikely(ret_if_str != 0)) {
> +			RTE_LOG(ERR, APP,
> +				"Interface get failed. (No = %d, path = %s)\n",
> +				table_cnt, JSONPATH_PORT);
> +			return -1;
> +		}
> +
> +		/* IF種別とIF番号に分割 */
> +		int ret_if = config_get_if_info(if_str, &tmp_table->port.if_type,
> +				&tmp_table->port.if_no);
> +		if (unlikely(ret_if != 0)) {
> +			RTE_LOG(ERR, APP,
> +				"Interface change failed. (No = %d, IF = %s)\n",
> +				table_cnt, if_str);
> +			return -1;
> +		}
> +	}
> +
> +	return 0;
> +}
> +
> +/*
> + * 処理種別を文字列から数値変換
> + */
> +static enum spp_core_type
> +config_change_core_type(const char *core_type)
> +{
> +	if(strncmp(core_type, CONFIG_CORE_TYPE_CLASSIFIER_MAC,
> +			 strlen(CONFIG_CORE_TYPE_CLASSIFIER_MAC)+1) == 0) {
> +		/* Classifier */
> +		return SPP_CONFIG_CLASSIFIER_MAC;
> +	} else if (strncmp(core_type, CONFIG_CORE_TYPE_MERGE,
> +			 strlen(CONFIG_CORE_TYPE_MERGE)+1) == 0) {
> +		/* Merge */
> +		return SPP_CONFIG_MERGE;
> +	} else if (strncmp(core_type, CONFIG_CORE_TYPE_FORWARD,
> +			 strlen(CONFIG_CORE_TYPE_FORWARD)+1) == 0) {
> +		/* Forward */
> +		return SPP_CONFIG_FORWARD;
> +	}
> +	return SPP_CONFIG_UNUSE;
> +}
> +
> +/*
> + * 受信ポート取得
> + */
> +static int
> +config_set_rx_port(enum spp_core_type type, json_t *obj,
> +		struct spp_config_functions *functions)
> +{
> +	struct spp_config_port_info *tmp_rx_port = NULL;
> +	char if_str[SPP_CONFIG_STR_LEN];
> +	if (type == SPP_CONFIG_MERGE) {
> +		/* Merge */
> +		/* 受信ポート用オブジェクト取得 */
> +		json_t *array_obj = json_path_get(obj, JSONPATH_RX_PORT);
> +		if (unlikely(!array_obj)) {
> +			RTE_LOG(ERR, APP, "Json object get failed. (path = %s, route = merge)\n",
> +				JSONPATH_RX_PORT);
> +			return -1;
> +		}
> +
> +		/* 受信ポート用オブジェクトが配列かチェック */
> +		if (unlikely(!json_is_array(array_obj))) {
> +			RTE_LOG(ERR, APP, "Not an array. (path = %s, route = merge)\n",
> +				JSONPATH_TABLE);
> +			return -1;
> +		}
> +
> +		/* 受信ポート用オブジェクトの要素数取得 */
> +		int port_num = json_array_size(array_obj);
> +		if (unlikely(port_num <= 0) ||
> +				unlikely(port_num >= RTE_MAX_ETHPORTS)) {
> +			RTE_LOG(ERR, APP, "RX port out of range. (path = %s, port = %d, route = merge)\n",
> +					JSONPATH_RX_PORT, port_num);
> +			return -1;
> +		}
> +		functions->num_rx_port = port_num;
> +
> +		/* 要素毎にデータ取得 */
> +		int array_cnt = 0;
> +		for (array_cnt = 0; array_cnt < port_num; array_cnt++) {
> +			tmp_rx_port = &functions->rx_ports[array_cnt];
> +
> +			/* 要素取得 */
> +			json_t *elements_obj = json_array_get(array_obj, array_cnt);
> +			if (unlikely(elements_obj == NULL)) {
> +				RTE_LOG(ERR, APP,
> +					"Element get failed. (No = %d, path = %s, route = merge)\n",
> +					array_cnt, JSONPATH_RX_PORT);
> +				return -1;
> +			}
> +
> +			/* String type check */
> +			if (unlikely(!json_is_string(elements_obj))) {
> +				RTE_LOG(ERR, APP, "Not a string. (path = %s, No = %d, route = merge)\n",
> +						JSONPATH_RX_PORT, array_cnt);
> +				return -1;
> +			}
> +			strcpy(if_str, json_string_value(elements_obj));
> +
> +			/* IF種別とIF番号に分割 */
> +			int ret_if = config_get_if_info(if_str, &tmp_rx_port->if_type,
> +					&tmp_rx_port->if_no);
> +			if (unlikely(ret_if != 0)) {
> +				RTE_LOG(ERR, APP,
> +					"Interface change failed. (No = %d, port = %s, route = merge)\n",
> +					array_cnt, if_str);
> +				return -1;
> +			}
> +		}
> +	} else {
> +		/* Classifier/Forward */
> +		tmp_rx_port = &functions->rx_ports[0];
> +		functions->num_rx_port = 1;
> +
> +		/* 受信ポート取得 */
> +		int ret_rx_port = config_get_str_value(obj, JSONPATH_RX_PORT, if_str);
> +		if (unlikely(ret_rx_port != 0)) {
> +			RTE_LOG(ERR, APP, "RX port get failed.\n");
> +			return -1;
> +		}
> +
> +		/* IF種別とIF番号に分割 */
> +		int ret_if = config_get_if_info(if_str, &tmp_rx_port->if_type,
> +				&tmp_rx_port->if_no);
> +		if (unlikely(ret_if != 0)) {
> +			RTE_LOG(ERR, APP,
> +				"Interface change failed. (port = %s)\n", if_str);
> +			return -1;
> +		}
> +	}
> +
> +	return 0;
> +}
> +
> +/*
> + * 送信先ポート情報取得
> + */
> +static int
> +config_set_tx_port(enum spp_core_type type, json_t *obj,
> +		struct spp_config_functions *functions,
> +		struct spp_config_classifier_table *classifier_table)
> +{
> +	struct spp_config_port_info *tmp_tx_port = NULL;
> +	char if_str[SPP_CONFIG_STR_LEN];
> +	if ((type == SPP_CONFIG_MERGE) || (type == SPP_CONFIG_FORWARD)) {
> +		/* Merge or Forward */
> +		tmp_tx_port = &functions->tx_ports[0];
> +		functions->num_tx_port = 1;
> +
> +		/* 送信ポート取得 */
> +		int ret_tx_port = config_get_str_value(obj,
> +				JSONPATH_TX_PORT, if_str);
> +		if (unlikely(ret_tx_port != 0)) {
> +			RTE_LOG(ERR, APP, "TX port get failed.\n");
> +			return -1;
> +		}
> +
> +		/* IF種別とIF番号に分割 */
> +		int ret_if = config_get_if_info(if_str, &tmp_tx_port->if_type,
> +				&tmp_tx_port->if_no);
> +		if (unlikely(ret_if != 0)) {
> +			RTE_LOG(ERR, APP,
> +				"Interface change failed. (port = %s)\n",
> +				if_str);
> +			return -1;
> +		}
> +	} else {
> +		/* Classifier */
> +		int cnt = 0;
> +		functions->num_tx_port = classifier_table->num_table;
> +		struct spp_config_mac_table_element *tmp_mac_table = NULL;
> +		for (cnt = 0; cnt < classifier_table->num_table; cnt++) {
> +			tmp_tx_port = &functions->tx_ports[cnt];
> +			tmp_mac_table = &classifier_table->mac_tables[cnt];
> +
> +			/* MAC振り分けテーブルより設定 */
> +			tmp_tx_port->if_type = tmp_mac_table->port.if_type;
> +			tmp_tx_port->if_no   = tmp_mac_table->port.if_no;
> +		}
> +	}
> +
> +	return 0;
> +}
> +
> +/*
> + * プロセス情報取得
> + */
> +static int
> +config_load_proc_info(const json_t *obj, int node_id, struct spp_config_area *config)
> +{
> +	struct spp_config_proc_info *proc = &config->proc;
> +	struct spp_config_classifier_table *classifier_table = &config->classifier_table;
> +
> +	/* proc_table用オブジェクト取得 */
> +	json_t *proc_table_obj = json_path_get(obj, JSONPATH_PROC_TABLE);
> +	if (unlikely(proc_table_obj == NULL)) {
> +		RTE_LOG(ERR, APP, "Json object get failed. (path = %s)\n",
> +				JSONPATH_PROC_TABLE);
> +		return -1;
> +	}
> +
> +	/* table用オブジェクトが配列かチェック */
> +	if (unlikely(!json_is_array(proc_table_obj))) {
> +		RTE_LOG(ERR, APP, "Not an array. (path = %s)\n",
> +				JSONPATH_TABLE);
> +		return -1;
> +	}
> +
> +	/* table用オブジェクトの要素数取得 */
> +	int proc_table_num = json_array_size(proc_table_obj);
> +	if (unlikely(proc_table_num < node_id)) {
> +		RTE_LOG(ERR, APP, "No process data. (Size = %d, Node = %d)\n",
> +			proc_table_num, node_id);
> +		return -1;
> +	}
> +
> +	/* 要素取得 */
> +	json_t *proc_obj = json_array_get(proc_table_obj, node_id);
> +	if (unlikely(proc_obj == NULL)) {
> +		RTE_LOG(ERR, APP, "Process data get failed. (Node = %d)\n",
> +				node_id);
> +		return -1;
> +	}
> +
> +	/* name取得 */
> +	int ret_name = config_get_str_value(proc_obj, JSONPATH_NAME, proc->name);
> +	if (unlikely(ret_name != 0)) {
> +		RTE_LOG(ERR, APP, "Process name get failed.\n");
> +		return -1;
> +	}
> +
> +	/* VHOST数取得 */
> +	int ret_vhost = config_get_int_value(proc_obj, JSONPATH_NUM_VHOST,
> +			&proc->num_vhost);
> +	if (unlikely(ret_vhost != 0)) {
> +		RTE_LOG(ERR, APP, "VHOST number get failed.\n");
> +		return -1;
> +	}
> +
> +	/* RING数取得 */
> +	int ret_ring = config_get_int_value(proc_obj, JSONPATH_NUM_RING,
> +			&proc->num_ring);
> +	if (unlikely(ret_ring != 0)) {
> +		RTE_LOG(ERR, APP, "RING number get failed.\n");
> +		return -1;
> +	}
> +
> +	/* functions用オブジェクト取得 */
> +	json_t *array_obj = json_path_get(proc_obj, JSONPATH_FUNCTIONS);
> +	if (unlikely(!array_obj)) {
> +		RTE_LOG(ERR, APP, "Json object get failed. (path = %s)\n",
> +				JSONPATH_FUNCTIONS);
> +		return -1;
> +	}
> +
> +	/* functions用オブジェクトが配列かチェック */
> +	if (unlikely(!json_is_array(array_obj))) {
> +		RTE_LOG(ERR, APP, "Not an array. (path = %s)\n",
> +				JSONPATH_FUNCTIONS);
> +		return -1;
> +	}
> +
> +	/* functions用オブジェクトの要素数取得 */
> +	int array_num = json_array_size(array_obj);
> +	if (unlikely(array_num <= 0) ||
> +			unlikely(array_num >= SPP_CONFIG_CORE_MAX)) {
> +		RTE_LOG(ERR, APP, "Functions size out of range. (path = %s, size = %d)\n",
> +				JSONPATH_TABLE, array_num);
> +		return -1;
> +	}
> +	proc->num_func = array_num;
> +
> +	/* 要素毎にデータ取得 */
> +	struct spp_config_functions *tmp_functions = NULL;
> +	char core_type_str[SPP_CONFIG_STR_LEN];
> +	int array_cnt = 0;
> +	for (array_cnt = 0; array_cnt < array_num; array_cnt++) {
> +		tmp_functions = &proc->functions[array_cnt];
> +
> +		/* 要素取得 */
> +		json_t *elements_obj = json_array_get(array_obj, array_cnt);
> +		if (unlikely(elements_obj == NULL)) {
> +			RTE_LOG(ERR, APP,
> +				"Element get failed. (No = %d, path = %s)\n",
> +				array_cnt, JSONPATH_FUNCTIONS);
> +			return -1;
> +		}
> +
> +		/* CORE番号取得 */
> +		int ret_core = config_get_int_value(elements_obj, JSONPATH_CORE_NO,
> +				&tmp_functions->core_no);
> +		if (unlikely(ret_core != 0)) {
> +			RTE_LOG(ERR, APP, "Core number get failed. (No = %d)\n",
> +					array_cnt);
> +			return -1;
> +		}
> +
> +		/* 処理種別取得 */
> +		int ret_core_type = config_get_str_value(elements_obj,
> +				 JSONPATH_CORE_TYPE, core_type_str);
> +		if (unlikely(ret_core_type != 0)) {
> +			RTE_LOG(ERR, APP, "Core type get failed. (No = %d)\n",
> +					array_cnt);
> +			return -1;
> +		}
> +
> +		/* 処理種別を数値に変換 */
> +		enum spp_core_type core_type = config_change_core_type(core_type_str);
> +		if (unlikely(core_type == SPP_CONFIG_UNUSE)) {
> +			RTE_LOG(ERR, APP,
> +				"Unknown core type. (No = %d, type = %s)\n",
> +				array_cnt, core_type_str);
> +			return -1;
> +		}
> +		tmp_functions->type = core_type;
> +
> +		/* 受信ポート取得 */
> +		int ret_rx_port = config_set_rx_port(core_type, elements_obj,
> +				tmp_functions);
> +		if (unlikely(ret_rx_port != 0)) {
> +			RTE_LOG(ERR, APP, "RX port set failure. (No = %d)\n",
> +					array_cnt);
> +			return -1;
> +		}
> +
> +		/* 送信ポート取得 */
> +		int ret_tx_port = config_set_tx_port(core_type, elements_obj,
> +				tmp_functions, classifier_table);
> +		if (unlikely(ret_tx_port != 0)) {
> +			RTE_LOG(ERR, APP, "TX port set failure. (No = %d)\n",
> +					array_cnt);
> +			return -1;
> +		}
> +	}
> +
> +	return 0;
> +}
> +
> +/*
> + * Load config file
> + * OK : 0
> + * NG : -1
> + */
> +int
> +spp_config_load_file(int node_id, struct spp_config_area *config)
> +{
> +	/* Config initialize */
> +	config_init_data(config);
> +	
> +	/* Config load */
> +	json_error_t json_error;
> +	json_t *conf_obj = json_load_file(SPP_CONFIG_FILE_PATH, 0, &json_error);
> +	if (unlikely(conf_obj == NULL)) {
> +		/* Load error */
> +		RTE_LOG(ERR, APP, "Config load failed. (path = %s, text = %s)\n",
> +				 SPP_CONFIG_FILE_PATH, json_error.text);
> +		return -1;
> +	}
> +
> +	/* classifier table */
> +	int ret_classifier = config_load_classifier_table(conf_obj,
> +			&config->classifier_table);
> +	if (unlikely(ret_classifier != 0)) {
> +		RTE_LOG(ERR, APP, "Classifier table load failed.\n");
> +		json_decref(conf_obj);
> +		return -1;
> +	}
> +
> +	/* proc info */
> +	int ret_proc = config_load_proc_info(conf_obj, node_id, config);
> +	if (unlikely(ret_proc != 0)) {
> +		RTE_LOG(ERR, APP, "Process table load failed.\n");
> +		json_decref(conf_obj);
> +		return -1;
> +	}
> +
> +	/* Config object release */
> +	json_decref(conf_obj);
> +
> +	return 0;
> +}
> diff --git a/src/vf/spp_config.h b/src/vf/spp_config.h
> new file mode 100644
> index 0000000..d2a6a4b
> --- /dev/null
> +++ b/src/vf/spp_config.h
> @@ -0,0 +1,90 @@
> +#ifndef __SPP_CONFIG_H__
> +#define __SPP_CONFIG_H__
> +
> +#include "common.h"
> +
> +#define SPP_CONFIG_FILE_PATH "/usr/local/etc/spp/spp.json"
> +
> +#define SPP_CONFIG_IFTYPE_NIC   "nic"
> +#define SPP_CONFIG_IFTYPE_VHOST "vhost"
> +#define SPP_CONFIG_IFTYPE_RING  "ring"
> +
> +#define SPP_CONFIG_STR_LEN 32
> +#define SPP_CONFIG_MAC_TABLE_MAX 16
> +#define SPP_CONFIG_CORE_MAX 64
> +
> +/*
> + * Process type for each CORE
> + */
> +enum spp_core_type {
> +	SPP_CONFIG_UNUSE,
> +	SPP_CONFIG_CLASSIFIER_MAC,
> +	SPP_CONFIG_MERGE,
> +	SPP_CONFIG_FORWARD,
> +};
> +
> +/*
> + * Interface information structure
> + */
> +struct spp_config_port_info {
> +	enum port_type	if_type;
> +	int		if_no;
> +};
> +
> +/*
> + * MAC Table information structure
> + */
> +struct spp_config_mac_table_element {
> +	struct		spp_config_port_info port;
> +	char		mac_addr_str[SPP_CONFIG_STR_LEN];
> +	uint64_t	mac_addr;
> +};
> +
> +/*
> + * Classifier Table information structure
> + */
> +struct spp_config_classifier_table {
> +	char	name[SPP_CONFIG_STR_LEN];
> +	int	num_table;
> +	struct spp_config_mac_table_element mac_tables[SPP_CONFIG_MAC_TABLE_MAX];
> +};
> +
> +/*
> + * Functions information structure
> + */
> +struct spp_config_functions {
> +	int	core_no;
> +	enum	spp_core_type type;
> +	int	num_rx_port;
> +	int	num_tx_port;
> +	struct spp_config_port_info rx_ports[RTE_MAX_ETHPORTS];
> +	struct spp_config_port_info tx_ports[RTE_MAX_ETHPORTS];
> +};
> +
> +/*
> + * Process information structure
> + */
> +struct spp_config_proc_info {
> +	char	name[SPP_CONFIG_STR_LEN];
> +	int	num_vhost;
> +	int	num_ring;
> +	int	num_func;
> +	struct spp_config_functions functions[SPP_CONFIG_CORE_MAX];
> +};
> +
> +/*
> + * Config information structure
> + */
> +struct spp_config_area {
> +	struct spp_config_proc_info proc;
> +	struct spp_config_classifier_table classifier_table;
> +};
> +
> +/*
> + * Load config file
> + * OK : 0
> + * NG : -1
> + */
> +int spp_config_load_file(int node_id, struct spp_config_area *config);
> +
> +#endif /* __SPP_CONFIG_H__ */
> diff --git a/src/vf/spp_forward.c b/src/vf/spp_forward.c
> new file mode 100644
> index 0000000..4396929
> --- /dev/null
> +++ b/src/vf/spp_forward.c
> @@ -0,0 +1,106 @@
> +#include "spp_vf.h"
> +#include "ringlatencystats.h"
> +
> +#define RTE_LOGTYPE_SPP_FORWARD RTE_LOGTYPE_USER1
> +
> +/*
> + * 送受信ポートの経路情報
> + */
> +struct rxtx {
> +	struct spp_core_port_info rx;
> +	struct spp_core_port_info tx;
> +};
> +
> +/*
> + * 使用するIF情報を移し替える
> + */
> +void
> +set_use_interface(struct spp_core_port_info *dst,
> +		struct spp_core_port_info *src)
> +{
> +	dst->if_type   = src->if_type;
> +	dst->if_no     = src->if_no;
> +	dst->dpdk_port = src->dpdk_port;
> +}
> +
> +/*
> + * Merge/Forward
> + */
> +int
> +spp_forward(void *arg)
> +{
> +	unsigned int lcore_id = rte_lcore_id();
> +	struct spp_core_info *core_info = (struct spp_core_info *)arg;
> +	int if_cnt, rxtx_num = 0;
> +	struct rxtx patch[RTE_MAX_ETHPORTS];
> +
> +	/* RX/TX Info setting */
> +	rxtx_num = core_info->num_rx_port;
> +	for (if_cnt = 0; if_cnt < rxtx_num; if_cnt++) {
> +		set_use_interface(&patch[if_cnt].rx,
> +				&core_info->rx_ports[if_cnt]);
> +		if (core_info->type == SPP_CONFIG_FORWARD) {
> +			/* FORWARD */
> +			set_use_interface(&patch[if_cnt].tx,
> +					&core_info->tx_ports[if_cnt]);
> +		} else {
> +			/* MERGE */
> +			set_use_interface(&patch[if_cnt].tx,
> +					&core_info->tx_ports[0]);
> +		}
> +	}
> +
> +	/* Thread IDLE */
> +	core_info->status = SPP_CORE_IDLE;
> +	RTE_LOG(INFO, FORWARD, "Core[%d] Start. (type = %d)\n", lcore_id,
> +			core_info->type);
> +
> +	int cnt, nb_rx, nb_tx, buf;
> +	struct spp_core_port_info *rx;
> +	struct spp_core_port_info *tx;
> +	struct rte_mbuf *bufs[MAX_PKT_BURST];
> +	while (likely(core_info->status == SPP_CORE_IDLE) ||
> +			likely(core_info->status == SPP_CORE_FORWARD)) {
> +		while (likely(core_info->status == SPP_CORE_FORWARD)) {
> +			for (cnt = 0; cnt < rxtx_num; cnt++) {
> +				rx = &patch[cnt].rx;
> +				tx = &patch[cnt].tx;
> +
> +				/* Packet receive */
> +				nb_rx = rte_eth_rx_burst(rx->dpdk_port, 0, bufs, MAX_PKT_BURST);
> +				if (unlikely(nb_rx == 0)) {
> +					continue;
> +				}
> +
> +#ifdef SPP_RINGLATENCYSTATS_ENABLE /* RING滞留時間 */
> +				if (rx->if_type == RING) {
> +					/* Receive port is RING */
> +					spp_ringlatencystats_calculate_latency(rx->if_no,
> +							bufs, nb_rx);
> +				}
> +				if (tx->if_type == RING) {
> +					/* Send port is RING */
> +					spp_ringlatencystats_add_time_stamp(tx->if_no,
> +							bufs, nb_rx);
> +				}
> +#endif /* SPP_RINGLATENCYSTATS_ENABLE */
> +
> +				/* Send packet */
> +				nb_tx = rte_eth_tx_burst(tx->dpdk_port, 0, bufs, nb_rx);
> +
> +				/* Free any unsent packets. */
> +				if (unlikely(nb_tx < nb_rx)) {
> +					for (buf = nb_tx; buf < nb_rx; buf++) {
> +						rte_pktmbuf_free(bufs[buf]);
> +					}
> +				}
> +			}
> +		}
> +	}
> +
> +	/* Thread STOP */
> +	RTE_LOG(INFO, FORWARD, "Core[%d] End. (type = %d)\n", lcore_id,
> +			core_info->type);
> +	core_info->status = SPP_CORE_STOP;
> +	return 0;
> +}
> diff --git a/src/vf/spp_forward.h b/src/vf/spp_forward.h
> new file mode 100644
> index 0000000..33208bf
> --- /dev/null
> +++ b/src/vf/spp_forward.h
> @@ -0,0 +1,9 @@
> +#ifndef __SPP_FORWARD_H__
> +#define __SPP_FORWARD_H__
> +
> +/*
> + * Merge/Forward
> + */
> +int spp_forward(void *arg);
> +
> +#endif /* __SPP_FORWARD_H__ */
> diff --git a/src/vf/spp_vf.c b/src/vf/spp_vf.c
> new file mode 100644
> index 0000000..ee5cf63
> --- /dev/null
> +++ b/src/vf/spp_vf.c
> @@ -0,0 +1,794 @@
> +#include <arpa/inet.h>
> +#include <getopt.h>
> +
> +#include <rte_eth_ring.h>
> +#include <rte_eth_vhost.h>
> +#include <rte_memzone.h>
> +
> +#include "spp_vf.h"
> +#include "ringlatencystats.h"
> +#include "classifier_mac.h"
> +#include "spp_forward.h"
> +
> +/* define */
> +#define SPP_CORE_STATUS_CHECK_MAX 5
> +#define SPP_RING_LATENCY_STATS_SAMPLING_INTERVAL 1000000
> +
> +/* struct */
> +struct startup_param {
> +	uint64_t cpu;
> +};
> +
> +struct patch_info {
> +	int	use_flg;
> +	int	dpdk_port;
> +	struct spp_config_mac_table_element *mac_info;
> +	struct spp_core_port_info *rx_core;
> +	struct spp_core_port_info *tx_core;
> +};
> +
> +struct if_info {
> +	int num_nic;
> +	int num_vhost;
> +	int num_ring;
> +	struct patch_info nic_patchs[RTE_MAX_ETHPORTS];
> +	struct patch_info vhost_patchs[RTE_MAX_ETHPORTS];
> +	struct patch_info ring_patchs[RTE_MAX_ETHPORTS];
> +};
> +
> +static struct spp_config_area	g_config;
> +static struct startup_param	g_startup_param;
> +static struct if_info		g_if_info;
> +static struct spp_core_info	g_core_info[SPP_CONFIG_CORE_MAX];
> +
> +/*
> + * print a usage message
> + */
> +static void
> +usage(const char *progname)
> +{
> +	RTE_LOG(INFO, APP, "Usage: %s [EAL args]\n\n", progname);
> +}
> +
> +/*
> + * Set RING PMD
> + */
> +static int
> +add_ring_pmd(int ring_id)
> +{
> +	struct rte_ring *ring;
> +	int ring_port_id;
> +
> +	/* look up ring, based on user's provided id*/
> +	ring = rte_ring_lookup(get_rx_queue_name(ring_id));
> +	if (unlikely(ring == NULL)) {
> +		RTE_LOG(ERR, APP,
> +			"Cannot get RX ring - is server process running?\n");
> +		return -1;
> +	}
> +
> +	/* create ring pmd*/
> +	ring_port_id = rte_eth_from_ring(ring);
> +	RTE_LOG(DEBUG, APP, "ring port id %d\n", ring_port_id);
> +
> +	return ring_port_id;
> +}
> +
> +/*
> + * Set VHOST PMD
> + */
> +static int
> +add_vhost_pmd(int index)
> +{
> +	struct rte_eth_conf port_conf = {
> +		.rxmode = { .max_rx_pkt_len = ETHER_MAX_LEN }
> +	};
> +	struct rte_mempool *mp;
> +	uint8_t vhost_port_id;
> +	int nr_queues = 1;
> +	const char *name;
> +	char devargs[64];
> +	char *iface;
> +	uint16_t q;
> +	int ret;
> +#define NR_DESCS 128
> +
> +	mp = rte_mempool_lookup(PKTMBUF_POOL_NAME);
> +	if (unlikely(mp == NULL)) {
> +		RTE_LOG(ERR, APP, "Cannot get mempool for mbufs. (name = %s)\n",
> +				PKTMBUF_POOL_NAME);
> +		return -1;
> +	}
> +
> +	/* eth_vhost0 index 0 iface /tmp/sock0 on numa 0 */
> +	name = get_vhost_backend_name(index);
> +	iface = get_vhost_iface_name(index);
> +
> +	sprintf(devargs, "%s,iface=%s,queues=%d", name, iface, nr_queues);
> +	ret = rte_eth_dev_attach(devargs, &vhost_port_id);
> +	if (unlikely(ret < 0)) {
> +		RTE_LOG(ERR, APP, "rte_eth_dev_attach error. (ret = %d)\n", ret);
> +		return ret;
> +	}
> +
> +	ret = rte_eth_dev_configure(vhost_port_id, nr_queues, nr_queues,
> +		&port_conf);
> +	if (unlikely(ret < 0)) {
> +		RTE_LOG(ERR, APP, "rte_eth_dev_configure error. (ret = %d)\n",
> +				ret);
> +		return ret;
> +	}
> +
> +	/* Allocate and set up 1 RX queue per Ethernet port. */
> +	for (q = 0; q < nr_queues; q++) {
> +		ret = rte_eth_rx_queue_setup(vhost_port_id, q, NR_DESCS,
> +			rte_eth_dev_socket_id(vhost_port_id), NULL, mp);
> +		if (unlikely(ret < 0)) {
> +			RTE_LOG(ERR, APP,
> +				"rte_eth_rx_queue_setup error. (ret = %d)\n",
> +				ret);
> +			return ret;
> +		}
> +	}
> +
> +	/* Allocate and set up 1 TX queue per Ethernet port. */
> +	for (q = 0; q < nr_queues; q++) {
> +		ret = rte_eth_tx_queue_setup(vhost_port_id, q, NR_DESCS,
> +			rte_eth_dev_socket_id(vhost_port_id), NULL);
> +		if (unlikely(ret < 0)) {
> +			RTE_LOG(ERR, APP,
> +				"rte_eth_tx_queue_setup error. (ret = %d)\n",
> +				ret);
> +			return ret;
> +		}
> +	}
> +
> +	/* Start the Ethernet port. */
> +	ret = rte_eth_dev_start(vhost_port_id);
> +	if (unlikely(ret < 0)) {
> +		RTE_LOG(ERR, APP, "rte_eth_dev_start error. (ret = %d)\n", ret);
> +		return ret;
> +	}
> +
> +	RTE_LOG(DEBUG, APP, "vhost port id %d\n", vhost_port_id);
> +
> +	return vhost_port_id;
> +}
> +
> +/*
> + * Check core status
> + */
> +static int
> +check_core_status(enum spp_core_status status)
> +{
> +	int cnt;
> +	for (cnt = 0; cnt < SPP_CONFIG_CORE_MAX; cnt++) {
> +		if (g_core_info[cnt].type == SPP_CONFIG_UNUSE) {
> +			continue;
> +		}
> +		if (g_core_info[cnt].status != status) {
> +			/* Status mismatch */
> +			return -1;
> +		}
> +	}
> +	return 0;
> +}
> +
> +/*
> + * Wait for core status check
> + */
> +static int
> +check_core_status_wait(enum spp_core_status status)
> +{
> +	int cnt = 0;
> +	for (cnt = 0; cnt < SPP_CORE_STATUS_CHECK_MAX; cnt++) {
> +		sleep(1);
> +		int ret = check_core_status(status);
> +		if (ret == 0) {
> +			return 0;
> +		}
> +	}
> +
> +	RTE_LOG(ERR, APP, "Status check time out. (status = %d)\n", status);
> +	return -1;
> +}
> +
> +/*
> + * Set core status
> + */
> +static void
> +set_core_status(enum spp_core_status status)
> +{
> +	int core_cnt = 0;
> +	for(core_cnt = 0; core_cnt < SPP_CONFIG_CORE_MAX; core_cnt++) {
> +		g_core_info[core_cnt].status = status;
> +	}
> +}
> +
> +/*
> + * Process stop
> + */
> +void
> +stop_process(int signal) {
> +	if (unlikely(signal != SIGTERM) &&
> +			unlikely(signal != SIGINT)) {
> +		/* Other signals */
> +		return;
> +	}
> +
> +	set_core_status(SPP_CORE_STOP_REQUEST);
> +}
> +
> +/*
> + * 起動パラメータのCPUのbitmapを数値へ変換
> + */
> +static int
> +parse_cpu_bit(uint64_t *cpu, const char *cpu_bit)
> +{
> +	char *endptr = NULL;
> +	uint64_t temp;
> +
> +	temp = strtoull(cpu_bit, &endptr, 0);
> +	if (unlikely(endptr == cpu_bit) || unlikely(*endptr != '\0')) {
> +		return -1;
> +	}
> +
> +	*cpu = temp;
> +	RTE_LOG(DEBUG, APP, "cpu = %lu", *cpu);
> +	return 0;
> +}
> +
> +/*
> + * Parse the application arguments to the client app.
> + */
> +static int
> +parse_app_args(int argc, char *argv[])
> +{
> +	int option_index, opt;
> +	char **argvopt = argv;
> +	const char *progname = argv[0];
> +	static struct option lgopts[] = { {0} };
> +
> +	/* Check DPDK parameter */
> +	optind = 0;
> +	opterr = 0;
> +	while ((opt = getopt_long(argc, argvopt, "c:", lgopts,
> +			&option_index)) != EOF) {
> +		switch (opt) {
> +		case 'c':
> +			/* CPU */
> +			if (parse_cpu_bit(&g_startup_param.cpu, optarg) != 0) {
> +				usage(progname);
> +				return -1;
> +			}
> +			break;
> +		default:
> +			/* CPU */
> +			/* DPDKのパラメータは他にもあるので、エラーとはしない */
> +			break;
> +		}
> +	}
> +
> +	return 0;
> +}
> +
> +/*
> + * IF種別&IF番号のIF情報の領域取得
> + */
> +static struct patch_info *
> +get_if_area(enum port_type if_type, int if_no)
> +{
> +	switch (if_type) {
> +	case PHY:
> +		return &g_if_info.nic_patchs[if_no];
> +		break;
> +	case VHOST:
> +		return &g_if_info.vhost_patchs[if_no];
> +		break;
> +	case RING:
> +		return &g_if_info.ring_patchs[if_no];
> +		break;
> +	default:
> +		/* エラー出力は呼び元でチェック */
> +		return NULL;
> +		break;
> +	}
> +}
> +
> +/*
> + * IF情報初期化
> + */
> +static void
> +init_if_info()
> +{
> +	memset(&g_if_info, 0x00, sizeof(g_if_info));
> +}
> +
> +/*
> + * CORE情報初期化
> + */
> +static void
> +init_core_info()
> +{
> +	memset(&g_core_info, 0x00, sizeof(g_core_info));
> +	int core_cnt, port_cnt;
> +	for (core_cnt = 0; core_cnt < SPP_CONFIG_CORE_MAX; core_cnt++) {
> +		for (port_cnt = 0; port_cnt < RTE_MAX_ETHPORTS; port_cnt++) {
> +			g_core_info[core_cnt].rx_ports[port_cnt].if_type = UNDEF;
> +			g_core_info[core_cnt].tx_ports[port_cnt].if_type = UNDEF;
> +		}
> +	}
> +}
> +
> +/*
> + * Configのプロセス情報から管理情報に設定
> + */
> +static int
> +set_form_proc_info(struct spp_config_area *config)
> +{
> +	/* Configのproc_infoから内部管理情報へ設定 */
> +	int core_cnt, rx_start, rx_cnt, tx_start, tx_cnt;
> +	enum port_type if_type;
> +	int if_no;
> +	int64_t cpu_bit = 0;
> +	struct spp_config_functions *core_func = NULL;
> +	struct spp_core_info *core_info = NULL;
> +	struct patch_info *patch_info = NULL;
> +	for (core_cnt = 0; core_cnt < config->proc.num_func; core_cnt++) {
> +		core_func = &config->proc.functions[core_cnt];
> +		core_info = &g_core_info[core_func->core_no];
> +
> +		if (core_func->type == SPP_CONFIG_UNUSE) {
> +			continue;
> +		}
> +
> +		/* Forwardをまとめる事は可、他種別は不可 */
> +		if ((core_info->type != SPP_CONFIG_UNUSE) &&
> +				((core_info->type != SPP_CONFIG_FORWARD) &&
> +				(core_func->type != SPP_CONFIG_FORWARD))) {
> +			RTE_LOG(ERR, APP, "Core in use. (core = %d, type = %d/%d)\n",
> +					core_func->core_no,
> +					core_func->type, core_info->type);
> +			return -1;
> +		}
> +
> +		/* Set CORE type */
> +		core_info->type = core_func->type;
> +		cpu_bit |= 1 << core_func->core_no;
> +
> +		/* Set RX port */
> +		rx_start = core_info->num_rx_port;
> +		core_info->num_rx_port += core_func->num_rx_port;
> +		for (rx_cnt = 0; rx_cnt < core_func->num_rx_port; rx_cnt++) {
> +			if_type = core_func->rx_ports[rx_cnt].if_type;
> +			if_no   = core_func->rx_ports[rx_cnt].if_no;
> +
> +			core_info->rx_ports[rx_start + rx_cnt].if_type = if_type;
> +			core_info->rx_ports[rx_start + rx_cnt].if_no   = if_no;
> +
> +			/* IF種別とIF番号に対応するIF情報の領域取得 */
> +			patch_info = get_if_area(if_type, if_no);
> +
> +			patch_info->use_flg = 1;
> +			if (unlikely(patch_info->rx_core != NULL)) {
> +				RTE_LOG(ERR, APP, "Used RX port (if_type = %d, if_no = %d)\n",
> +						if_type, if_no);
> +				return -1;
> +			}
> +
> +			/* IF情報からCORE情報を変更する場合用に設定 */
> +			patch_info->rx_core = &core_info->rx_ports[rx_start + rx_cnt];
> +		}
> +
> +		/* Set TX port */
> +		tx_start = core_info->num_tx_port;
> +		core_info->num_tx_port += core_func->num_tx_port;
> +		for (tx_cnt = 0; tx_cnt < core_func->num_tx_port; tx_cnt++) {
> +			if_type = core_func->tx_ports[tx_cnt].if_type;
> +			if_no   = core_func->tx_ports[tx_cnt].if_no;
> +
> +			core_info->tx_ports[tx_start + tx_cnt].if_type = if_type;
> +			core_info->tx_ports[tx_start + tx_cnt].if_no   = if_no;
> +
> +			/* IF種別とIF番号に対応するIF情報の領域取得 */
> +			patch_info = get_if_area(if_type, if_no);
> +
> +			patch_info->use_flg = 1;
> +			if (unlikely(patch_info->tx_core != NULL)) {
> +				RTE_LOG(ERR, APP, "Used TX port (if_type = %d, if_no = %d)\n",
> +						if_type, if_no);
> +				return -1;
> +			}
> +
> +			/* IF情報からCORE情報を変更する場合用に設定 */
> +			patch_info->tx_core = &core_info->tx_ports[tx_start + tx_cnt];
> +		}
> +	}
> +
> +	if (unlikely((cpu_bit & g_startup_param.cpu) != cpu_bit)) {
> +		/* CPU mismatch */
> +		RTE_LOG(ERR, APP, "CPU mismatch (cpu param = %lx, config = %lx)\n",
> +				g_startup_param.cpu, cpu_bit);
> +		return -1;
> +	}
> +	return 0;
> +}
> +
> +/*
> + * ConfigのMACテーブル情報から管理情報に設定
> + */
> +static int
> +set_from_classifier_table(struct spp_config_area *config)
> +{
> +	/* MAC table */
> +	enum port_type if_type;
> +	int if_no = 0;
> +	int mac_cnt = 0;
> +	struct spp_config_mac_table_element *mac_table = NULL;
> +	struct patch_info *patch_info = NULL;
> +	for (mac_cnt = 0; mac_cnt < config->classifier_table.num_table; mac_cnt++) {
> +		mac_table = &config->classifier_table.mac_tables[mac_cnt];
> +
> +		if_type = mac_table->port.if_type;
> +		if_no   = mac_table->port.if_no;
> +
> +		/* IF種別とIF番号に対応するIF情報の領域取得 */
> +		patch_info = get_if_area(if_type, if_no);
> +
> +		if (unlikely(patch_info->use_flg == 0)) {
> +			RTE_LOG(ERR, APP, "Not used interface (if_type = %d, if_no = %d)\n",
> +					if_type, if_no);
> +			return -1;
> +		}
> +
> +		/* CORE情報側にもMACアドレスの情報設定 */
> +		/* MACアドレスは送信側のみに影響する為、送信側のみ設定 */
> +		patch_info->mac_info = mac_table;
> +		if (unlikely(patch_info->tx_core != NULL)) {
> +			patch_info->tx_core->mac_addr = mac_table->mac_addr;
> +			strcpy(patch_info->tx_core->mac_addr_str, mac_table->mac_addr_str);
> +		}
> +	}
> +	return 0;
> +}
> +
> +/*
> + * NIC用の情報設定
> + */
> +static int
> +set_nic_interface(struct spp_config_area *config)
> +{
> +	/* NIC Setting */
> +	g_if_info.num_nic = rte_eth_dev_count();
> +	if (g_if_info.num_nic > RTE_MAX_ETHPORTS) {
> +		g_if_info.num_nic = RTE_MAX_ETHPORTS;
> +	}
> +
> +	int nic_cnt, nic_num = 0;
> +	struct patch_info *patch_info = NULL;
> +	for (nic_cnt = 0; nic_cnt < RTE_MAX_ETHPORTS; nic_cnt++) {
> +		patch_info = &g_if_info.nic_patchs[nic_cnt];
> +		/* Set DPDK port */
> +		patch_info->dpdk_port = nic_cnt;
> +
> +		if (patch_info->use_flg == 0) {
> +			/* Not Used */
> +			continue;
> +		}
> +
> +		/* CORE情報側にもDPDKポート番号の情報設定 */
> +		if (patch_info->rx_core != NULL) {
> +			patch_info->rx_core->dpdk_port = nic_cnt;
> +		}
> +		if (patch_info->tx_core != NULL) {
> +			patch_info->tx_core->dpdk_port = nic_cnt;
> +		}
> +
> +		/* NICの設定数カウント */
> +		nic_num++;
> +	}
> +
> +	if (unlikely(nic_num > g_if_info.num_nic)) {
> +		RTE_LOG(ERR, APP, "NIC Setting mismatch. (IF = %d, config = %d)\n",
> +				nic_num, g_if_info.num_nic);
> +		return -1;
> +	}
> +	
> +	return 0;
> +}
> +
> +/*
> + * VHOST用の情報設定
> + */
> +static int
> +set_vhost_interface(struct spp_config_area *config)
> +{
> +	/* VHOST Setting */
> +	int vhost_cnt, vhost_num = 0;
> +	g_if_info.num_vhost = config->proc.num_vhost;
> +	struct patch_info *patch_info = NULL;
> +	for (vhost_cnt = 0; vhost_cnt < RTE_MAX_ETHPORTS; vhost_cnt++) {
> +		patch_info = &g_if_info.vhost_patchs[vhost_cnt];
> +		if (patch_info->use_flg == 0) {
> +			/* Not Used */
> +			continue;
> +		}
> +
> +		/* Set DPDK port */
> +		int dpdk_port = add_vhost_pmd(vhost_cnt);
> +		if (unlikely(dpdk_port < 0)) {
> +			RTE_LOG(ERR, APP, "VHOST add failed. (no = %d)\n",
> +					vhost_cnt);
> +			return -1;
> +		}
> +		patch_info->dpdk_port = dpdk_port;
> +
> +		/* CORE情報側にもDPDKポート番号の情報設定 */
> +		if (patch_info->rx_core != NULL) {
> +			patch_info->rx_core->dpdk_port = dpdk_port;
> +		}
> +		if (patch_info->tx_core != NULL) {
> +			patch_info->tx_core->dpdk_port = dpdk_port;
> +		}
> +		vhost_num++;
> +	}
> +	if (unlikely(vhost_num > g_if_info.num_vhost)) {
> +		RTE_LOG(ERR, APP, "VHOST Setting mismatch. (IF = %d, config = %d)\n",
> +				vhost_num, g_if_info.num_vhost);
> +		return -1;
> +	}
> +	return 0;
> +}
> +
> +/*
> + * RING用の情報設定
> + */
> +static int
> +set_ring_interface(struct spp_config_area *config)
> +{
> +	/* RING Setting */
> +	int ring_cnt, ring_num = 0;
> +	g_if_info.num_ring = config->proc.num_ring;
> +	struct patch_info *patch_info = NULL;
> +	for (ring_cnt = 0; ring_cnt < RTE_MAX_ETHPORTS; ring_cnt++) {
> +		patch_info = &g_if_info.ring_patchs[ring_cnt];
> +		if (patch_info->use_flg == 0) {
> +			/* Not Used */
> +			continue;
> +		}
> +
> +		/* Set DPDK port */
> +		int dpdk_port = add_ring_pmd(ring_cnt);
> +		if (unlikely(dpdk_port < 0)) {
> +			RTE_LOG(ERR, APP, "RING add failed. (no = %d)\n",
> +					ring_cnt);
> +			return -1;
> +		}
> +		patch_info->dpdk_port = dpdk_port;
> +
> +		/* CORE情報側にもDPDKポート番号の情報設定 */
> +		if (patch_info->rx_core != NULL) {
> +			patch_info->rx_core->dpdk_port = dpdk_port;
> +		}
> +		if (patch_info->tx_core != NULL) {
> +			patch_info->tx_core->dpdk_port = dpdk_port;
> +		}
> +		ring_num++;
> +	}
> +	if (unlikely(ring_num > g_if_info.num_ring)) {
> +		RTE_LOG(ERR, APP, "RING Setting mismatch. (IF = %d, config = %d)\n",
> +				ring_num, g_if_info.num_ring);
> +		return -1;
> +	}
> +	return 0;
> +}
> +
> +/*
> + * 管理データ初期設定
> + */
> +static int
> +init_manage_data(struct spp_config_area *config)
> +{
> +	/* Initialize */
> +	init_if_info(config);
> +	init_core_info(config);
> +
> +	/* Set config data */
> +	int ret_proc = set_form_proc_info(config);
> +	if (unlikely(ret_proc != 0)) {
> +		/* 関数内でログ出力済みなので、省略 */
> +		return -1;
> +	}
> +	int ret_classifier = set_from_classifier_table(config);
> +	if (unlikely(ret_classifier != 0)) {
> +		/* 関数内でログ出力済みなので、省略 */
> +		return -1;
> +	}
> +
> +	/* Set interface data */
> +	int ret_nic = set_nic_interface(config);
> +	if (unlikely(ret_nic != 0)) {
> +		/* 関数内でログ出力済みなので、省略 */
> +		return -1;
> +	}
> +
> +	int ret_vhost = set_vhost_interface(config);
> +	if (unlikely(ret_vhost != 0)) {
> +		/* 関数内でログ出力済みなので、省略 */
> +		return -1;
> +	}
> +
> +	int ret_ring = set_ring_interface(config);
> +	if (unlikely(ret_ring != 0)) {
> +		/* 関数内でログ出力済みなので、省略 */
> +		return -1;
> +	}
> +
> +	return 0;
> +}
> +
> +#ifdef SPP_RINGLATENCYSTATS_ENABLE /* RING滞留時間 */
> +static void
> +print_ring_latency_stats()
> +{
> +	/* Clear screen and move to top left */
> +	const char topLeft[] = { 27, '[', '1', ';', '1', 'H', '\0' };
> +	const char clr[] = { 27, '[', '2', 'J', '\0' };
> +	printf("%s%s", clr, topLeft);
> +
> +	/* Print per RING */
> +	int ring_cnt, stats_cnt;
> +	struct spp_ringlatencystats_ring_latency_stats stats[RTE_MAX_ETHPORTS];
> +	memset(&stats, 0x00, sizeof(stats));
> +
> +	printf("RING Latency\n");
> +	printf(" RING");
> +	for (ring_cnt = 0; ring_cnt < RTE_MAX_ETHPORTS; ring_cnt++) {
> +		if (g_if_info.ring_patchs[ring_cnt].use_flg == 0) {
> +			continue;
> +		}
> +		spp_ringlatencystats_get_stats(ring_cnt, &stats[ring_cnt]);
> +		printf(", %-18d", ring_cnt);
> +	}
> +	printf("\n");
> +
> +	for (stats_cnt = 0; stats_cnt < SPP_RINGLATENCYSTATS_STATS_SLOT_COUNT; stats_cnt++) {
> +		printf("%3dns", stats_cnt);
> +		for (ring_cnt = 0; ring_cnt < RTE_MAX_ETHPORTS; ring_cnt++) {
> +			if (g_if_info.ring_patchs[ring_cnt].use_flg == 0) {
> +				continue;
> +			}
> +
> +			printf(", 0x%-16lx", stats[ring_cnt].slot[stats_cnt]);
> +		}
> +		printf("\n");
> +	}
> +
> +	return;
> +}
> +#endif /* SPP_RINGLATENCYSTATS_ENABLE */
> +
> +/*
> + * main
> + */
> +int
> +#ifndef USE_UT_SPP_VF
> +main(int argc, char *argv[])
> +#else /* ifndef USE_UT_SPP_VF */
> +ut_main(int argc, char *argv[])
> +#endif  /* ifndef USE_UT_SPP_VF */
> +{
> +	int ret = -1;
> +#ifdef SPP_DEMONIZE
> +	/* Daemonize process */
> +	int ret_daemon = daemon(0, 0);
> +	if (unlikely(ret_daemon != 0)) {
> +		RTE_LOG(ERR, APP, "daemonize is faild. (ret = %d)\n", ret_daemon);
> +		return ret_daemon;
> +	}
> +#endif
> +
> +	/* Signal handler registration (SIGTERM/SIGINT) */
> +	signal(SIGTERM, stop_process);
> +	signal(SIGINT,  stop_process);
> +
> +	unsigned int main_lcore_id = 0xffffffff;
> +	while(1) {
> +		/* Parse parameters */
> +		int ret_parse = parse_app_args(argc, argv);
> +		if (unlikely(ret_parse != 0)) {
> +			break;
> +		}
> +
> +		/* Load config */
> +		int ret_config = spp_config_load_file(0, &g_config);
> +		if (unlikely(ret_config != 0)) {
> +			break;
> +		}
> +
> +		/* DPDK initialize */
> +		int ret_dpdk = rte_eal_init(argc, argv);
> +		if (unlikely(ret_dpdk < 0)) {
> +			break;
> +		}
> +		/* Get core id. */
> +		main_lcore_id = rte_lcore_id();
> +
> +		/* 起動パラメータとコンフィグチェック */
> +		/* 各IF情報設定 */
> +		int ret_manage = init_manage_data(&g_config);
> +		if (unlikely(ret_manage != 0)) {
> +			break;
> +		}
> +
> +		/* 他機能部初期化 */
> +#ifdef SPP_RINGLATENCYSTATS_ENABLE /* RING滞留時間 */
> +		int ret_ringlatency = spp_ringlatencystats_init(
> +				SPP_RING_LATENCY_STATS_SAMPLING_INTERVAL, g_if_info.num_ring);
> +		if (unlikely(ret_ringlatency != 0)) {
> +			break;
> +		}
> +#endif /* SPP_RINGLATENCYSTATS_ENABLE */
> +
> +		/* Start  thread */
> +		unsigned int lcore_id = 0;
> +		RTE_LCORE_FOREACH_SLAVE(lcore_id) {
> +			if (g_core_info[lcore_id].type == SPP_CONFIG_CLASSIFIER_MAC) {
> +				rte_eal_remote_launch(spp_classifier_mac_do,
> +						(void *)&g_core_info[lcore_id],
> +						lcore_id);
> +			} else {
> +				rte_eal_remote_launch(spp_forward,
> +						(void *)&g_core_info[lcore_id],
> +						lcore_id);
> +			}
> +		}
> +
> +		/* スレッド状態確認 */
> +		g_core_info[main_lcore_id].status = SPP_CORE_IDLE;
> +		int ret_wait = check_core_status_wait(SPP_CORE_IDLE);
> +		if (unlikely(ret_wait != 0)) {
> +			break;
> +		}
> +
> +		/* Start forward */
> +		set_core_status(SPP_CORE_FORWARD);
> +		RTE_LOG(INFO, APP, "My ID %d start handling message\n", 0);
> +		RTE_LOG(INFO, APP, "[Press Ctrl-C to quit ...]\n");
> +
> +		/* loop */
> +#ifndef USE_UT_SPP_VF
> +		while(likely(g_core_info[main_lcore_id].status != SPP_CORE_STOP_REQUEST)) {
> +#else
> +		{
> +#endif
> +			sleep(1);
> +
> +#ifdef SPP_RINGLATENCYSTATS_ENABLE /* RING滞留時間 */
> +			print_ring_latency_stats();
> +#endif /* SPP_RINGLATENCYSTATS_ENABLE */
> +		}
> +
> +		/* 正常終了 */
> +		ret = 0;
> +		break;
> +	}
> +
> +	/* exit */
> +	stop_process(SIGINT);
> +	if (main_lcore_id == rte_lcore_id())
> +	{
> +		g_core_info[main_lcore_id].status = SPP_CORE_STOP;
> +		int ret_core_end = check_core_status_wait(SPP_CORE_STOP);
> +		if (unlikely(ret_core_end != 0)) {
> +			RTE_LOG(ERR, APP, "Core did not stop.\n");
> +		}
> +	}
> +
> +	/* 他機能部終了処理 */
> +#ifdef SPP_RINGLATENCYSTATS_ENABLE /* RING滞留時間 */
> +	spp_ringlatencystats_uninit();
> +#endif /* SPP_RINGLATENCYSTATS_ENABLE */
> +	RTE_LOG(INFO, APP, "spp_vf exit.\n");
> +	return ret;
> +}
> diff --git a/src/vf/spp_vf.h b/src/vf/spp_vf.h
> new file mode 100644
> index 0000000..feb59b6
> --- /dev/null
> +++ b/src/vf/spp_vf.h
> @@ -0,0 +1,40 @@
> +#ifndef __SPP_VF_H__
> +#define __SPP_VF_H__
> +
> +#include "common.h"
> +#include "spp_config.h"
> +
> +/*
> + * State on core
> + */
> +enum spp_core_status {
> +	SPP_CORE_STOP,
> +	SPP_CORE_IDLE,
> +	SPP_CORE_FORWARD,
> +	SPP_CORE_STOP_REQUEST
> +};
> +
> +/*
> + * Port info on core
> + */
> +struct spp_core_port_info {
> +	enum		port_type if_type;
> +	int		if_no;
> +	int		dpdk_port;
> +	uint64_t	mac_addr;
> +	char		mac_addr_str[SPP_CONFIG_STR_LEN];
> +};
> +
> +/*
> + * Core info
> + */
> +struct spp_core_info {
> +	enum	spp_core_status status;
> +	enum	spp_core_type type;
> +	int	num_rx_port;
> +	int	num_tx_port;
> +	struct spp_core_port_info rx_ports[RTE_MAX_ETHPORTS];
> +	struct spp_core_port_info tx_ports[RTE_MAX_ETHPORTS];
> +};
> +
> +#endif /* __SPP_VF_H__ */
> 


-- 
Yasufumi Ogawa
NTT Network Service Systems Labs

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

* Re: [spp] Proposal - spp_vf(SR-IOV like feature) addition to SPP
  2017-12-25  4:41 [spp] Proposal - spp_vf(SR-IOV like feature) addition to SPP Nakamura Hioryuki
  2017-12-26  1:54 ` Yasufumi Ogawa
@ 2018-01-15 11:04 ` Ferruh Yigit
  2018-01-16  5:16   ` [spp] [PATCH 01/30] doc: add setup guide x-fn-spp
                     ` (29 more replies)
  1 sibling, 30 replies; 97+ messages in thread
From: Ferruh Yigit @ 2018-01-15 11:04 UTC (permalink / raw)
  To: Nakamura Hioryuki, spp

On 12/25/2017 4:41 AM, Nakamura Hioryuki wrote:
> Hi everyone,
> 
> As announced in DPDK Summit, we would like to introduce a SR-IOV like network 
> functionality to SPP on DPDK17.08[1].
> 
> To support such functionality, we have developed new 
> controller(spp_vf.py) and secondary process(spp_vf).
> 
> spp_vf process has three kinds of component, classifier, forwarder and merger.
> These components communicate each other via ring-pmd, 
> and provides SR-IOV like packet classification function according to virtual 
> MAC address.
> 
> Classifier:
> This component provides packet forwarding function from one port to one port.
> Classifier has table of virtual MAC address.
> According to this table, classifier lookups L2 destination MAC address
> and determines which port to be transferred to incoming packets.
> L2 Multicast feature is also supported. 
> 
> Forwarder:
> This provides function for packet processing from one port to one port.
> Incoming packets from port are to be transferred to specific one port.
> The direction of this transferring is specified by `port` command.
> 
> Merger:
> This component provides packet forwarding function from multiple ports to one port.
> Incoming packets from multiple ports are to be transferred to one specific port.
> The flow of this merging process is specified by `port` command.
> 
> By the combination of these component, following SR-IOV like function can be configured.
> 
>                    +----------+           +-----------+
>                    |Classifier|->ringPMD->|Forwarder#1|->vhost->VM#1 --------+
> Packet(dstMAC:A/B) |          |           +-----------+         (vMAC:A)     |
> ------phy--------> |          |           +-----------+                      |
>                    |          |->ringPMD->|Forwarder#2|->vhost->VM#2 ---+    |
>                    |          |           +-----------+         (vMAC:B)|    |
>                    +----------+                                         |    |
>                                                                         |    |
>                    +----------+           +-----------+                 |    |
>                    |Merger    |<-ringPMD<-|Forwarder#3|<-vhost --==----------+
>                    |          |           +-----------+                 |
>  <------phy--------|          |           +-----------+                 |
>                    |          |<-ringPMD<-|Forwarder#4|<-vhost ---------+
>                    +----------+           +-----------+ 
> 
> Limitaion#1: vlan support is not yet, this feature is in still our backlogs.
> Limitaion#2: Support DPDK17.11 is not yet.
>                    
> Code changes will be posted in the following emails.

Series applied, thanks.

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

* [spp] [PATCH 01/30] doc: add setup guide
  2018-01-15 11:04 ` [spp] Proposal - spp_vf(SR-IOV like feature) addition to SPP Ferruh Yigit
@ 2018-01-16  5:16   ` x-fn-spp
  2018-01-19  0:52     ` Yasufumi Ogawa
  2018-01-16  5:16   ` [spp] [PATCH 02/30] doc: add how_to_use.md x-fn-spp
                     ` (28 subsequent siblings)
  29 siblings, 1 reply; 97+ messages in thread
From: x-fn-spp @ 2018-01-16  5:16 UTC (permalink / raw)
  To: spp

From: Hiroyuki Nakamura <nakamura.hioryuki@po.ntt-tx.co.jp>

Hi all,

> Series applied, thanks.

Ferruh, thank you for accepting our patches.

We will post the document patches for spp_vf on DPDK17.08 in the
following emails.


Translate Japanese setup guide to English.

Signed-off-by: Naoki Takada <takada.naoki@lab.ntt.co.jp>
---
 docs/spp_vf/setup.md | 288 +++++++++++++++++++++++++++++++++++++++++++++++++++
 1 file changed, 288 insertions(+)
 create mode 100644 docs/spp_vf/setup.md

diff --git a/docs/spp_vf/setup.md b/docs/spp_vf/setup.md
new file mode 100644
index 0000000..572777b
--- /dev/null
+++ b/docs/spp_vf/setup.md
@@ -0,0 +1,288 @@
+# Setup Guide
+
+## Environment
+
+* Ubuntu 16.04
+* qemu-kvm
+* DPDK v17.05
+
+## Setting
+
+### Host
+
+#### Edit Config
+
+Uncomment user and group in `/etc/libvirt/qemu.conf`.
+
+```sh
+# /etc/libvirt/qemu.conf
+
+user = "root"
+group = "root"
+```
+
+Change `KVM_HUGEPAGES` from 0 to 1 in `/etc/default/qemu-kvm`.
+
+```sh
+# /etc/default/qemu-kvm
+
+KVM_HUGEPAGES=1
+```
+
+Change grub config for hugepages and isolcpus.
+
+```sh
+# /etc/default/grub
+
+GRUB_CMDLINE_LINUX_DEFAULT="isolcpus=2,4,6,8,10,12-18,20,22,24,26-42,44,46 hugepagesz=1G hugepages=36 default_hugepagesz=1G"
+```
+
+You need to run `update-grub` and reboot to activate grub config.
+
+```sh
+$ sudo upadte-grub
+$ sudo reboot
+```
+
+You can check hugepage settings as following.
+
+```sh
+$ cat /proc/meminfo | grep -i huge
+AnonHugePages:      2048 kB
+HugePages_Total:      36		#	/etc/default/grub
+HugePages_Free:       36
+HugePages_Rsvd:        0
+HugePages_Surp:        0
+Hugepagesize:    1048576 kB		#	/etc/default/grub
+
+$ mount | grep -i huge
+cgroup on /sys/fs/cgroup/hugetlb type cgroup (rw,nosuid,nodev,noexec,relatime,hugetlb,release_agent=/run/cgmanager/agents/cgm-release-agent.hugetlb,nsroot=/)
+hugetlbfs on /dev/hugepages type hugetlbfs (rw,relatime)
+hugetlbfs-kvm on /run/hugepages/kvm type hugetlbfs (rw,relatime,mode=775,gid=117)
+hugetlb on /run/lxcfs/controllers/hugetlb type cgroup (rw,relatime,hugetlb,release_agent=/run/cgmanager/agents/cgm-release-agent.hugetlb,nsroot=/)
+```
+
+Finally, you unmount default hugepage.
+
+```sh
+$ sudo unmount /dev/hugepages
+```
+
+#### Install jasson
+
+Network configuration is defined in JSON and `spp_vf` reads config from
+the file while launching.
+[jasson](http://www.digip.org/jansson/) is a JSON library written in C.
+
+It is required to use `json_path` feature of `jasson` for `spp_vf`.
+It has develped under `json_path` branch and you need to checkout and compile
+it manually.
+
+```sh
+$ git clone https://github.com/rogerz/jansson
+$ cd jansson
+$ sudo git checkout json_path
+Branch json_path set up to track remote branch json_path from origin. Switched to a new branch 'json_path'
+```
+
+This setup guide expects that `jasson` is placed as `/opt/jasson`.
+
+```sh
+$ sudo mkdir -p /opt/jansson
+$ sudo mv jansson /opt/jansson
+```
+
+Compile it as following.
+
+```sh
+$ cd /opt/jansson/jansson
+$ sudo autoreconf -i
+$ sudo ./configure
+$ sudo make
+$ sudo make install
+$ sudo ldconfig
+```
+
+Then, confirm that header files of jasson are generated in `/usr/local/include`.
+
+```sh
+$ ls -al /usr/local/include
+total 24
+drwxr-xr-x  2 root root 4096 Jul 28 16:45 .
+drwxr-xr-x 10 root root 4096 May 27 10:23 ..
+-rw-r--r--  1 root root 1183 Jul 28 16:45 jansson_config.h
+-rw-r--r--  1 root root 9499 Jul 28 16:45 jansson.h
+```
+
+#### Install DPDK
+
+Install DPDK v17.05 in any directory. This is a simple instruction and please refer
+[Getting Started Guide for Linux](http://dpdk.org/doc/guides/linux_gsg/index.html)
+for details.
+
+```sh
+$ cd /path/to/any_dir
+$ git clone http://dpdk.org/git/dpdk
+$ cd dpdk
+$ git checkout v17.05
+$ export RTE_SDK=`pwd`
+$ export RTE_TARGET=x86_64-native-linuxapp-gcc
+$ make T=x86_64-native-linuxapp-gcc install
+```
+
+#### Install SPP
+
+Clone SPP in any directory and compile it.
+
+```sh
+$ cd /path/to/spp_home/
+$ git clone https://github.com/ntt-ns/Soft-Patch-Panel.git
+export SPP_HOME=/path/to/spp_home/Soft-Patch-Panel
+$ cd $SPP_HOME
+$ make
+```
+
+#### Setup for DPDK
+
+Load igb_uio module.
+
+```sh
+$ sudo modprobe uio
+$ sudo insmod $RTE_SDK/x86_64-native-linuxapp-gcc/kmod/igb_uio.ko
+$ lsmod | grep uio
+igb_uio                16384  0  # igb_uio is loaded
+uio                    20480  1 igb_uio
+```
+
+Then, bind it with PCI_Number.
+```sh
+$ $RTE_SDK/usertools/dpdk-devbind.py --status
+# check your device for PCI_Number
+
+$ sudo $RTE_SDK/usertools/dpdk-devbind.py --bind=igb_uio [PCI_Number]
+```
+
+#### virsh setup
+
+Edit VM configuration with virsh.
+
+```sh
+$ virsh edit [VM_NAME]
+<domain type='kvm' xmlns:qemu='http://libvirt.org/schemas/domain/qemu/1.0'>
+	  <name>spp-vm1</name>
+	  <uuid>d90f5420-861a-4479-8559-62d7a1545cb9</uuid>
+	  <memory unit='KiB'>4194304</memory>
+	  <currentMemory unit='KiB'>4194304</currentMemory>
+	  <memoryBacking>
+	    <hugepages/>
+	  </memoryBacking>
+	  <vcpu placement='static'>4</vcpu>
+	  <os>
+	    <type arch='x86_64' machine='pc-i440fx-2.3'>hvm</type>
+	    <boot dev='hd'/>
+	  </os>
+	  <features>
+	    <acpi/>
+	    <apic/>
+	    <pae/>
+	  </features>
+	  <clock offset='utc'/>
+	  <on_poweroff>destroy</on_poweroff>
+	  <on_reboot>restart</on_reboot>
+	  <on_crash>restart</on_crash>
+	  <devices>
+	    <emulator>/usr/local/bin/qemu-system-x86_64</emulator>
+	    <disk type='file' device='disk'>
+	      <driver name='qemu' type='raw'/>
+	      <source file='/var/lib/libvirt/images/spp-vm1.qcow2'/>
+	      <target dev='hda' bus='ide'/>
+	      <address type='drive' controller='0' bus='0' target='0' unit='0'/>
+	    </disk>
+	    <disk type='block' device='cdrom'>
+	      <driver name='qemu' type='raw'/>
+	      <target dev='hdc' bus='ide'/>
+	      <readonly/>
+	      <address type='drive' controller='0' bus='1' target='0' unit='0'/>
+	    </disk>
+	    <controller type='usb' index='0'>
+	      <address type='pci' domain='0x0000' bus='0x00' slot='0x01' function='0x2'/>
+	    </controller>
+	    <controller type='pci' index='0' model='pci-root'/>
+	    <controller type='ide' index='0'>
+	      <address type='pci' domain='0x0000' bus='0x00' slot='0x01' function='0x1'/>
+	    </controller>
+	    <interface type='network'>
+	      <mac address='52:54:00:99:aa:7f'/>
+	      <source network='default'/>
+	      <model type='rtl8139'/>
+	      <address type='pci' domain='0x0000' bus='0x00' slot='0x02' function='0x0'/>
+	    </interface>
+	    <serial type='pty'>
+	      <target type='isa-serial' port='0'/>
+	    </serial>
+	    <console type='pty'>
+	      <target type='serial' port='0'/>
+	    </console>
+	    <memballoon model='virtio'>
+	      <address type='pci' domain='0x0000' bus='0x00' slot='0x03' function='0x0'/>
+	    </memballoon>
+	  </devices>
+	  <qemu:commandline>
+	    <qemu:arg value='-cpu'/>
+	    <qemu:arg value='host'/>
+	    <qemu:arg value='-object'/>
+	    <qemu:arg value='memory-backend-file,id=mem,size=4096M,mem-path=/run/hugepages/kvm,share=on'/>
+	    <qemu:arg value='-numa'/>
+	    <qemu:arg value='node,memdev=mem'/>
+	    <qemu:arg value='-mem-prealloc'/>
+	    <qemu:arg value='-chardev'/>
+	    <qemu:arg value='socket,id=chr0,path=/tmp/sock0'/>
+	    <qemu:arg value='-device'/>
+	    <qemu:arg value='virtio-net-pci,netdev=vhost-net0'/>
+	    <qemu:arg value='-netdev'/>
+	    <qemu:arg value='vhost-user,id=vhost-net0,chardev=chr0,vhostforce'/>
+	    <qemu:arg value='-chardev'/>
+	    <qemu:arg value='socket,id=chr1,path=/tmp/sock1'/>
+	    <qemu:arg value='-device'/>
+	    <qemu:arg value='virtio-net-pci,netdev=vhost-net1'/>
+	    <qemu:arg value='-netdev'/>
+	    <qemu:arg value='vhost-user,id=vhost-net1,chardev=chr1,vhostforce'/>
+	  </qemu:commandline>
+	</domain>
+```
+
+### Trouble Shooting
+
+You might encounter a permission error for `tmp/sockN` because of appamor.
+In this case, you should try it.
+
+```sh
+$ sudo ln -s /etc/apparmor.d/usr.lib.libvirt.virt-aa-helper /etc/apparmor.d/disable/usr.lib.libvirt.virt-aa-helper
+$ sudo ln -s /etc/apparmor.d/usr.sbin.libvirtd /etc/apparmor.d/disable/usr.sbin.libvirtd
+$ sudo apparmor_parser -R /etc/apparmor.d/usr.lib.libvirt.virt-aa-helper
+$ sudo apparmor_parser -R /etc/apparmor.d/usr.sbin.libvirtd
+$ sudo service apparmor reload
+$ sudo service apparmor restart
+$ sudo service libvirt-bin restart
+```
+
+Or, you remove appamor.
+
+```sh
+$ sudo apt-get remove apparmor
+```
+
+If you use CentOS, not Ubuntu, confirm that SELinux doesn't prevent for permission.
+SELinux should be disabled in this case.
+
+```sh
+# /etc/selinux/config
+SELINUX=disabled
+```
+
+Check your SELinux configuration.
+
+```sh
+$ getenforce
+Disabled
+```
-- 
1.9.1

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

* [spp] [PATCH 02/30] doc: add how_to_use.md
  2018-01-15 11:04 ` [spp] Proposal - spp_vf(SR-IOV like feature) addition to SPP Ferruh Yigit
  2018-01-16  5:16   ` [spp] [PATCH 01/30] doc: add setup guide x-fn-spp
@ 2018-01-16  5:16   ` x-fn-spp
  2018-01-16  5:16   ` [spp] [PATCH 03/30] doc: add config_manual.md x-fn-spp
                     ` (27 subsequent siblings)
  29 siblings, 0 replies; 97+ messages in thread
From: x-fn-spp @ 2018-01-16  5:16 UTC (permalink / raw)
  To: spp

From: Hiroyuki Nakamura <nakamura.hioryuki@po.ntt-tx.co.jp>

how_to_use.md is a guide for running spp_vf.

Signed-off-by: Naoki Takada <takada.naoki@lab.ntt.co.jp>
---
 docs/spp_vf/how_to_use.md       | 105 ++++++
 docs/spp_vf/setup.md            |   3 +
 docs/spp_vf/spp_vf_overview.svg | 793 ++++++++++++++++++++++++++++++++++++++++
 3 files changed, 901 insertions(+)
 create mode 100644 docs/spp_vf/how_to_use.md
 create mode 100644 docs/spp_vf/spp_vf_overview.svg

diff --git a/docs/spp_vf/how_to_use.md b/docs/spp_vf/how_to_use.md
new file mode 100644
index 0000000..ca9cf15
--- /dev/null
+++ b/docs/spp_vf/how_to_use.md
@@ -0,0 +1,105 @@
+# How to Use SPP_VF
+
+## SPP_VF
+
+SPP_VF is a SR-IOV like network functionality for NFV.
+
+![spp_vf_overview](spp_vf_overview.svg)
+
+## Environment
+
+* Ubuntu 16.04
+* qemu-kvm
+* DPDK v17.05
+
+## Launch SPP
+
+Before launching spp, you need to setup described as [setup guide](setup.md).
+
+### SPP Controller
+
+First, run SPP Controller with port numbers for spp primary and secondary.
+
+```sh
+$ python ./src/spp.py -p 5555 -s 6666
+```
+
+### SPP Primary
+
+SPP primary reserves and manages resources for secondary processes.
+You have to run it before secondaries.
+
+Options of spp primary are
+  * -p : port mask
+  * -n : number of rings
+  * -s : ip addr and port of spp primary
+
+```sh
+$ sudo ./src/primary/x86_64-native-linuxapp-gcc/spp_primary \
+-c 0x02 -n 4 --socket-mem 512,512 \
+--huge-dir=/run/hugepages/kvm \
+--proc-type=primary \
+-- -p 0x03 -n 9 -s 127.0.0.1:5555
+```
+
+### SPP Secondary
+
+In `spp_vf`, spp secondary processes are launched by single command.
+Core assingment and network configuration are defined
+in JSON formatted config file.
+If you run `spp_vf` without giving config file, it refers default
+config file (test/spp_config/spp_config/vf.json).
+
+```sh
+$ sudo ./src/vf/x86_64-native-linuxapp-gcc/spp_vf \
+-c 0x3ffd -n 4 --proc-type=secondary
+```
+
+You can also indicate which of config you use explicitly with
+`--config` option as following example.
+Please refer to sample config files in test/spp_config/spp_config.
+
+[NOTE] Core mask should be changed to correspond with core assingment
+defined in each of config files.
+
+```sh
+$ sudo ./src/vf/x86_64-native-linuxapp-gcc/spp_vf \
+-c 0x3ffd -n 4 --proc-type=secondary \
+-- --config /path/to/config/spp_vf1.json
+```
+
+### SPP VM
+
+Launch VMs with `virsh` command.
+
+```sh
+$ virsh start [VM]
+```
+
+### Additional Network Configurations
+
+To enable processes running on the VM to communicate through spp,
+it is required additional network configurations on host and guest VMss.
+
+#### Host1
+
+```sh
+# Interface for vhost
+$ sudo ifconfig [IF_NAME] inet [IP_ADDR] netmask [NETMASK] up
+
+# Register host2 to arp table
+$ sudo arp -s [IP_ADDR] [MAC_ADDR] -i [IF_NAME]
+
+# Disable offload for vhost interface
+$ sudo ethtool -K [IF_NAME] tx off
+```
+
+#### Host2
+
+```sh
+# Register VM to arp table
+$ sudo arp -s [IP_ADDR] [MAC_ADDR] -i [IF_NAME]
+
+# Disable offload for VM interface
+$ ethtool -K [IF_NAME] tx off
+```
diff --git a/docs/spp_vf/setup.md b/docs/spp_vf/setup.md
index 572777b..450e68a 100644
--- a/docs/spp_vf/setup.md
+++ b/docs/spp_vf/setup.md
@@ -168,6 +168,9 @@ Edit VM configuration with virsh.
 
 ```sh
 $ virsh edit [VM_NAME]
+```
+
+```xml
 <domain type='kvm' xmlns:qemu='http://libvirt.org/schemas/domain/qemu/1.0'>
 	  <name>spp-vm1</name>
 	  <uuid>d90f5420-861a-4479-8559-62d7a1545cb9</uuid>
diff --git a/docs/spp_vf/spp_vf_overview.svg b/docs/spp_vf/spp_vf_overview.svg
new file mode 100644
index 0000000..d0a6769
--- /dev/null
+++ b/docs/spp_vf/spp_vf_overview.svg
@@ -0,0 +1,793 @@
+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+<!-- Created with Inkscape (http://www.inkscape.org/) -->
+
+<svg
+   xmlns:dc="http://purl.org/dc/elements/1.1/"
+   xmlns:cc="http://creativecommons.org/ns#"
+   xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
+   xmlns:svg="http://www.w3.org/2000/svg"
+   xmlns="http://www.w3.org/2000/svg"
+   xmlns:xlink="http://www.w3.org/1999/xlink"
+   xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
+   xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
+   width="210mm"
+   height="297mm"
+   viewBox="0 0 744.09448819 1052.3622047"
+   id="svg2"
+   version="1.1"
+   inkscape:version="0.91 r13725"
+   sodipodi:docname="spp_vf_overview.svg">
+  <defs
+     id="defs4">
+    <marker
+       inkscape:isstock="true"
+       style="overflow:visible"
+       id="marker5641"
+       refX="0.0"
+       refY="0.0"
+       orient="auto"
+       inkscape:stockid="Arrow1Lstart">
+      <path
+         transform="scale(0.8) translate(12.5,0)"
+         style="fill-rule:evenodd;stroke:#000000;stroke-width:1pt;stroke-opacity:1;fill:#000000;fill-opacity:1"
+         d="M 0.0,0.0 L 5.0,-5.0 L -12.5,0.0 L 5.0,5.0 L 0.0,0.0 z "
+         id="path5643" />
+    </marker>
+    <marker
+       inkscape:stockid="Arrow1Lstart"
+       orient="auto"
+       refY="0.0"
+       refX="0.0"
+       id="marker5547"
+       style="overflow:visible"
+       inkscape:isstock="true"
+       inkscape:collect="always">
+      <path
+         id="path5549"
+         d="M 0.0,0.0 L 5.0,-5.0 L -12.5,0.0 L 5.0,5.0 L 0.0,0.0 z "
+         style="fill-rule:evenodd;stroke:#000000;stroke-width:1pt;stroke-opacity:1;fill:#000000;fill-opacity:1"
+         transform="scale(0.8) translate(12.5,0)" />
+    </marker>
+    <marker
+       inkscape:stockid="Arrow1Lstart"
+       orient="auto"
+       refY="0.0"
+       refX="0.0"
+       id="marker5465"
+       style="overflow:visible"
+       inkscape:isstock="true">
+      <path
+         id="path5467"
+         d="M 0.0,0.0 L 5.0,-5.0 L -12.5,0.0 L 5.0,5.0 L 0.0,0.0 z "
+         style="fill-rule:evenodd;stroke:#000000;stroke-width:1pt;stroke-opacity:1;fill:#000000;fill-opacity:1"
+         transform="scale(0.8) translate(12.5,0)" />
+    </marker>
+    <marker
+       inkscape:isstock="true"
+       style="overflow:visible;"
+       id="marker5365"
+       refX="0.0"
+       refY="0.0"
+       orient="auto"
+       inkscape:stockid="Arrow2Lend">
+      <path
+         transform="scale(1.1) rotate(180) translate(1,0)"
+         d="M 8.7185878,4.0337352 L -2.2072895,0.016013256 L 8.7185884,-4.0017078 C 6.9730900,-1.6296469 6.9831476,1.6157441 8.7185878,4.0337352 z "
+         style="fill-rule:evenodd;stroke-width:0.625;stroke-linejoin:round;stroke:#000000;stroke-opacity:1;fill:#000000;fill-opacity:1"
+         id="path5367" />
+    </marker>
+    <marker
+       inkscape:stockid="Arrow2Lend"
+       orient="auto"
+       refY="0.0"
+       refX="0.0"
+       id="Arrow2Lend"
+       style="overflow:visible;"
+       inkscape:isstock="true"
+       inkscape:collect="always">
+      <path
+         id="path4630"
+         style="fill-rule:evenodd;stroke-width:0.625;stroke-linejoin:round;stroke:#000000;stroke-opacity:1;fill:#000000;fill-opacity:1"
+         d="M 8.7185878,4.0337352 L -2.2072895,0.016013256 L 8.7185884,-4.0017078 C 6.9730900,-1.6296469 6.9831476,1.6157441 8.7185878,4.0337352 z "
+         transform="scale(1.1) rotate(180) translate(1,0)" />
+    </marker>
+    <marker
+       inkscape:stockid="Arrow1Lstart"
+       orient="auto"
+       refY="0.0"
+       refX="0.0"
+       id="Arrow1Lstart"
+       style="overflow:visible"
+       inkscape:isstock="true">
+      <path
+         id="path4609"
+         d="M 0.0,0.0 L 5.0,-5.0 L -12.5,0.0 L 5.0,5.0 L 0.0,0.0 z "
+         style="fill-rule:evenodd;stroke:#000000;stroke-width:1pt;stroke-opacity:1;fill:#000000;fill-opacity:1"
+         transform="scale(0.8) translate(12.5,0)" />
+    </marker>
+    <marker
+       inkscape:stockid="Arrow1Lend"
+       orient="auto"
+       refY="0.0"
+       refX="0.0"
+       id="marker5147"
+       style="overflow:visible;"
+       inkscape:isstock="true">
+      <path
+         id="path5149"
+         d="M 0.0,0.0 L 5.0,-5.0 L -12.5,0.0 L 5.0,5.0 L 0.0,0.0 z "
+         style="fill-rule:evenodd;stroke:#000000;stroke-width:1pt;stroke-opacity:1;fill:#000000;fill-opacity:1"
+         transform="scale(0.8) rotate(180) translate(12.5,0)" />
+    </marker>
+    <marker
+       inkscape:stockid="Arrow1Lend"
+       orient="auto"
+       refY="0.0"
+       refX="0.0"
+       id="marker5113"
+       style="overflow:visible;"
+       inkscape:isstock="true">
+      <path
+         id="path5115"
+         d="M 0.0,0.0 L 5.0,-5.0 L -12.5,0.0 L 5.0,5.0 L 0.0,0.0 z "
+         style="fill-rule:evenodd;stroke:#000000;stroke-width:1pt;stroke-opacity:1;fill:#000000;fill-opacity:1"
+         transform="scale(0.8) rotate(180) translate(12.5,0)" />
+    </marker>
+    <marker
+       inkscape:isstock="true"
+       style="overflow:visible;"
+       id="marker5009"
+       refX="0.0"
+       refY="0.0"
+       orient="auto"
+       inkscape:stockid="Arrow1Lend"
+       inkscape:collect="always">
+      <path
+         transform="scale(0.8) rotate(180) translate(12.5,0)"
+         style="fill-rule:evenodd;stroke:#000000;stroke-width:1pt;stroke-opacity:1;fill:#000000;fill-opacity:1"
+         d="M 0.0,0.0 L 5.0,-5.0 L -12.5,0.0 L 5.0,5.0 L 0.0,0.0 z "
+         id="path5011" />
+    </marker>
+    <marker
+       inkscape:stockid="Arrow1Lend"
+       orient="auto"
+       refY="0.0"
+       refX="0.0"
+       id="marker4963"
+       style="overflow:visible;"
+       inkscape:isstock="true"
+       inkscape:collect="always">
+      <path
+         id="path4965"
+         d="M 0.0,0.0 L 5.0,-5.0 L -12.5,0.0 L 5.0,5.0 L 0.0,0.0 z "
+         style="fill-rule:evenodd;stroke:#000000;stroke-width:1pt;stroke-opacity:1;fill:#000000;fill-opacity:1"
+         transform="scale(0.8) rotate(180) translate(12.5,0)" />
+    </marker>
+    <marker
+       inkscape:isstock="true"
+       style="overflow:visible;"
+       id="marker4923"
+       refX="0.0"
+       refY="0.0"
+       orient="auto"
+       inkscape:stockid="Arrow1Lend"
+       inkscape:collect="always">
+      <path
+         transform="scale(0.8) rotate(180) translate(12.5,0)"
+         style="fill-rule:evenodd;stroke:#000000;stroke-width:1pt;stroke-opacity:1;fill:#000000;fill-opacity:1"
+         d="M 0.0,0.0 L 5.0,-5.0 L -12.5,0.0 L 5.0,5.0 L 0.0,0.0 z "
+         id="path4925" />
+    </marker>
+    <marker
+       inkscape:stockid="Arrow1Lend"
+       orient="auto"
+       refY="0.0"
+       refX="0.0"
+       id="Arrow1Lend"
+       style="overflow:visible;"
+       inkscape:isstock="true"
+       inkscape:collect="always">
+      <path
+         id="path4612"
+         d="M 0.0,0.0 L 5.0,-5.0 L -12.5,0.0 L 5.0,5.0 L 0.0,0.0 z "
+         style="fill-rule:evenodd;stroke:#000000;stroke-width:1pt;stroke-opacity:1;fill:#000000;fill-opacity:1"
+         transform="scale(0.8) rotate(180) translate(12.5,0)" />
+    </marker>
+    <marker
+       inkscape:stockid="Arrow2Mend"
+       orient="auto"
+       refY="0.0"
+       refX="0.0"
+       id="Arrow2Mend"
+       style="overflow:visible;"
+       inkscape:isstock="true">
+      <path
+         id="path4636"
+         style="fill-rule:evenodd;stroke-width:0.625;stroke-linejoin:round;stroke:#000000;stroke-opacity:1;fill:#000000;fill-opacity:1"
+         d="M 8.7185878,4.0337352 L -2.2072895,0.016013256 L 8.7185884,-4.0017078 C 6.9730900,-1.6296469 6.9831476,1.6157441 8.7185878,4.0337352 z "
+         transform="scale(0.6) rotate(180) translate(0,0)" />
+    </marker>
+  </defs>
+  <sodipodi:namedview
+     id="base"
+     pagecolor="#ffffff"
+     bordercolor="#666666"
+     borderopacity="1.0"
+     inkscape:pageopacity="0.0"
+     inkscape:pageshadow="2"
+     inkscape:zoom="0.49497475"
+     inkscape:cx="123.1929"
+     inkscape:cy="463.15501"
+     inkscape:document-units="px"
+     inkscape:current-layer="layer2"
+     showgrid="false"
+     inkscape:window-width="1331"
+     inkscape:window-height="840"
+     inkscape:window-x="255"
+     inkscape:window-y="0"
+     inkscape:window-maximized="0" />
+  <metadata
+     id="metadata7">
+    <rdf:RDF>
+      <cc:Work
+         rdf:about="">
+        <dc:format>image/svg+xml</dc:format>
+        <dc:type
+           rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
+        <dc:title />
+      </cc:Work>
+    </rdf:RDF>
+  </metadata>
+  <g
+     inkscape:groupmode="layer"
+     id="layer2"
+     inkscape:label="host"
+     style="display:inline">
+    <rect
+       id="rect3397"
+       width="515.59247"
+       height="371.01962"
+       x="199.04526"
+       y="-494.46774"
+       rx="0"
+       ry="0"
+       style="fill:#f9f9f9;stroke:#000000;stroke-width:1;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
+       transform="scale(1,-1)" />
+    <image
+       y="188.82965"
+       x="199.5847"
+       id="image4253"
+       xlink:href="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAACQAAAAkCAYAAADhAJiYAAAABHNCSVQICAgIfAhkiAAAAJdJREFU WIXtzrEJwkAYBeB33pFOd7CQ4AwSwSLgMIcoOIe9jQtIIDiArQppHOEC4gjpPHubV/4W75vgc9NF lV05h7WhT4ir5TZ8ZiXS4Wj9gb80eN2vk5F15JdCjEKMQoxCjEKMQoxCjEKMQoxCjEKMQoxCjEKM QszfhcLQJ6A9Wz+A7gHvfQ77db15P29j648rXI5xd/oCgL0bFKgMdsQAAAAASUVORK5CYII= "
+       style="fill:#ffff00;fill-opacity:1;stroke:#000000;stroke-opacity:1;image-rendering:optimizeSpeed"
+       preserveAspectRatio="none"
+       height="29.383257"
+       width="32.579395" />
+    <image
+       y="397.5441"
+       x="198.29185"
+       id="image4273"
+       xlink:href="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAACQAAAAkCAIAAABuYg/PAAAAA3NCSVQICAjb4U/gAAAAbUlEQVRI iWNUtLZlVNdkoDH4/ujhxrZmln+q6g/7ZtLaMuZNa9+8ecNEa2uQwahlo5aNWjZq2ahlo5aNWjZq 2ahlo5aNWjZq2ahlOAHL90cPGTasprk9Z04y+bgynj179t27d7S2i5GR0cHBAQDdpBlSwJ9IHwAA AABJRU5ErkJggg== "
+       style="fill:#ffff00;fill-opacity:1;stroke:#000000;stroke-opacity:1;image-rendering:optimizeSpeed"
+       preserveAspectRatio="none"
+       height="29.383257"
+       width="32.579395" />
+    <image
+       y="670.39264"
+       x="208.19046"
+       id="image4254"
+       xlink:href="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAgUAAAF0CAYAAACzCkr0AAAABHNCSVQICAgIfAhkiAAABixJREFU
+eJzt1jGRmgEABtElc9j4W3xQIBIfEYEBZKS4juKGNJ8HMpP3FGy5p/P5/D6OIwDg//T9/d3tdvv9
+dRxHz+fz0z0AwIfc7/cej8fp16dDAIB/gykAACpTAACMKQAAKlMAAIwpAAAqUwAAjCkAACpTAACM
+KQAAKlMAAIwpAAAqUwAAjCkAACpTAACMKQAAKlMAAIwpAAAqUwAAjCkAACpTAACMKQAAKlMAAIwp
+AAAqUwAAjCkAACpTAACMKQAAKlMAAIwpAAAqUwAAjCkAACpTAACMKQAAKlMAAIwpAAAqUwAAjCkA
+ACpTAACMKQAAKlMAAIwpAAAqUwAAjCkAACpTAACMKQAAKlMAAIwpAAAqUwAAjCkAACpTAACMKQAA
+KlMAAIwpAAAqUwAAjCkAACpTAACMKQAAKlMAAIwpAAAqUwAAjCkAACpTAACMKQAAKlMAAIwpAAAq
+UwAAjCkAACpTAACMKQAAKlMAAIwpAAAqUwAAjCkAACpTAACMKQAAKlMAAIwpAAAqUwAAjCkAACpT
+AACMKQAAKlMAAIwpAAAqUwAAjCkAACpTAACMKQAAKlMAAIwpAAAqUwAAjCkAACpTAACMKQAAKlMA
+AIwpAAAqUwAAjCkAACpTAACMKQAAKlMAAIwpAAAqUwAAjCkAACpTAACMKQAAKlMAAIwpAAAqUwAA
+jCkAACpTAACMKQAAKlMAAIwpAAAqUwAAjCkAACpTAACMKQAAKlMAAIwpAAAqUwAAjCkAACpTAACM
+KQAAKlMAAIwpAAAqUwAAjCkAACpTAACMKQAAKlMAAIwpAAAqUwAAjCkAACpTAACMKQAAKlMAAIwp
+AAAqUwAAjCkAACpTAACMKQAAKlMAAIwpAAAqUwAAjCkAACpTAACMKQAAKlMAAIwpAAAqUwAAjCkA
+ACpTAACMKQAAKlMAAIwpAAAqUwAAjCkAACpTAACMKQAAKlMAAIwpAAAqUwAAjCkAACpTAACMKQAA
+KlMAAIwpAAAqUwAAjCkAACpTAACMKQAAKlMAAIwpAAAqUwAAjCkAACpTAACMKQAAKlMAAIwpAAAq
+UwAAjCkAACpTAACMKQAAKlMAAIwpAAAqUwAAjCkAACpTAACMKQAAKlMAAIwpAAAqUwAAjCkAACpT
+AACMKQAAKlMAAIwpAAAqUwAAjCkAACpTAACMKQAAKlMAAIwpAAAqUwAAjCkAACpTAACMKQAAKlMA
+AIwpAAAqUwAAjCkAACpTAACMKQAAKlMAAIwpAAAqUwAAjCkAACpTAACMKQAAKlMAAIwpAAAqUwAA
+jCkAACpTAACMKQAAKlMAAIwpAAAqUwAAjCkAACpTAACMKQAAKlMAAIwpAAAqUwAAjCkAACpTAACM
+KQAAKlMAAIwpAAAqUwAAjCkAACpTAACMKQAAKlMAAIwpAAAqUwAAjCkAACpTAACMKQAAKlMAAIwp
+AAAqUwAAjCkAACpTAACMKQAAKlMAAIwpAAAqUwAAjCkAACpTAACMKQAAKlMAAIwpAAAqUwAAjCkA
+ACpTAACMKQAAKlMAAIwpAAAqUwAAjCkAACpTAACMKQAAKlMAAIwpAAAqUwAAjCkAACpTAACMKQAA
+KlMAAIwpAAAqUwAAjCkAACpTAACMKQAAKlMAAIwpAAAqUwAAjCkAACpTAACMKQAAKlMAAIwpAAAq
+UwAAjCkAACpTAACMKQAAKlMAAIwpAAAqUwAAjCkAACpTAACMKQAAKlMAAIwpAAAqUwAAjCkAACpT
+AACMKQAAKlMAAIwpAAAqUwAAjCkAACpTAACMKQAAKlMAAIwpAAAqUwAAjCkAACpTAACMKQAAKlMA
+AIwpAAAqUwAAjCkAACpTAACMKQAAKlMAAIwpAAAqUwAAjCkAACpTAACMKQAAKlMAAIwpAAAqUwAA
+jCkAACpTAACMKQAAKlMAAIwpAAAqUwAAjCkAACpTAACMKQAAKlMAAIwpAAAqUwAAjCkAACpTAACM
+KQAAKlMAAIwpAAAqUwAAjCkAACpTAACMKQAAKlMAAIwpAAAqUwAAjCkAACpTAACMKQAAKlMAAIwp
+AAAqUwAAjCkAACpTAADM1+v1+rlcLqdPhwAAn/F+v7ter3/+At56GMaw9bmuAAAAAElFTkSuQmCC
+
+"
+       style="stroke:#000000;stroke-width:1;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1;image-rendering:optimizeSpeed"
+       preserveAspectRatio="none"
+       height="232.59895"
+       width="498.81723" />
+    <image
+       y="728.25555"
+       x="207.75386"
+       id="image4294"
+       xlink:href="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAACEAAAAeCAYAAACiyHcXAAAABHNCSVQICAgIfAhkiAAAAIRJREFU
+SIljVLS2/c+orskwEOD7o4cMC8uKj7D8U1VneNg3c0AcwbxpLcOLFy9YmQbEdjQw6ggYGHUEDIw6
+AgZGHQEDo46AgVFHwMCoI2Bg1BEwMOoIGBh1BAyMOgIGRh0BA4PCESzfHz1kYNiwemBsP3OSgcnC
+kIHx////SQPjAji4BgCwERjrIQkp5wAAAABJRU5ErkJggg==
+"
+       style="image-rendering:optimizeSpeed"
+       preserveAspectRatio="none"
+       height="30"
+       width="33" />
+    <image
+       y="829.27075"
+       x="207.75388"
+       id="image4314"
+       xlink:href="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAACEAAAAeCAYAAACiyHcXAAAABHNCSVQICAgIfAhkiAAAAH5JREFU
+SIntzqENhEAYROFZoBEEIVfDBYm7KmiFBImnhgvJQRckaPyi1+NY1CCugR8xXwPvufxdRVe+YOHY
+PaauRXYWJXw/mEyk84gQAhKT+h9NkCZIE6QJ0gRpgjRBmiBNkCZIE6QJesREduwe+H1t6uuC5FPD
+xRgbm4PbdgF0sBiGQ2sxrAAAAABJRU5ErkJggg==
+"
+       style="image-rendering:optimizeSpeed"
+       preserveAspectRatio="none"
+       height="30"
+       width="33" />
+    <path
+       style="fill:none;fill-rule:evenodd;stroke:#000000;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
+       d="M 208.09142,741.23523 C 175.04704,701.33452 142.10284,661.21343 135.36044,563.44837 135.73123,495.86243 158.93068,440.2096 197.9899,411.92549"
+       id="path4317"
+       inkscape:connector-curvature="0"
+       sodipodi:nodetypes="ccc" />
+    <path
+       style="fill:none;fill-rule:evenodd;stroke:#000000;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
+       d="M 195.96959,211.91529 C 90.766866,304.85183 82.207898,365.56976 74.751289,533.14379 80.131674,656.66835 90.106723,745.84772 207.75388,849.16922"
+       id="path4339"
+       inkscape:connector-curvature="0"
+       sodipodi:nodetypes="ccc" />
+    <path
+       style="fill:#ffff00;fill-opacity:1;stroke:#000000;stroke-width:1;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
+       d="m 200.36855,202.93062 0,-13.13199 15.15229,0 15.15229,0 0,13.13199 0,13.13198 -15.15229,0 -15.15229,0 0,-13.13198 z"
+       id="path4365"
+       inkscape:connector-curvature="0" />
+    <path
+       style="fill:#ffff00;fill-opacity:1;stroke:#000000;stroke-width:1;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
+       d="m 198.34825,412.03219 0,-14.14213 15.15228,0 15.15229,0 0,14.14213 0,14.14214 -15.15229,0 -15.15228,0 0,-14.14214 z"
+       id="path4367"
+       inkscape:connector-curvature="0" />
+    <path
+       style="fill:#ffff00;fill-opacity:1;stroke:#000000;stroke-width:1;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
+       d="m 208.44977,742.35208 0,-13.13199 15.15229,0 15.15229,0 0,13.13199 0,13.13198 -15.15229,0 -15.15229,0 0,-13.13198 z"
+       id="path4371"
+       inkscape:connector-curvature="0" />
+    <path
+       style="fill:#ffff00;fill-opacity:1;stroke:#000000;stroke-width:1;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
+       d="m 208.44977,843.36733 0,-13.13198 15.15229,0 15.15229,0 0,13.13198 0,13.13198 -15.15229,0 -15.15229,0 0,-13.13198 z"
+       id="path4373"
+       inkscape:connector-curvature="0" />
+    <text
+       xml:space="preserve"
+       style="font-style:normal;font-weight:normal;font-size:17.5px;line-height:125%;font-family:sans-serif;letter-spacing:0px;word-spacing:0px;fill:#000000;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
+       x="214.07114"
+       y="698.42303"
+       id="text4427"
+       sodipodi:linespacing="125%"><tspan
+         sodipodi:role="line"
+         id="tspan4429"
+         x="214.07114"
+         y="698.42303">host2</tspan></text>
+    <text
+       xml:space="preserve"
+       style="font-style:normal;font-weight:normal;font-size:17.5px;line-height:125%;font-family:sans-serif;letter-spacing:0px;word-spacing:0px;fill:#000000;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
+       x="203.96959"
+       y="144.92035"
+       id="text4431"
+       sodipodi:linespacing="125%"><tspan
+         sodipodi:role="line"
+         id="tspan4433"
+         x="203.96959"
+         y="144.92035">host1</tspan></text>
+    <text
+       xml:space="preserve"
+       style="font-style:normal;font-weight:normal;font-size:17.5px;line-height:125%;font-family:sans-serif;letter-spacing:0px;word-spacing:0px;fill:#000000;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
+       x="209.5847"
+       y="208.82965"
+       id="text4435"
+       sodipodi:linespacing="125%"><tspan
+         sodipodi:role="line"
+         id="tspan4437"
+         x="209.5847"
+         y="208.82965">rx</tspan></text>
+    <text
+       xml:space="preserve"
+       style="font-style:normal;font-weight:normal;font-size:17.5px;line-height:125%;font-family:sans-serif;letter-spacing:0px;word-spacing:0px;fill:#000000;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
+       x="204.05083"
+       y="420.00671"
+       id="text4439"
+       sodipodi:linespacing="125%"><tspan
+         sodipodi:role="line"
+         id="tspan4441"
+         x="204.05083"
+         y="420.00671">tx</tspan></text>
+    <rect
+       style="fill:#ffeeaa;fill-opacity:1;stroke:#000000;stroke-width:1;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
+       id="rect4445"
+       width="139.40105"
+       height="121.21831"
+       x="28.284271"
+       y="494.758" />
+    <text
+       xml:space="preserve"
+       style="font-style:normal;font-weight:normal;font-size:22.39949417px;line-height:125%;font-family:sans-serif;letter-spacing:0px;word-spacing:0px;fill:#000000;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
+       x="48.699158"
+       y="555.4043"
+       id="text4455"
+       sodipodi:linespacing="125%"
+       transform="scale(0.985853,1.01435)"><tspan
+         sodipodi:role="line"
+         id="tspan4457"
+         x="48.699158"
+         y="555.4043">network</tspan></text>
+    <text
+       xml:space="preserve"
+       style="font-style:normal;font-weight:normal;font-size:17.5px;line-height:125%;font-family:sans-serif;letter-spacing:0px;word-spacing:0px;fill:#000000;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
+       x="212.13203"
+       y="743.25549"
+       id="text4459"
+       sodipodi:linespacing="125%"><tspan
+         sodipodi:role="line"
+         id="tspan4461"
+         x="212.13203"
+         y="743.25549">rx</tspan></text>
+    <text
+       xml:space="preserve"
+       style="font-style:normal;font-weight:normal;font-size:17.5px;line-height:125%;font-family:sans-serif;letter-spacing:0px;word-spacing:0px;fill:#000000;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
+       x="214.15234"
+       y="848.3114"
+       id="text4463"
+       sodipodi:linespacing="125%"><tspan
+         sodipodi:role="line"
+         id="tspan4465"
+         x="214.15234"
+         y="848.3114">tx</tspan></text>
+  </g>
+  <g
+     inkscape:groupmode="layer"
+     id="layer4"
+     inkscape:label="guests"
+     style="display:inline"
+     sodipodi:insensitive="true">
+    <rect
+       style="fill:#ececec;fill-opacity:1;stroke:#000000;stroke-width:0.74355245;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
+       id="rect4385"
+       width="155.18895"
+       height="272.38342"
+       x="544.70715"
+       y="193.82353" />
+    <rect
+       style="fill:#ffff00;fill-opacity:1;stroke:#000000;stroke-width:0.85944676;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
+       id="rect4387"
+       width="31.027994"
+       height="27.984053"
+       x="546.06403"
+       y="243.84534" />
+    <rect
+       style="fill:#ffff00;fill-opacity:1;stroke:#000000;stroke-width:0.85944676;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
+       id="rect4389"
+       width="32.320827"
+       height="27.984053"
+       x="546.06403"
+       y="281.98343" />
+    <rect
+       style="fill:#ffff00;fill-opacity:1;stroke:#000000;stroke-width:0.85944676;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
+       id="rect4391"
+       width="32.320827"
+       height="29.150057"
+       x="546.06403"
+       y="356.95554" />
+    <rect
+       style="fill:#ffff00;fill-opacity:1;stroke:#000000;stroke-width:0.85944676;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
+       id="rect4393"
+       width="34.906494"
+       height="26.818052"
+       x="544.77112"
+       y="397.75766" />
+    <text
+       xml:space="preserve"
+       style="font-style:normal;font-weight:normal;font-size:19.04654694px;line-height:125%;font-family:sans-serif;letter-spacing:0px;word-spacing:0px;fill:#000000;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
+       x="558.37213"
+       y="210.79575"
+       id="text4395"
+       sodipodi:linespacing="125%"
+       transform="scale(0.98137951,1.0189738)"><tspan
+         sodipodi:role="line"
+         id="tspan4397"
+         x="558.37213"
+         y="210.79575">guest</tspan></text>
+    <rect
+       style="fill:none;fill-opacity:1;stroke:#000000;stroke-width:1;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
+       id="rect4375"
+       width="48.773148"
+       height="81.09803"
+       x="539.2785"
+       y="236.01605" />
+    <rect
+       style="fill:#cccccc;fill-opacity:0;stroke:#000000;stroke-width:1;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
+       id="rect4397"
+       width="46.589622"
+       height="82.955116"
+       x="539.38049"
+       y="349.23471" />
+    <text
+       xml:space="preserve"
+       style="font-style:normal;font-weight:normal;font-size:17.5px;line-height:125%;font-family:sans-serif;letter-spacing:0px;word-spacing:0px;fill:#000000;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
+       x="551.50269"
+       y="258.30109"
+       id="text4399"
+       sodipodi:linespacing="125%"><tspan
+         sodipodi:role="line"
+         id="tspan4401"
+         x="551.50269"
+         y="258.30109">rx</tspan></text>
+    <text
+       xml:space="preserve"
+       style="font-style:normal;font-weight:normal;font-size:17.5px;line-height:125%;font-family:sans-serif;letter-spacing:0px;word-spacing:0px;fill:#000000;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
+       x="551.54327"
+       y="298.78842"
+       id="text4403"
+       sodipodi:linespacing="125%"><tspan
+         sodipodi:role="line"
+         id="tspan4405"
+         x="551.54327"
+         y="298.78842">tx</tspan></text>
+    <text
+       xml:space="preserve"
+       style="font-style:normal;font-weight:normal;font-size:17.5px;line-height:125%;font-family:sans-serif;letter-spacing:0px;word-spacing:0px;fill:#000000;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
+       x="549.52295"
+       y="375.56"
+       id="text4407"
+       sodipodi:linespacing="125%"><tspan
+         sodipodi:role="line"
+         id="tspan4409"
+         x="549.52295"
+         y="375.56">rx</tspan></text>
+    <text
+       xml:space="preserve"
+       style="font-style:normal;font-weight:normal;font-size:17.5px;line-height:125%;font-family:sans-serif;letter-spacing:0px;word-spacing:0px;fill:#000000;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
+       x="551.54327"
+       y="415.96606"
+       id="text4411"
+       sodipodi:linespacing="125%"><tspan
+         sodipodi:role="line"
+         id="tspan4413"
+         x="551.54327"
+         y="415.96606">tx</tspan></text>
+    <text
+       xml:space="preserve"
+       style="font-style:normal;font-weight:normal;font-size:17.5px;line-height:125%;font-family:sans-serif;letter-spacing:0px;word-spacing:0px;fill:#000000;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
+       x="594.03064"
+       y="266.46353"
+       id="text4415"
+       sodipodi:linespacing="125%"><tspan
+         sodipodi:role="line"
+         id="tspan4417"
+         x="594.03064"
+         y="266.46353">vNIC</tspan><tspan
+         sodipodi:role="line"
+         x="594.03064"
+         y="288.33853"
+         id="tspan4425">(vhost)</tspan></text>
+    <text
+       xml:space="preserve"
+       style="font-style:normal;font-weight:normal;font-size:17.5px;line-height:125%;font-family:sans-serif;letter-spacing:0px;word-spacing:0px;fill:#000000;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
+       x="596.07123"
+       y="381.62091"
+       id="text4419"
+       sodipodi:linespacing="125%"><tspan
+         sodipodi:role="line"
+         id="tspan4421"
+         x="596.07123"
+         y="381.62091">vNIC</tspan><tspan
+         sodipodi:role="line"
+         x="596.07123"
+         y="403.49591"
+         id="tspan4423">(vhost)</tspan></text>
+  </g>
+  <g
+     inkscape:groupmode="layer"
+     id="layer3"
+     inkscape:label="spp_vf_process"
+     style="display:inline"
+     sodipodi:insensitive="true">
+    <rect
+       style="fill:#f4e3d7;fill-opacity:1;stroke:#000000;stroke-width:0.87971044;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
+       id="rect4399"
+       width="223.64525"
+       height="265.71939"
+       x="277.04822"
+       y="179.91371"
+       ry="13.91201"
+       rx="10.217305" />
+    <text
+       xml:space="preserve"
+       style="font-style:normal;font-weight:normal;font-size:17.5px;line-height:125%;font-family:sans-serif;letter-spacing:0px;word-spacing:0px;fill:#000000;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
+       x="292.96454"
+       y="203.81377"
+       id="text5769"
+       sodipodi:linespacing="125%"><tspan
+         sodipodi:role="line"
+         id="tspan5771"
+         x="292.96454"
+         y="203.81377">spp_vf</tspan></text>
+  </g>
+  <g
+     inkscape:label="spp_vf_threads"
+     inkscape:groupmode="layer"
+     id="layer1"
+     style="display:inline"
+     sodipodi:insensitive="true">
+    <rect
+       style="fill:#ffeeaa;fill-opacity:1;fill-rule:evenodd;stroke:#000000;stroke-width:1.056795;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
+       id="rect3338"
+       width="88.294899"
+       height="41.616783"
+       x="291.37378"
+       y="228.27687"
+       rx="14.345392"
+       ry="8.049448" />
+    <path
+       style="fill:#ffeeaa;fill-opacity:1;stroke:#000000;stroke-width:1.00371253;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
+       d="m 300.46715,378.46629 c -4.32888,-2.69254 -5.14237,-5.33087 -5.14237,-16.678 0,-18.70818 -0.47456,-18.50573 43.37958,-18.50573 24.02629,0 36.284,0.61286 38.38411,1.91912 1.97847,1.23059 3.08541,7.52178 3.08541,17.53559 0,13.80279 -0.5776,15.80876 -4.97333,17.27202 -2.73534,0.91054 -19.51231,1.65552 -37.28218,1.65552 -28.8806,0 -32.8545,-0.33939 -37.45122,-3.19852 z"
+       id="path4551"
+       inkscape:connector-curvature="0" />
+    <path
+       style="fill:#ffeeaa;fill-opacity:1;stroke:#000000;stroke-width:1;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
+       d="m 423.06161,258.14039 c -3.47945,-3.47946 -3.22798,-24.79967 0.32732,-27.75031 1.88343,-1.5631 11.35671,-2.1431 28.78935,-1.7626 l 25.98222,0.5671 0,15.15229 0,15.15229 -26.30954,0.56052 c -18.74837,0.39942 -27.02222,-0.15217 -28.78935,-1.91929 z"
+       id="path4553"
+       inkscape:connector-curvature="0" />
+    <path
+       style="fill:#ffeeaa;fill-opacity:1;stroke:#000000;stroke-width:1;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
+       d="m 423.00617,302.53166 c -3.14772,-3.14772 -3.14772,-24.32844 0,-27.47615 2.54806,-2.54806 46.84009,-3.54987 52.96879,-1.19806 4.63563,1.77886 4.63563,28.09341 0,29.87227 -6.1287,2.3518 -50.42073,1.34999 -52.96879,-1.19806 z"
+       id="path4555"
+       inkscape:connector-curvature="0" />
+    <path
+       style="fill:#ffeeaa;fill-opacity:1;stroke:#000000;stroke-width:1;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
+       d="m 423.08192,351.07442 c -3.1916,-3.19159 -3.23421,-24.35282 -0.0554,-27.53158 2.80195,-2.80196 49.46626,-3.40751 53.73879,-0.69736 1.84322,1.1692 2.44496,5.8234 2.02031,15.62643 l -0.60478,13.96129 -26.30954,0.56051 c -18.74837,0.39943 -27.02222,-0.15217 -28.78934,-1.91929 z"
+       id="path4557"
+       inkscape:connector-curvature="0" />
+    <path
+       style="fill:#ffeeaa;fill-opacity:1;stroke:#000000;stroke-width:1;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
+       d="m 425.04678,399.5063 c -3.43282,-3.43282 -3.13788,-24.77299 0.38276,-27.69486 1.88343,-1.56311 11.35671,-2.1431 28.78935,-1.7626 l 25.98222,0.5671 0.60477,13.96129 c 0.42465,9.80303 -0.17708,14.45723 -2.0203,15.62642 -4.27253,2.71016 -50.93684,2.10461 -53.7388,-0.69735 z"
+       id="path4559"
+       inkscape:connector-curvature="0" />
+    <text
+       xml:space="preserve"
+       style="font-style:normal;font-weight:normal;font-size:17.5px;line-height:125%;font-family:sans-serif;letter-spacing:0px;word-spacing:0px;fill:#000000;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
+       x="296.98483"
+       y="252.3214"
+       id="text4561"
+       sodipodi:linespacing="125%"><tspan
+         sodipodi:role="line"
+         id="tspan4563"
+         x="296.98483"
+         y="252.3214">classifier</tspan></text>
+    <text
+       xml:space="preserve"
+       style="font-style:normal;font-weight:normal;font-size:17.5px;line-height:125%;font-family:sans-serif;letter-spacing:0px;word-spacing:0px;fill:#000000;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
+       x="304.98483"
+       y="365.4585"
+       id="text4565"
+       sodipodi:linespacing="125%"><tspan
+         sodipodi:role="line"
+         id="tspan4567"
+         x="304.98483"
+         y="365.4585">merger</tspan></text>
+    <text
+       xml:space="preserve"
+       style="font-style:normal;font-weight:normal;font-size:17.5px;line-height:125%;font-family:sans-serif;letter-spacing:0px;word-spacing:0px;fill:#000000;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
+       x="436.42651"
+       y="246.17924"
+       id="text4569"
+       sodipodi:linespacing="125%"><tspan
+         sodipodi:role="line"
+         id="tspan4571"
+         x="436.42651"
+         y="246.17924">fwd</tspan></text>
+    <text
+       xml:space="preserve"
+       style="font-style:normal;font-weight:normal;font-size:17.5px;line-height:125%;font-family:sans-serif;letter-spacing:0px;word-spacing:0px;fill:#000000;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
+       x="436.42651"
+       y="290.64627"
+       id="text4573"
+       sodipodi:linespacing="125%"><tspan
+         sodipodi:role="line"
+         id="tspan4575"
+         x="436.42651"
+         y="290.64627">fwd</tspan></text>
+    <text
+       xml:space="preserve"
+       style="font-style:normal;font-weight:normal;font-size:17.5px;line-height:125%;font-family:sans-serif;letter-spacing:0px;word-spacing:0px;fill:#000000;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
+       x="436.40619"
+       y="343.19452"
+       id="text4577"
+       sodipodi:linespacing="125%"><tspan
+         sodipodi:role="line"
+         id="tspan4579"
+         x="436.40619"
+         y="343.19452">fwd</tspan></text>
+    <text
+       xml:space="preserve"
+       style="font-style:normal;font-weight:normal;font-size:17.5px;line-height:125%;font-family:sans-serif;letter-spacing:0px;word-spacing:0px;fill:#000000;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
+       x="436.42651"
+       y="393.6412"
+       id="text4581"
+       sodipodi:linespacing="125%"><tspan
+         sodipodi:role="line"
+         id="tspan4583"
+         x="436.42651"
+         y="393.6412">fwd</tspan></text>
+    <path
+       style="fill:none;fill-rule:evenodd;stroke:#000000;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;marker-end:url(#marker5365)"
+       d="m 232.1641,200.95148 60.78014,49.34961"
+       id="path4585"
+       inkscape:connector-curvature="0"
+       sodipodi:nodetypes="cc" />
+    <path
+       style="fill:none;fill-rule:evenodd;stroke:#000000;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;marker-start:url(#marker5641)"
+       d="m 230.87125,409.66593 64.09329,-48.24807"
+       id="path4587"
+       inkscape:connector-curvature="0"
+       sodipodi:nodetypes="cc" />
+    <path
+       style="fill:none;fill-rule:evenodd;stroke:#000000;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;marker-end:url(#Arrow2Lend)"
+       d="M 545.48238,294.7478 476.792,288.68688"
+       id="path4589"
+       inkscape:connector-curvature="0"
+       sodipodi:nodetypes="cc" />
+    <path
+       style="fill:none;fill-rule:evenodd;stroke:#000000;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;marker-end:url(#marker5009)"
+       d="m 474.7717,339.19451 66.67007,30.30458"
+       id="path4591"
+       inkscape:connector-curvature="0"
+       sodipodi:nodetypes="cc" />
+    <path
+       style="fill:none;fill-rule:evenodd;stroke:#000000;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;marker-start:url(#Arrow1Lstart)"
+       d="m 480.83262,383.64122 64.64975,28.28427"
+       id="path4593"
+       inkscape:connector-curvature="0"
+       sodipodi:nodetypes="cc" />
+    <path
+       style="fill:none;fill-rule:evenodd;stroke:#000000;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;marker-end:url(#marker4963)"
+       d="m 478.81231,244.24016 66.67007,10.10154"
+       id="path4595"
+       inkscape:connector-curvature="0"
+       sodipodi:nodetypes="cc" />
+    <path
+       style="fill:none;fill-rule:evenodd;stroke:#000000;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;marker-end:url(#Arrow1Lend)"
+       d="m 377.79705,248.28078 42.42641,-6.06091"
+       id="path4597"
+       inkscape:connector-curvature="0"
+       sodipodi:nodetypes="cc" />
+    <path
+       style="fill:none;fill-rule:evenodd;stroke:#000000;stroke-width:0.9164362px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;marker-end:url(#marker4923)"
+       d="m 377.75479,246.23771 42.51093,90.95926"
+       id="path4599"
+       inkscape:connector-curvature="0"
+       sodipodi:nodetypes="cc" />
+    <path
+       style="fill:none;fill-rule:evenodd;stroke:#000000;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;marker-start:url(#marker5465)"
+       d="m 379.79706,363.43817 40.40609,-74.75129"
+       id="path4601"
+       inkscape:connector-curvature="0"
+       sodipodi:nodetypes="cc" />
+    <path
+       style="fill:none;fill-rule:evenodd;stroke:#000000;stroke-width:1.15162241px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;marker-start:url(#marker5547)"
+       d="m 377.82552,361.46823 48.43039,24.14292"
+       id="path4603"
+       inkscape:connector-curvature="0"
+       sodipodi:nodetypes="cc" />
+  </g>
+</svg>
-- 
1.9.1

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

* [spp] [PATCH 03/30] doc: add config_manual.md
  2018-01-15 11:04 ` [spp] Proposal - spp_vf(SR-IOV like feature) addition to SPP Ferruh Yigit
  2018-01-16  5:16   ` [spp] [PATCH 01/30] doc: add setup guide x-fn-spp
  2018-01-16  5:16   ` [spp] [PATCH 02/30] doc: add how_to_use.md x-fn-spp
@ 2018-01-16  5:16   ` x-fn-spp
  2018-01-16  5:16   ` [spp] [PATCH 04/30] doc: add spp_vf.md x-fn-spp
                     ` (26 subsequent siblings)
  29 siblings, 0 replies; 97+ messages in thread
From: x-fn-spp @ 2018-01-16  5:16 UTC (permalink / raw)
  To: spp

From: Hiroyuki Nakamura <nakamura.hioryuki@po.ntt-tx.co.jp>

config_manual.md is a detailed manual for JSON config file.

Signed-off-by: Naoki Takada <takada.naoki@lab.ntt.co.jp>
---
 docs/spp_vf/config_manual.md | 214 +++++++++++++++++++++++++++++++++++++++++++
 1 file changed, 214 insertions(+)
 create mode 100644 docs/spp_vf/config_manual.md

diff --git a/docs/spp_vf/config_manual.md b/docs/spp_vf/config_manual.md
new file mode 100644
index 0000000..370dfdb
--- /dev/null
+++ b/docs/spp_vf/config_manual.md
@@ -0,0 +1,214 @@
+# SPP_VF Config Manual
+
+## Forwarder Type
+
+There are three types of forwarder for 1:1, 1:N and N:1.
+
+  * forward: 1:1
+  * classifier_mac: 1:N (Destination is determined by MAC address)
+  * merge: N:1
+
+### Restrictions
+
+  * Different types of forwarder cannot assing on same core.
+  * Only one classifier_mac is allowed (Cannot use two or more).
+
+## Port Type
+
+There are three port types.
+
+  * nic: Physical NIC
+  * vhost: Vhost PMD for VMs
+  * ring: Ring PMD for spp components
+
+Each of ports is identified as resource ID with port type and resource ID.
+For example, resource ID of physical NIC of ID 0 is described as `nic0`.
+
+## Config Format
+
+Config files is described in JSON format.
+It consists of `vfs` and `classifier_table`.
+`vfs` defines each of spp_vf attributes and
+`classifier_table` defines MAC address and correnpond port for
+determining destination.
+
+### Attributes in Config
+
+  * vfs
+    * name: Name of spp_vf component.
+    * num_vhost: Number of vhosts spp_vf use.
+    * num_ring: Number of rings spp_vf use.
+    * functions: List of forwarders and its attributes (function means a forwarder).
+      * core: Core ID forwarder running on.
+      * type: Forwarder type (`forward`, `classifier_mac`, or `merger`).
+      * rx_port: Resource ID(s) of rx port.
+      * tx_port: Resource ID of tx port. If 1:N, which means the dest is `classifier_mac`,
+                 directly described as `classifier_mac_table`.
+
+  * classifier_table
+    * name: Table name for classifier_mac, It MUST be "classifier_mac_table" in current implementation
+    * table: Set of MAC address and port for destination
+      * mac: MAC address
+      * port: Resource ID of port
+
+## Sample Config
+
+Here is default config `spp.json` and network diagram of it.
+
+```json
+{
+  "vfs": [
+    {
+      "name": "vf0",
+      "num_vhost": 4,  // Number of vhosts
+      "num_ring": 9,   // Number of rings
+      "functions":[    // Attributes of forward,merge or classifier_mac
+        {
+          "core": 2,   // Core ID
+          "type": "merge",   // Forwarder type
+          "rx_port": ["nic0", "nic1"],  // Rx port, It MUST be a list for merge type
+          "tx_port": "ring8"            // Tx port
+        },
+        {
+          "core": 3,
+          "type": "classifier_mac",
+          "rx_port": "ring8",        // Rx port, It is not a list because type is classifier_mac
+          "tx_port_table": "classifier_mac_table"	// If type is classifier_mac, tx is classifier_mac_table
+        },
+
+        {
+          "core": 4,
+          "type": "forward",
+          "rx_port": "ring0",
+          "tx_port": "vhost0"
+        },
+        {
+          "core": 5,
+          "type": "forward",
+          "rx_port": "ring1",
+          "tx_port": "vhost2"
+        },
+        {
+          "core": 6,
+          "type": "forward",
+          "rx_port": "vhost0",
+          "tx_port": "ring2"
+        },
+        {
+          "core": 7,
+          "type": "forward",
+          "rx_port": "vhost2",
+          "tx_port": "ring3"
+        },
+        {
+          "core": 8,
+          "type": "merge",
+          "rx_port": ["ring2", "ring3"],
+          "tx_port": "nic0"
+        },
+
+        {
+          "core": 9,
+          "type": "forward",
+          "rx_port": "ring4",
+          "tx_port": "vhost1"
+        },
+        {
+          "core": 10,
+          "type": "forward",
+          "rx_port": "ring5",
+          "tx_port": "vhost3"
+        },
+        {
+          "core": 11,
+          "type": "forward",
+          "rx_port": "vhost1",
+          "tx_port": "ring6"
+        },
+        {
+          "core": 12,
+          "type": "forward",
+          "rx_port": "vhost3",
+          "tx_port": "ring7"
+        },
+        {
+          "core": 13,
+          "type": "merge",
+          "rx_port": ["ring6", "ring7"],
+          "tx_port": "nic1"
+        }
+      ]
+    }
+  ],
+  "classifier_table": {
+    "name":"classifier_mac_table",
+    "table": [
+      {
+        "mac":"52:54:00:12:34:56",
+        "port":"ring0"
+      },
+      {
+        "mac":"52:54:00:12:34:57",
+        "port":"ring4"
+      },
+      {
+        "mac":"52:54:00:12:34:58",
+        "port":"ring1"
+      },
+      {
+        "mac":"52:54:00:12:34:59",
+        "port":"ring5"
+      }
+    ]
+  }
+}
+```
+
+Network diagram
+[TODO] Replace it to more readable SVG img.
+
+```
++---------+  +-----------------------------------------------------------------------------------------------+
+|  host2  |  | Host1                                                                                         |
+|         |  |              +------------------------------------------------------+  +-------------------+  |
+|         |  |              | spp_vf                                               |  |                   |  |
+| +-----+ |  | +--------+   | +---+  +----+  +---+     +----+  +---+  +----------+ |  | +----------+      |  |
+| | nic <------>  nic0  +-----> M +--> r8 +--> C +-----> r0 +--> F +-->          +------>          |      |  |
+| +-----+ |  | +----+---+   | +-^-+  +----+  +-+-+     +----+  +---+  |          | |  | |          |      |  |
+|         |  |      ^       |   |              |                      |  vhost0  | |  | |    nic   |      |  |
+|         |  |      |       |   |              |       +----+  +---+  |          | |  | |          |      |  |
+|         |  |      |       |   |       +--------------+ r2 <--+ F <--+          <------+          |      |  |
+|         |  |      |       |   |       |      |       +----+  +---+  +----------+ |  | +----------+      |  |
+|         |  |      |       |   |       |      |                                   |  |             spp vm|  |
+|         |  |      |       |   |       |      |       +----+  +---+  +----------+ |  | +----------+      |  |
+|         |  |      |       |   |       |      +-------> r4 +--+ F +-->          +------>          |      |  |
+|         |  |      |       |   |    +--v--+   |       +----+  +---+  |          | |  | |          |      |  |
+|         |  |      +----------------+  M  |   |                      |  vhost1  | |  | |    nic   |      |  |
+|         |  |              |   |    +--^--+   |       +----+  +---+  |          | |  | |          |      |  |
+|         |  |              |   |       | +------------+ r6 +--+ F <--+          <------+          |      |  |
+|         |  |              |   |       | |    |       +----+  +---+  +----------+ |  | +----------+      |  |
+|         |  |              |   |       | |    |                                   |  |                   |  |
+|         |  |              |   |       | |    |                                   |  +-------------------+  |
+|         |  |              |   |       | |    |                                   |                         |
+|         |  |              |   |       | |    |                                   |  +-------------------+  |
+|         |  |              |   |       | |    |                                   |  |                   |  |
+| +-----+ |  | +--------+   |   |       | |    |       +----+  +---+  +----------+ |  | +----------+      |  |
+| | nic <------>  nic1  +-------+       | |    +-------> r1 +--+ F +-->          +------>          |      |  |
+| +-----+ |  | +----+---+   |           | |    |       +----+  +---+  |          | |  | |          |      |  |
+|         |  |      ^       |           | |    |                      |  vhost2  | |  | |    nic   |      |  |
+|         |  |      |       |           | |    |       +----+  +---+  |          | |  | |          |      |  |
+|         |  |      |       |           +--------------+ r3 +--+ F <--+          <------+          |      |  |
+|         |  |      |       |             |    |       +----+  +---+  +----------+ |  | +----------+      |  |
+|         |  |      |       |             |    |                                   |  |             spp vm|  |
+|         |  |      |       |             |    |       +----+  +---+  +----------+ |  | +----------+      |  |
+|         |  |      |       |             |    +-------> r5 +--+ F +-->          +------>          |      |  |
+|         |  |      |       |        +----v+           +----+  +---+  |          | |  | |          |      |  |
+|         |  |      +----------------+  M  |                          |  vhost3  | |  | |    nic   |      |  |
+|         |  |              |        +--^--+           +----+  +---+  |          | |  | |          |      |  |
+|         |  |              |           +--------------+ r7 +--+ F <--+          <------+          |      |  |
+|         |  |              |                          +----+  +---+  +----------+ |  | +----------+      |  |
+|         |  |              |                                                      |  |                   |  |
+|         |  |              +------------------------------------------------------+  +-------------------+  |
+|         |  |                                                                                               |
++---------+  +-----------------------------------------------------------------------------------------------+
+```
-- 
1.9.1

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

* [spp] [PATCH 04/30] doc: add spp_vf.md
  2018-01-15 11:04 ` [spp] Proposal - spp_vf(SR-IOV like feature) addition to SPP Ferruh Yigit
                     ` (2 preceding siblings ...)
  2018-01-16  5:16   ` [spp] [PATCH 03/30] doc: add config_manual.md x-fn-spp
@ 2018-01-16  5:16   ` x-fn-spp
  2018-01-16  5:16   ` [spp] [PATCH 05/30] doc: revise spp_vf.md x-fn-spp
                     ` (25 subsequent siblings)
  29 siblings, 0 replies; 97+ messages in thread
From: x-fn-spp @ 2018-01-16  5:16 UTC (permalink / raw)
  To: spp

From: Hiroyuki Nakamura <nakamura.hioryuki@po.ntt-tx.co.jp>

This is a top level document for spp_vf. setup_guide or other
documents are refererd from it.

Signed-off-by: Naoki Takada <takada.naoki@lab.ntt.co.jp>
---
 docs/spp_vf/spp_vf.md | 48 ++++++++++++++++++++++++++++++++++++++++++++++++
 1 file changed, 48 insertions(+)
 create mode 100644 docs/spp_vf/spp_vf.md

diff --git a/docs/spp_vf/spp_vf.md b/docs/spp_vf/spp_vf.md
new file mode 100644
index 0000000..6587249
--- /dev/null
+++ b/docs/spp_vf/spp_vf.md
@@ -0,0 +1,48 @@
+# SPP_VF
+
+SPP_VF is a SR-IOV like network functionality using DPDK for NFV.
+
+![spp_vf_overview](spp_vf_overview.svg)
+
+## Overview
+
+The application distributes incoming packets depends on MAC address
+similar to SR-IOV functionality.
+Network configuration is defined in JSON config file which is imported
+while launching the application.
+The configuration is able to change by sending commnad from spp after
+initialization.
+
+SPP_VF is a multi-thread application.
+It consists of manager thread and forwarder threads.
+There are three types of forwarder for 1:1, 1:N and N:1.
+
+  * forward: 1:1
+  * classifier_mac: 1:N (Destination is determined by MAC address)
+  * merge: N:1
+
+This is an example of network configration, in which one classifier_mac,
+one merger and four forwarders are runnig in spp_vf process for two
+destinations of vhost interface.
+Incoming packets from rx on host1 are sent to each of vhosts on guest
+by looking MAC address in the packet..
+
+![spp_vf_overview](spp_vf_overview.svg)
+
+## Build the Application
+
+See [setup_guide](setup_guide.md).
+
+## Running the Application
+
+See [how_to_use](how_to_use.md).
+
+## Explanation
+
+The following sections provide some explanation of the code.
+
+### Configuration
+
+### Forwarding
+
+### Packet Cloning
-- 
1.9.1

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

* [spp] [PATCH 05/30] doc: revise spp_vf.md
  2018-01-15 11:04 ` [spp] Proposal - spp_vf(SR-IOV like feature) addition to SPP Ferruh Yigit
                     ` (3 preceding siblings ...)
  2018-01-16  5:16   ` [spp] [PATCH 04/30] doc: add spp_vf.md x-fn-spp
@ 2018-01-16  5:16   ` x-fn-spp
  2018-01-16  5:16   ` [spp] [PATCH 06/30] doc: add config section x-fn-spp
                     ` (24 subsequent siblings)
  29 siblings, 0 replies; 97+ messages in thread
From: x-fn-spp @ 2018-01-16  5:16 UTC (permalink / raw)
  To: spp

From: Hiroyuki Nakamura <nakamura.hioryuki@po.ntt-tx.co.jp>

Remove wrong placed image and Refactor explanation of overview.

Signed-off-by: Naoki Takada <takada.naoki@lab.ntt.co.jp>
---
 docs/spp_vf/spp_vf.md | 10 ++++------
 1 file changed, 4 insertions(+), 6 deletions(-)

diff --git a/docs/spp_vf/spp_vf.md b/docs/spp_vf/spp_vf.md
index 6587249..b9ce299 100644
--- a/docs/spp_vf/spp_vf.md
+++ b/docs/spp_vf/spp_vf.md
@@ -2,16 +2,14 @@
 
 SPP_VF is a SR-IOV like network functionality using DPDK for NFV.
 
-![spp_vf_overview](spp_vf_overview.svg)
-
 ## Overview
 
 The application distributes incoming packets depends on MAC address
 similar to SR-IOV functionality.
 Network configuration is defined in JSON config file which is imported
 while launching the application.
-The configuration is able to change by sending commnad from spp after
-initialization.
+The configuration is able to change after initialization by sending
+commnad from spp controller.
 
 SPP_VF is a multi-thread application.
 It consists of manager thread and forwarder threads.
@@ -31,11 +29,11 @@ by looking MAC address in the packet..
 
 ## Build the Application
 
-See [setup_guide](setup_guide.md).
+See [setup guide](setup.md).
 
 ## Running the Application
 
-See [how_to_use](how_to_use.md).
+See [how to use](how_to_use.md).
 
 ## Explanation
 
-- 
1.9.1

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

* [spp] [PATCH 06/30] doc: add config section
  2018-01-15 11:04 ` [spp] Proposal - spp_vf(SR-IOV like feature) addition to SPP Ferruh Yigit
                     ` (4 preceding siblings ...)
  2018-01-16  5:16   ` [spp] [PATCH 05/30] doc: revise spp_vf.md x-fn-spp
@ 2018-01-16  5:16   ` x-fn-spp
  2018-01-16  5:16   ` [spp] [PATCH 07/30] doc: update jp setup manual x-fn-spp
                     ` (23 subsequent siblings)
  29 siblings, 0 replies; 97+ messages in thread
From: x-fn-spp @ 2018-01-16  5:16 UTC (permalink / raw)
  To: spp

From: Hiroyuki Nakamura <nakamura.hioryuki@po.ntt-tx.co.jp>

Add description for importing json config to explain about
how it load config using jansson library.

Signed-off-by: Naoki Takada <takada.naoki@lab.ntt.co.jp>
---
 docs/spp_vf/spp_vf.md | 72 +++++++++++++++++++++++++++++++++++++++++++++++++++
 1 file changed, 72 insertions(+)

diff --git a/docs/spp_vf/spp_vf.md b/docs/spp_vf/spp_vf.md
index b9ce299..2d06e2e 100644
--- a/docs/spp_vf/spp_vf.md
+++ b/docs/spp_vf/spp_vf.md
@@ -41,6 +41,78 @@ The following sections provide some explanation of the code.
 
 ### Configuration
 
+The config file is imported after rte_eal_init() and initialization
+of the application.
+spp_config_load_file() is defined in spp_config.c and default file
+path SPP_CONFIG_FILE_PATH is defined in its header file..
+
+  ```c:spp_vf.c
+	/* set default config file path */
+	strcpy(config_file_path, SPP_CONFIG_FILE_PATH);
+
+	unsigned int main_lcore_id = 0xffffffff;
+	while(1) {
+		/* Parse dpdk parameters */
+		int ret_parse = parse_dpdk_args(argc, argv);
+		if (unlikely(ret_parse != 0)) {
+			break;
+		}
+
+		/* DPDK initialize */
+		int ret_dpdk = rte_eal_init(argc, argv);
+		if (unlikely(ret_dpdk < 0)) {
+			break;
+		}
+
+		/* Skip dpdk parameters */
+		argc -= ret_dpdk;
+		argv += ret_dpdk;
+
+		/* Set log level  */
+		rte_log_set_global_level(RTE_LOG_LEVEL);
+
+		/* Parse application parameters */
+		ret_parse = parse_app_args(argc, argv);
+		if (unlikely(ret_parse != 0)) {
+			break;
+		}
+
+		RTE_LOG(INFO, APP, "Load config file(%s)\n", config_file_path);
+
+		/* Load config */
+		int ret_config = spp_config_load_file(config_file_path, 0, &g_config);
+		if (unlikely(ret_config != 0)) {
+			break;
+		}
+
+		/* Get core id. */
+		main_lcore_id = rte_lcore_id();
+  ```
+
+spp_config_load_file() uses [jansson]() for parsing JSON.
+json_load_file() is a function  of jansson to parse raw JSON
+file and return json_t object as a result.
+In spp_config_load_file(), configuration of classifier table and
+resource assignment of threads are loaded into config of spp.
+
+After importing config, each of threads are launched.
+
+  ```c:spp_vf.c
+		/* Start  thread */
+		unsigned int lcore_id = 0;
+		RTE_LCORE_FOREACH_SLAVE(lcore_id) {
+			if (g_core_info[lcore_id].type == SPP_CONFIG_CLASSIFIER_MAC) {
+				rte_eal_remote_launch(spp_classifier_mac_do,
+						(void *)&g_core_info[lcore_id],
+						lcore_id);
+			} else {
+				rte_eal_remote_launch(spp_forward,
+						(void *)&g_core_info[lcore_id],
+						lcore_id);
+			}
+		}
+  ```
+
 ### Forwarding
 
 ### Packet Cloning
-- 
1.9.1

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

* [spp] [PATCH 07/30] doc: update jp setup manual
  2018-01-15 11:04 ` [spp] Proposal - spp_vf(SR-IOV like feature) addition to SPP Ferruh Yigit
                     ` (5 preceding siblings ...)
  2018-01-16  5:16   ` [spp] [PATCH 06/30] doc: add config section x-fn-spp
@ 2018-01-16  5:16   ` x-fn-spp
  2018-01-16  5:16   ` [spp] [PATCH 08/30] doc: modify figure in spp_vf_overview x-fn-spp
                     ` (22 subsequent siblings)
  29 siblings, 0 replies; 97+ messages in thread
From: x-fn-spp @ 2018-01-16  5:16 UTC (permalink / raw)
  To: spp

From: Hiroyuki Nakamura <nakamura.hioryuki@po.ntt-tx.co.jp>

Remove description for registering ARP in guests and client machines
which is no need for current version.

Signed-off-by: Naoki Takada <takada.naoki@lab.ntt.co.jp>
---
 docs/spp_vf/spp_vf.md | 111 ++++++++++++++++++++++++++------------------------
 1 file changed, 57 insertions(+), 54 deletions(-)

diff --git a/docs/spp_vf/spp_vf.md b/docs/spp_vf/spp_vf.md
index 2d06e2e..786e712 100644
--- a/docs/spp_vf/spp_vf.md
+++ b/docs/spp_vf/spp_vf.md
@@ -46,47 +46,47 @@ of the application.
 spp_config_load_file() is defined in spp_config.c and default file
 path SPP_CONFIG_FILE_PATH is defined in its header file..
 
-  ```c:spp_vf.c
-	/* set default config file path */
-	strcpy(config_file_path, SPP_CONFIG_FILE_PATH);
-
-	unsigned int main_lcore_id = 0xffffffff;
-	while(1) {
-		/* Parse dpdk parameters */
-		int ret_parse = parse_dpdk_args(argc, argv);
-		if (unlikely(ret_parse != 0)) {
-			break;
-		}
-
-		/* DPDK initialize */
-		int ret_dpdk = rte_eal_init(argc, argv);
-		if (unlikely(ret_dpdk < 0)) {
-			break;
-		}
-
-		/* Skip dpdk parameters */
-		argc -= ret_dpdk;
-		argv += ret_dpdk;
-
-		/* Set log level  */
-		rte_log_set_global_level(RTE_LOG_LEVEL);
-
-		/* Parse application parameters */
-		ret_parse = parse_app_args(argc, argv);
-		if (unlikely(ret_parse != 0)) {
-			break;
-		}
-
-		RTE_LOG(INFO, APP, "Load config file(%s)\n", config_file_path);
-
-		/* Load config */
-		int ret_config = spp_config_load_file(config_file_path, 0, &g_config);
-		if (unlikely(ret_config != 0)) {
-			break;
-		}
-
-		/* Get core id. */
-		main_lcore_id = rte_lcore_id();
+  ```c
+  /* set default config file path */
+  strcpy(config_file_path, SPP_CONFIG_FILE_PATH);
+
+  unsigned int main_lcore_id = 0xffffffff;
+  while(1) {
+  	/* Parse dpdk parameters */
+  	int ret_parse = parse_dpdk_args(argc, argv);
+  	if (unlikely(ret_parse != 0)) {
+  		break;
+  	}
+
+  	/* DPDK initialize */
+  	int ret_dpdk = rte_eal_init(argc, argv);
+  	if (unlikely(ret_dpdk < 0)) {
+  		break;
+  	}
+
+  	/* Skip dpdk parameters */
+  	argc -= ret_dpdk;
+  	argv += ret_dpdk;
+
+  	/* Set log level  */
+  	rte_log_set_global_level(RTE_LOG_LEVEL);
+
+  	/* Parse application parameters */
+  	ret_parse = parse_app_args(argc, argv);
+  	if (unlikely(ret_parse != 0)) {
+  		break;
+  	}
+
+  	RTE_LOG(INFO, APP, "Load config file(%s)\n", config_file_path);
+
+  	/* Load config */
+  	int ret_config = spp_config_load_file(config_file_path, 0, &g_config);
+  	if (unlikely(ret_config != 0)) {
+  		break;
+  	}
+
+  	/* Get core id. */
+  	main_lcore_id = rte_lcore_id();
   ```
 
 spp_config_load_file() uses [jansson]() for parsing JSON.
@@ -97,22 +97,25 @@ resource assignment of threads are loaded into config of spp.
 
 After importing config, each of threads are launched.
 
-  ```c:spp_vf.c
-		/* Start  thread */
-		unsigned int lcore_id = 0;
-		RTE_LCORE_FOREACH_SLAVE(lcore_id) {
-			if (g_core_info[lcore_id].type == SPP_CONFIG_CLASSIFIER_MAC) {
-				rte_eal_remote_launch(spp_classifier_mac_do,
-						(void *)&g_core_info[lcore_id],
-						lcore_id);
-			} else {
-				rte_eal_remote_launch(spp_forward,
-						(void *)&g_core_info[lcore_id],
-						lcore_id);
-			}
+  ```c
+	/* Start  thread */
+	unsigned int lcore_id = 0;
+	RTE_LCORE_FOREACH_SLAVE(lcore_id) {
+		if (g_core_info[lcore_id].type == SPP_CONFIG_CLASSIFIER_MAC) {
+			rte_eal_remote_launch(spp_classifier_mac_do,
+					(void *)&g_core_info[lcore_id],
+					lcore_id);
+		} else {
+			rte_eal_remote_launch(spp_forward,
+					(void *)&g_core_info[lcore_id],
+					lcore_id);
 		}
+	}
   ```
 
 ### Forwarding
 
+
 ### Packet Cloning
+
+
-- 
1.9.1

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

* [spp] [PATCH 08/30] doc: modify figure in spp_vf_overview
  2018-01-15 11:04 ` [spp] Proposal - spp_vf(SR-IOV like feature) addition to SPP Ferruh Yigit
                     ` (6 preceding siblings ...)
  2018-01-16  5:16   ` [spp] [PATCH 07/30] doc: update jp setup manual x-fn-spp
@ 2018-01-16  5:16   ` x-fn-spp
  2018-01-16  5:16   ` [spp] [PATCH 09/30] doc: fix " x-fn-spp
                     ` (21 subsequent siblings)
  29 siblings, 0 replies; 97+ messages in thread
From: x-fn-spp @ 2018-01-16  5:16 UTC (permalink / raw)
  To: spp

From: Hiroyuki Nakamura <nakamura.hioryuki@po.ntt-tx.co.jp>

Modify fingure spp_vf_overview.svg in spp_vf_overview.

* Add "ring" icons in "SPP-VF" area.
* Divide "guest VM" icon into two corresponding to "vhosts".
* Change "vhost" position.
* Change icons of "rx" and "tx" in "host1" and in "host2" to "NIC".
* Change icon of "network" to that of cloud shape.
* Add "traffic generator" in host2.

Signed-off-by: Tomoyuki Mizuguchi <mizuguchi.tomoyuki@po.ntt-tx.co.jp>
Signed-off-by: Naoki Takada <takada.naoki@lab.ntt.co.jp>
---
 docs/spp_vf/spp_vf_overview.svg | 2165 ++++++++++++++++++++++++++++-----------
 1 file changed, 1561 insertions(+), 604 deletions(-)

diff --git a/docs/spp_vf/spp_vf_overview.svg b/docs/spp_vf/spp_vf_overview.svg
index d0a6769..9115e66 100644
--- a/docs/spp_vf/spp_vf_overview.svg
+++ b/docs/spp_vf/spp_vf_overview.svg
@@ -7,205 +7,964 @@
    xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
    xmlns:svg="http://www.w3.org/2000/svg"
    xmlns="http://www.w3.org/2000/svg"
-   xmlns:xlink="http://www.w3.org/1999/xlink"
    xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
    xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
-   width="210mm"
-   height="297mm"
-   viewBox="0 0 744.09448819 1052.3622047"
-   id="svg2"
+   width="230.12679mm"
+   height="159.57605mm"
+   viewBox="0 0 230.12679 159.57605"
    version="1.1"
-   inkscape:version="0.91 r13725"
+   id="svg4746"
+   inkscape:version="0.92.1 r15371"
    sodipodi:docname="spp_vf_overview.svg">
   <defs
-     id="defs4">
+     id="defs4740">
+    <marker
+       inkscape:stockid="Arrow2Lend"
+       orient="auto"
+       refY="0"
+       refX="0"
+       id="marker8593"
+       style="overflow:visible"
+       inkscape:isstock="true">
+      <path
+         inkscape:connector-curvature="0"
+         id="path8591"
+         style="fill:#000000;fill-opacity:1;fill-rule:evenodd;stroke:#000000;stroke-width:0.625;stroke-linejoin:round;stroke-opacity:1"
+         d="M 8.7185878,4.0337352 -2.2072895,0.01601326 8.7185884,-4.0017078 c -1.7454984,2.3720609 -1.7354408,5.6174519 -6e-7,8.035443 z"
+         transform="matrix(-1.1,0,0,-1.1,-1.1,0)" />
+    </marker>
+    <marker
+       inkscape:stockid="Arrow2Lend"
+       orient="auto"
+       refY="0"
+       refX="0"
+       id="marker8169"
+       style="overflow:visible"
+       inkscape:isstock="true">
+      <path
+         id="path8167"
+         style="fill:#000000;fill-opacity:1;fill-rule:evenodd;stroke:#000000;stroke-width:0.625;stroke-linejoin:round;stroke-opacity:1"
+         d="M 8.7185878,4.0337352 -2.2072895,0.01601326 8.7185884,-4.0017078 c -1.7454984,2.3720609 -1.7354408,5.6174519 -6e-7,8.035443 z"
+         transform="matrix(-1.1,0,0,-1.1,-1.1,0)"
+         inkscape:connector-curvature="0" />
+    </marker>
+    <marker
+       inkscape:stockid="Arrow1Lend"
+       orient="auto"
+       refY="0"
+       refX="0"
+       id="marker7739"
+       style="overflow:visible"
+       inkscape:isstock="true">
+      <path
+         id="path7737"
+         d="M 0,0 5,-5 -12.5,0 5,5 Z"
+         style="fill:#000000;fill-opacity:1;fill-rule:evenodd;stroke:#000000;stroke-width:1.00000003pt;stroke-opacity:1"
+         transform="matrix(-0.8,0,0,-0.8,-10,0)"
+         inkscape:connector-curvature="0" />
+    </marker>
+    <marker
+       inkscape:stockid="Arrow1Lend"
+       orient="auto"
+       refY="0"
+       refX="0"
+       id="Arrow1Lend"
+       style="overflow:visible"
+       inkscape:isstock="true">
+      <path
+         id="path5589"
+         d="M 0,0 5,-5 -12.5,0 5,5 Z"
+         style="fill:#000000;fill-opacity:1;fill-rule:evenodd;stroke:#000000;stroke-width:1.00000003pt;stroke-opacity:1"
+         transform="matrix(-0.8,0,0,-0.8,-10,0)"
+         inkscape:connector-curvature="0" />
+    </marker>
     <marker
        inkscape:isstock="true"
        style="overflow:visible"
-       id="marker5641"
-       refX="0.0"
-       refY="0.0"
+       id="marker6959"
+       refX="0"
+       refY="0"
        orient="auto"
-       inkscape:stockid="Arrow1Lstart">
+       inkscape:stockid="Arrow2Lend">
       <path
-         transform="scale(0.8) translate(12.5,0)"
-         style="fill-rule:evenodd;stroke:#000000;stroke-width:1pt;stroke-opacity:1;fill:#000000;fill-opacity:1"
-         d="M 0.0,0.0 L 5.0,-5.0 L -12.5,0.0 L 5.0,5.0 L 0.0,0.0 z "
-         id="path5643" />
+         inkscape:connector-curvature="0"
+         transform="matrix(-1.1,0,0,-1.1,-1.1,0)"
+         d="M 8.7185878,4.0337352 -2.2072895,0.01601326 8.7185884,-4.0017078 c -1.7454984,2.3720609 -1.7354408,5.6174519 -6e-7,8.035443 z"
+         style="fill:#000000;fill-opacity:1;fill-rule:evenodd;stroke:#000000;stroke-width:0.625;stroke-linejoin:round;stroke-opacity:1"
+         id="path6957" />
+    </marker>
+    <marker
+       inkscape:isstock="true"
+       style="overflow:visible"
+       id="marker6583"
+       refX="0"
+       refY="0"
+       orient="auto"
+       inkscape:stockid="Arrow2Lend">
+      <path
+         inkscape:connector-curvature="0"
+         transform="matrix(-1.1,0,0,-1.1,-1.1,0)"
+         d="M 8.7185878,4.0337352 -2.2072895,0.01601326 8.7185884,-4.0017078 c -1.7454984,2.3720609 -1.7354408,5.6174519 -6e-7,8.035443 z"
+         style="fill:#000000;fill-opacity:1;fill-rule:evenodd;stroke:#000000;stroke-width:0.625;stroke-linejoin:round;stroke-opacity:1"
+         id="path6581" />
+    </marker>
+    <marker
+       inkscape:isstock="true"
+       style="overflow:visible"
+       id="marker6219"
+       refX="0"
+       refY="0"
+       orient="auto"
+       inkscape:stockid="Arrow2Lend">
+      <path
+         inkscape:connector-curvature="0"
+         transform="matrix(-1.1,0,0,-1.1,-1.1,0)"
+         d="M 8.7185878,4.0337352 -2.2072895,0.01601326 8.7185884,-4.0017078 c -1.7454984,2.3720609 -1.7354408,5.6174519 -6e-7,8.035443 z"
+         style="fill:#000000;fill-opacity:1;fill-rule:evenodd;stroke:#000000;stroke-width:0.625;stroke-linejoin:round;stroke-opacity:1"
+         id="path6217" />
     </marker>
     <marker
        inkscape:stockid="Arrow1Lstart"
        orient="auto"
-       refY="0.0"
-       refX="0.0"
-       id="marker5547"
+       refY="0"
+       refX="0"
+       id="marker5849"
+       style="overflow:visible"
+       inkscape:isstock="true">
+      <path
+         id="path5586"
+         d="M 0,0 5,-5 -12.5,0 5,5 Z"
+         style="fill:#000000;fill-opacity:1;fill-rule:evenodd;stroke:#000000;stroke-width:1.00000003pt;stroke-opacity:1"
+         transform="matrix(0.8,0,0,0.8,10,0)"
+         inkscape:connector-curvature="0" />
+    </marker>
+    <marker
+       inkscape:stockid="Arrow2Lend"
+       orient="auto"
+       refY="0"
+       refX="0"
+       id="marker2605"
        style="overflow:visible"
        inkscape:isstock="true"
        inkscape:collect="always">
       <path
-         id="path5549"
-         d="M 0.0,0.0 L 5.0,-5.0 L -12.5,0.0 L 5.0,5.0 L 0.0,0.0 z "
-         style="fill-rule:evenodd;stroke:#000000;stroke-width:1pt;stroke-opacity:1;fill:#000000;fill-opacity:1"
-         transform="scale(0.8) translate(12.5,0)" />
+         id="path2603"
+         style="fill:#000000;fill-opacity:1;fill-rule:evenodd;stroke:#000000;stroke-width:0.625;stroke-linejoin:round;stroke-opacity:1"
+         d="M 8.7185878,4.0337352 -2.2072895,0.01601326 8.7185884,-4.0017078 c -1.7454984,2.3720609 -1.7354408,5.6174519 -6e-7,8.035443 z"
+         transform="matrix(-1.1,0,0,-1.1,-1.1,0)"
+         inkscape:connector-curvature="0" />
     </marker>
     <marker
-       inkscape:stockid="Arrow1Lstart"
+       inkscape:stockid="Arrow2Lend"
        orient="auto"
-       refY="0.0"
-       refX="0.0"
-       id="marker5465"
+       refY="0"
+       refX="0"
+       id="marker2218"
        style="overflow:visible"
        inkscape:isstock="true">
       <path
-         id="path5467"
-         d="M 0.0,0.0 L 5.0,-5.0 L -12.5,0.0 L 5.0,5.0 L 0.0,0.0 z "
-         style="fill-rule:evenodd;stroke:#000000;stroke-width:1pt;stroke-opacity:1;fill:#000000;fill-opacity:1"
-         transform="scale(0.8) translate(12.5,0)" />
+         id="path2216"
+         style="fill:#000000;fill-opacity:1;fill-rule:evenodd;stroke:#000000;stroke-width:0.625;stroke-linejoin:round;stroke-opacity:1"
+         d="M 8.7185878,4.0337352 -2.2072895,0.01601326 8.7185884,-4.0017078 c -1.7454984,2.3720609 -1.7354408,5.6174519 -6e-7,8.035443 z"
+         transform="matrix(-1.1,0,0,-1.1,-1.1,0)"
+         inkscape:connector-curvature="0" />
     </marker>
     <marker
-       inkscape:isstock="true"
-       style="overflow:visible;"
-       id="marker5365"
-       refX="0.0"
-       refY="0.0"
+       inkscape:stockid="Arrow2Lend"
        orient="auto"
-       inkscape:stockid="Arrow2Lend">
+       refY="0"
+       refX="0"
+       id="marker1864"
+       style="overflow:visible"
+       inkscape:isstock="true">
+      <path
+         id="path1862"
+         style="fill:#000000;fill-opacity:1;fill-rule:evenodd;stroke:#000000;stroke-width:0.625;stroke-linejoin:round;stroke-opacity:1"
+         d="M 8.7185878,4.0337352 -2.2072895,0.01601326 8.7185884,-4.0017078 c -1.7454984,2.3720609 -1.7354408,5.6174519 -6e-7,8.035443 z"
+         transform="matrix(-1.1,0,0,-1.1,-1.1,0)"
+         inkscape:connector-curvature="0" />
+    </marker>
+    <marker
+       inkscape:stockid="Arrow2Lend"
+       orient="auto"
+       refY="0"
+       refX="0"
+       id="marker1516"
+       style="overflow:visible"
+       inkscape:isstock="true">
+      <path
+         id="path1514"
+         style="fill:#000000;fill-opacity:1;fill-rule:evenodd;stroke:#000000;stroke-width:0.625;stroke-linejoin:round;stroke-opacity:1"
+         d="M 8.7185878,4.0337352 -2.2072895,0.01601326 8.7185884,-4.0017078 c -1.7454984,2.3720609 -1.7354408,5.6174519 -6e-7,8.035443 z"
+         transform="matrix(-1.1,0,0,-1.1,-1.1,0)"
+         inkscape:connector-curvature="0" />
+    </marker>
+    <marker
+       inkscape:stockid="Arrow2Lend"
+       orient="auto"
+       refY="0"
+       refX="0"
+       id="marker1632"
+       style="overflow:visible"
+       inkscape:isstock="true">
       <path
-         transform="scale(1.1) rotate(180) translate(1,0)"
-         d="M 8.7185878,4.0337352 L -2.2072895,0.016013256 L 8.7185884,-4.0017078 C 6.9730900,-1.6296469 6.9831476,1.6157441 8.7185878,4.0337352 z "
-         style="fill-rule:evenodd;stroke-width:0.625;stroke-linejoin:round;stroke:#000000;stroke-opacity:1;fill:#000000;fill-opacity:1"
-         id="path5367" />
+         id="path1630"
+         style="fill:#000000;fill-opacity:1;fill-rule:evenodd;stroke:#000000;stroke-width:0.625;stroke-linejoin:round;stroke-opacity:1"
+         d="M 8.7185878,4.0337352 -2.2072895,0.01601326 8.7185884,-4.0017078 c -1.7454984,2.3720609 -1.7354408,5.6174519 -6e-7,8.035443 z"
+         transform="matrix(-1.1,0,0,-1.1,-1.1,0)"
+         inkscape:connector-curvature="0" />
     </marker>
     <marker
        inkscape:stockid="Arrow2Lend"
        orient="auto"
-       refY="0.0"
-       refX="0.0"
+       refY="0"
+       refX="0"
+       id="marker1626"
+       style="overflow:visible"
+       inkscape:isstock="true">
+      <path
+         id="path1624"
+         style="fill:#000000;fill-opacity:1;fill-rule:evenodd;stroke:#000000;stroke-width:0.625;stroke-linejoin:round;stroke-opacity:1"
+         d="M 8.7185878,4.0337352 -2.2072895,0.01601326 8.7185884,-4.0017078 c -1.7454984,2.3720609 -1.7354408,5.6174519 -6e-7,8.035443 z"
+         transform="matrix(-1.1,0,0,-1.1,-1.1,0)"
+         inkscape:connector-curvature="0" />
+    </marker>
+    <marker
+       inkscape:stockid="Arrow2Lend"
+       orient="auto"
+       refY="0"
+       refX="0"
+       id="marker1620"
+       style="overflow:visible"
+       inkscape:isstock="true">
+      <path
+         id="path1618"
+         style="fill:#000000;fill-opacity:1;fill-rule:evenodd;stroke:#000000;stroke-width:0.625;stroke-linejoin:round;stroke-opacity:1"
+         d="M 8.7185878,4.0337352 -2.2072895,0.01601326 8.7185884,-4.0017078 c -1.7454984,2.3720609 -1.7354408,5.6174519 -6e-7,8.035443 z"
+         transform="matrix(-1.1,0,0,-1.1,-1.1,0)"
+         inkscape:connector-curvature="0" />
+    </marker>
+    <marker
+       inkscape:stockid="Arrow2Lend"
+       orient="auto"
+       refY="0"
+       refX="0"
+       id="marker1614"
+       style="overflow:visible"
+       inkscape:isstock="true">
+      <path
+         id="path1612"
+         style="fill:#000000;fill-opacity:1;fill-rule:evenodd;stroke:#000000;stroke-width:0.625;stroke-linejoin:round;stroke-opacity:1"
+         d="M 8.7185878,4.0337352 -2.2072895,0.01601326 8.7185884,-4.0017078 c -1.7454984,2.3720609 -1.7354408,5.6174519 -6e-7,8.035443 z"
+         transform="matrix(-1.1,0,0,-1.1,-1.1,0)"
+         inkscape:connector-curvature="0" />
+    </marker>
+    <marker
+       inkscape:stockid="Arrow2Lend"
+       orient="auto"
+       refY="0"
+       refX="0"
+       id="marker1608"
+       style="overflow:visible"
+       inkscape:isstock="true">
+      <path
+         id="path1606"
+         style="fill:#000000;fill-opacity:1;fill-rule:evenodd;stroke:#000000;stroke-width:0.625;stroke-linejoin:round;stroke-opacity:1"
+         d="M 8.7185878,4.0337352 -2.2072895,0.01601326 8.7185884,-4.0017078 c -1.7454984,2.3720609 -1.7354408,5.6174519 -6e-7,8.035443 z"
+         transform="matrix(-1.1,0,0,-1.1,-1.1,0)"
+         inkscape:connector-curvature="0" />
+    </marker>
+    <marker
+       inkscape:stockid="Arrow2Lend"
+       orient="auto"
+       refY="0"
+       refX="0"
+       id="marker1560"
+       style="overflow:visible"
+       inkscape:isstock="true">
+      <path
+         id="path1558"
+         style="fill:#000000;fill-opacity:1;fill-rule:evenodd;stroke:#000000;stroke-width:0.625;stroke-linejoin:round;stroke-opacity:1"
+         d="M 8.7185878,4.0337352 -2.2072895,0.01601326 8.7185884,-4.0017078 c -1.7454984,2.3720609 -1.7354408,5.6174519 -6e-7,8.035443 z"
+         transform="matrix(-1.1,0,0,-1.1,-1.1,0)"
+         inkscape:connector-curvature="0" />
+    </marker>
+    <marker
+       inkscape:stockid="Arrow2Lend"
+       orient="auto"
+       refY="0"
+       refX="0"
+       id="marker1552"
+       style="overflow:visible"
+       inkscape:isstock="true">
+      <path
+         id="path1550"
+         style="fill:#000000;fill-opacity:1;fill-rule:evenodd;stroke:#000000;stroke-width:0.625;stroke-linejoin:round;stroke-opacity:1"
+         d="M 8.7185878,4.0337352 -2.2072895,0.01601326 8.7185884,-4.0017078 c -1.7454984,2.3720609 -1.7354408,5.6174519 -6e-7,8.035443 z"
+         transform="matrix(-1.1,0,0,-1.1,-1.1,0)"
+         inkscape:connector-curvature="0" />
+    </marker>
+    <marker
+       inkscape:stockid="Arrow2Lend"
+       orient="auto"
+       refY="0"
+       refX="0"
        id="Arrow2Lend"
-       style="overflow:visible;"
+       style="overflow:visible"
+       inkscape:isstock="true">
+      <path
+         id="path1305"
+         style="fill:#000000;fill-opacity:1;fill-rule:evenodd;stroke:#000000;stroke-width:0.625;stroke-linejoin:round;stroke-opacity:1"
+         d="M 8.7185878,4.0337352 -2.2072895,0.01601326 8.7185884,-4.0017078 c -1.7454984,2.3720609 -1.7354408,5.6174519 -6e-7,8.035443 z"
+         transform="matrix(-1.1,0,0,-1.1,-1.1,0)"
+         inkscape:connector-curvature="0" />
+    </marker>
+    <marker
+       inkscape:isstock="true"
+       style="overflow:visible"
+       id="marker4611"
+       refX="0"
+       refY="0"
+       orient="auto"
+       inkscape:stockid="Arrow2Lend">
+      <path
+         transform="matrix(-1.1,0,0,-1.1,-1.1,0)"
+         d="M 8.7185878,4.0337352 -2.2072895,0.01601326 8.7185884,-4.0017078 c -1.7454984,2.3720609 -1.7354408,5.6174519 -6e-7,8.035443 z"
+         style="fill:#000000;fill-opacity:1;fill-rule:evenodd;stroke:#000000;stroke-width:0.625;stroke-linejoin:round;stroke-opacity:1"
+         id="path4609"
+         inkscape:connector-curvature="0" />
+    </marker>
+    <marker
        inkscape:isstock="true"
+       style="overflow:visible"
+       id="marker26660"
+       refX="0"
+       refY="0"
+       orient="auto"
+       inkscape:stockid="Arrow2Lend"
        inkscape:collect="always">
       <path
-         id="path4630"
-         style="fill-rule:evenodd;stroke-width:0.625;stroke-linejoin:round;stroke:#000000;stroke-opacity:1;fill:#000000;fill-opacity:1"
-         d="M 8.7185878,4.0337352 L -2.2072895,0.016013256 L 8.7185884,-4.0017078 C 6.9730900,-1.6296469 6.9831476,1.6157441 8.7185878,4.0337352 z "
-         transform="scale(1.1) rotate(180) translate(1,0)" />
+         transform="matrix(-1.1,0,0,-1.1,-1.1,0)"
+         d="M 8.7185878,4.0337352 -2.2072895,0.01601326 8.7185884,-4.0017078 c -1.7454984,2.3720609 -1.7354408,5.6174519 -6e-7,8.035443 z"
+         style="fill:#000000;fill-opacity:1;fill-rule:evenodd;stroke:#000000;stroke-width:0.625;stroke-linejoin:round;stroke-opacity:1"
+         id="path26658"
+         inkscape:connector-curvature="0" />
+    </marker>
+    <marker
+       inkscape:isstock="true"
+       style="overflow:visible"
+       id="marker24654"
+       refX="0"
+       refY="0"
+       orient="auto"
+       inkscape:stockid="Arrow2Lstart">
+      <path
+         transform="matrix(1.1,0,0,1.1,1.1,0)"
+         d="M 8.7185878,4.0337352 -2.2072895,0.01601326 8.7185884,-4.0017078 c -1.7454984,2.3720609 -1.7354408,5.6174519 -6e-7,8.035443 z"
+         style="fill:#000000;fill-opacity:1;fill-rule:evenodd;stroke:#000000;stroke-width:0.625;stroke-linejoin:round;stroke-opacity:1"
+         id="path24652"
+         inkscape:connector-curvature="0" />
+    </marker>
+    <marker
+       inkscape:isstock="true"
+       style="overflow:visible"
+       id="marker23978"
+       refX="0"
+       refY="0"
+       orient="auto"
+       inkscape:stockid="Arrow2Lend">
+      <path
+         transform="matrix(-1.1,0,0,-1.1,-1.1,0)"
+         d="M 8.7185878,4.0337352 -2.2072895,0.01601326 8.7185884,-4.0017078 c -1.7454984,2.3720609 -1.7354408,5.6174519 -6e-7,8.035443 z"
+         style="fill:#000000;fill-opacity:1;fill-rule:evenodd;stroke:#000000;stroke-width:0.625;stroke-linejoin:round;stroke-opacity:1"
+         id="path23976"
+         inkscape:connector-curvature="0" />
+    </marker>
+    <marker
+       inkscape:isstock="true"
+       style="overflow:visible"
+       id="marker23136"
+       refX="0"
+       refY="0"
+       orient="auto"
+       inkscape:stockid="Arrow2Lend">
+      <path
+         transform="matrix(-1.1,0,0,-1.1,-1.1,0)"
+         d="M 8.7185878,4.0337352 -2.2072895,0.01601326 8.7185884,-4.0017078 c -1.7454984,2.3720609 -1.7354408,5.6174519 -6e-7,8.035443 z"
+         style="fill:#000000;fill-opacity:1;fill-rule:evenodd;stroke:#000000;stroke-width:0.625;stroke-linejoin:round;stroke-opacity:1"
+         id="path23134"
+         inkscape:connector-curvature="0" />
+    </marker>
+    <marker
+       inkscape:isstock="true"
+       style="overflow:visible"
+       id="marker22960"
+       refX="0"
+       refY="0"
+       orient="auto"
+       inkscape:stockid="Arrow2Lstart">
+      <path
+         transform="matrix(1.1,0,0,1.1,1.1,0)"
+         d="M 8.7185878,4.0337352 -2.2072895,0.01601326 8.7185884,-4.0017078 c -1.7454984,2.3720609 -1.7354408,5.6174519 -6e-7,8.035443 z"
+         style="fill:#000000;fill-opacity:1;fill-rule:evenodd;stroke:#000000;stroke-width:0.625;stroke-linejoin:round;stroke-opacity:1"
+         id="path22958"
+         inkscape:connector-curvature="0" />
+    </marker>
+    <marker
+       inkscape:isstock="true"
+       style="overflow:visible"
+       id="marker14793"
+       refX="0"
+       refY="0"
+       orient="auto"
+       inkscape:stockid="Arrow2Lend">
+      <path
+         transform="matrix(-1.1,0,0,-1.1,-1.1,0)"
+         d="M 8.7185878,4.0337352 -2.2072895,0.01601326 8.7185884,-4.0017078 c -1.7454984,2.3720609 -1.7354408,5.6174519 -6e-7,8.035443 z"
+         style="fill:#000000;fill-opacity:1;fill-rule:evenodd;stroke:#000000;stroke-width:0.625;stroke-linejoin:round;stroke-opacity:1"
+         id="path14791"
+         inkscape:connector-curvature="0" />
+    </marker>
+    <marker
+       inkscape:isstock="true"
+       style="overflow:visible"
+       id="marker13092"
+       refX="0"
+       refY="0"
+       orient="auto"
+       inkscape:stockid="Arrow2Lend">
+      <path
+         transform="matrix(-1.1,0,0,-1.1,-1.1,0)"
+         d="M 8.7185878,4.0337352 -2.2072895,0.01601326 8.7185884,-4.0017078 c -1.7454984,2.3720609 -1.7354408,5.6174519 -6e-7,8.035443 z"
+         style="fill:#000000;fill-opacity:1;fill-rule:evenodd;stroke:#000000;stroke-width:0.625;stroke-linejoin:round;stroke-opacity:1"
+         id="path13090"
+         inkscape:connector-curvature="0" />
+    </marker>
+    <marker
+       inkscape:isstock="true"
+       style="overflow:visible"
+       id="marker12910"
+       refX="0"
+       refY="0"
+       orient="auto"
+       inkscape:stockid="Arrow2Lend">
+      <path
+         transform="matrix(-1.1,0,0,-1.1,-1.1,0)"
+         d="M 8.7185878,4.0337352 -2.2072895,0.01601326 8.7185884,-4.0017078 c -1.7454984,2.3720609 -1.7354408,5.6174519 -6e-7,8.035443 z"
+         style="fill:#000000;fill-opacity:1;fill-rule:evenodd;stroke:#000000;stroke-width:0.625;stroke-linejoin:round;stroke-opacity:1"
+         id="path12908"
+         inkscape:connector-curvature="0" />
+    </marker>
+    <marker
+       inkscape:isstock="true"
+       style="overflow:visible"
+       id="marker12568"
+       refX="0"
+       refY="0"
+       orient="auto"
+       inkscape:stockid="Arrow2Lend">
+      <path
+         transform="matrix(-1.1,0,0,-1.1,-1.1,0)"
+         d="M 8.7185878,4.0337352 -2.2072895,0.01601326 8.7185884,-4.0017078 c -1.7454984,2.3720609 -1.7354408,5.6174519 -6e-7,8.035443 z"
+         style="fill:#000000;fill-opacity:1;fill-rule:evenodd;stroke:#000000;stroke-width:0.625;stroke-linejoin:round;stroke-opacity:1"
+         id="path12566"
+         inkscape:connector-curvature="0" />
+    </marker>
+    <marker
+       inkscape:isstock="true"
+       style="overflow:visible"
+       id="marker5180"
+       refX="0"
+       refY="0"
+       orient="auto"
+       inkscape:stockid="Arrow1Lend">
+      <path
+         transform="matrix(-0.8,0,0,-0.8,-10,0)"
+         style="fill:#000000;fill-opacity:1;fill-rule:evenodd;stroke:#000000;stroke-width:1.00000003pt;stroke-opacity:1"
+         d="M 0,0 5,-5 -12.5,0 5,5 Z"
+         id="path5178"
+         inkscape:connector-curvature="0" />
+    </marker>
+    <marker
+       inkscape:stockid="Arrow1Lend"
+       orient="auto"
+       refY="0"
+       refX="0"
+       id="marker4816"
+       style="overflow:visible"
+       inkscape:isstock="true">
+      <path
+         id="path4814"
+         d="M 0,0 5,-5 -12.5,0 5,5 Z"
+         style="fill:#000000;fill-opacity:1;fill-rule:evenodd;stroke:#000000;stroke-width:1.00000003pt;stroke-opacity:1"
+         transform="matrix(-0.8,0,0,-0.8,-10,0)"
+         inkscape:connector-curvature="0" />
+    </marker>
+    <marker
+       inkscape:stockid="Arrow2Lend"
+       orient="auto"
+       refY="0"
+       refX="0"
+       id="marker4059"
+       style="overflow:visible"
+       inkscape:isstock="true">
+      <path
+         id="path4057"
+         style="fill:#000000;fill-opacity:1;fill-rule:evenodd;stroke:#000000;stroke-width:0.625;stroke-linejoin:round;stroke-opacity:1"
+         d="M 8.7185878,4.0337352 -2.2072895,0.01601326 8.7185884,-4.0017078 c -1.7454984,2.3720609 -1.7354408,5.6174519 -6e-7,8.035443 z"
+         transform="matrix(-1.1,0,0,-1.1,-1.1,0)"
+         inkscape:connector-curvature="0" />
     </marker>
     <marker
        inkscape:stockid="Arrow1Lstart"
        orient="auto"
-       refY="0.0"
-       refX="0.0"
+       refY="0"
+       refX="0"
        id="Arrow1Lstart"
        style="overflow:visible"
        inkscape:isstock="true">
       <path
-         id="path4609"
-         d="M 0.0,0.0 L 5.0,-5.0 L -12.5,0.0 L 5.0,5.0 L 0.0,0.0 z "
-         style="fill-rule:evenodd;stroke:#000000;stroke-width:1pt;stroke-opacity:1;fill:#000000;fill-opacity:1"
-         transform="scale(0.8) translate(12.5,0)" />
+         id="path5293"
+         d="M 0,0 5,-5 -12.5,0 5,5 Z"
+         style="fill-rule:evenodd;stroke:#000000;stroke-width:1.00000003pt"
+         transform="matrix(0.8,0,0,0.8,10,0)"
+         inkscape:connector-curvature="0" />
     </marker>
     <marker
-       inkscape:stockid="Arrow1Lend"
+       inkscape:stockid="Arrow2Lend"
        orient="auto"
-       refY="0.0"
-       refX="0.0"
-       id="marker5147"
-       style="overflow:visible;"
+       refY="0"
+       refX="0"
+       id="Arrow2Lend-4"
+       style="overflow:visible"
        inkscape:isstock="true">
       <path
-         id="path5149"
-         d="M 0.0,0.0 L 5.0,-5.0 L -12.5,0.0 L 5.0,5.0 L 0.0,0.0 z "
-         style="fill-rule:evenodd;stroke:#000000;stroke-width:1pt;stroke-opacity:1;fill:#000000;fill-opacity:1"
-         transform="scale(0.8) rotate(180) translate(12.5,0)" />
+         inkscape:connector-curvature="0"
+         id="path2284-4"
+         style="fill:#000000;fill-opacity:1;fill-rule:evenodd;stroke:#000000;stroke-width:0.625;stroke-linejoin:round;stroke-opacity:1"
+         d="M 8.7185878,4.0337352 -2.2072895,0.01601326 8.7185884,-4.0017078 c -1.7454984,2.3720609 -1.7354408,5.6174519 -6e-7,8.035443 z"
+         transform="matrix(-1.1,0,0,-1.1,-1.1,0)" />
     </marker>
     <marker
-       inkscape:stockid="Arrow1Lend"
+       inkscape:stockid="Arrow2Lend"
+       orient="auto"
+       refY="0"
+       refX="0"
+       id="marker4059-8"
+       style="overflow:visible"
+       inkscape:isstock="true">
+      <path
+         inkscape:connector-curvature="0"
+         id="path4057-0"
+         style="fill:#000000;fill-opacity:1;fill-rule:evenodd;stroke:#000000;stroke-width:0.625;stroke-linejoin:round;stroke-opacity:1"
+         d="M 8.7185878,4.0337352 -2.2072895,0.01601326 8.7185884,-4.0017078 c -1.7454984,2.3720609 -1.7354408,5.6174519 -6e-7,8.035443 z"
+         transform="matrix(-1.1,0,0,-1.1,-1.1,0)" />
+    </marker>
+    <marker
+       inkscape:stockid="Arrow2Lend"
+       orient="auto"
+       refY="0"
+       refX="0"
+       id="Arrow2Lend-2"
+       style="overflow:visible"
+       inkscape:isstock="true">
+      <path
+         inkscape:connector-curvature="0"
+         id="path2284-6"
+         style="fill:#000000;fill-opacity:1;fill-rule:evenodd;stroke:#000000;stroke-width:0.625;stroke-linejoin:round;stroke-opacity:1"
+         d="M 8.7185878,4.0337352 -2.2072895,0.01601326 8.7185884,-4.0017078 c -1.7454984,2.3720609 -1.7354408,5.6174519 -6e-7,8.035443 z"
+         transform="matrix(-1.1,0,0,-1.1,-1.1,0)" />
+    </marker>
+    <marker
+       inkscape:stockid="Arrow2Lend"
+       orient="auto"
+       refY="0"
+       refX="0"
+       id="Arrow2Lend-2-4"
+       style="overflow:visible"
+       inkscape:isstock="true">
+      <path
+         inkscape:connector-curvature="0"
+         id="path2284-6-0"
+         style="fill:#000000;fill-opacity:1;fill-rule:evenodd;stroke:#000000;stroke-width:0.625;stroke-linejoin:round;stroke-opacity:1"
+         d="M 8.7185878,4.0337352 -2.2072895,0.01601326 8.7185884,-4.0017078 c -1.7454984,2.3720609 -1.7354408,5.6174519 -6e-7,8.035443 z"
+         transform="matrix(-1.1,0,0,-1.1,-1.1,0)" />
+    </marker>
+    <marker
+       inkscape:stockid="Arrow2Lend"
+       orient="auto"
+       refY="0"
+       refX="0"
+       id="Arrow2Lend-2-2"
+       style="overflow:visible"
+       inkscape:isstock="true">
+      <path
+         inkscape:connector-curvature="0"
+         id="path2284-6-6"
+         style="fill:#000000;fill-opacity:1;fill-rule:evenodd;stroke:#000000;stroke-width:0.625;stroke-linejoin:round;stroke-opacity:1"
+         d="M 8.7185878,4.0337352 -2.2072895,0.01601326 8.7185884,-4.0017078 c -1.7454984,2.3720609 -1.7354408,5.6174519 -6e-7,8.035443 z"
+         transform="matrix(-1.1,0,0,-1.1,-1.1,0)" />
+    </marker>
+    <marker
+       inkscape:stockid="Arrow2Lend"
+       orient="auto"
+       refY="0"
+       refX="0"
+       id="Arrow2Lend-2-6"
+       style="overflow:visible"
+       inkscape:isstock="true">
+      <path
+         inkscape:connector-curvature="0"
+         id="path2284-6-3"
+         style="fill:#000000;fill-opacity:1;fill-rule:evenodd;stroke:#000000;stroke-width:0.625;stroke-linejoin:round;stroke-opacity:1"
+         d="M 8.7185878,4.0337352 -2.2072895,0.01601326 8.7185884,-4.0017078 c -1.7454984,2.3720609 -1.7354408,5.6174519 -6e-7,8.035443 z"
+         transform="matrix(-1.1,0,0,-1.1,-1.1,0)" />
+    </marker>
+    <marker
+       inkscape:stockid="Arrow2Lend"
+       orient="auto"
+       refY="0"
+       refX="0"
+       id="Arrow2Lend-2-6-2"
+       style="overflow:visible"
+       inkscape:isstock="true">
+      <path
+         inkscape:connector-curvature="0"
+         id="path2284-6-3-4"
+         style="fill:#000000;fill-opacity:1;fill-rule:evenodd;stroke:#000000;stroke-width:0.625;stroke-linejoin:round;stroke-opacity:1"
+         d="M 8.7185878,4.0337352 -2.2072895,0.01601326 8.7185884,-4.0017078 c -1.7454984,2.3720609 -1.7354408,5.6174519 -6e-7,8.035443 z"
+         transform="matrix(-1.1,0,0,-1.1,-1.1,0)" />
+    </marker>
+    <marker
+       inkscape:stockid="Arrow2Lend"
        orient="auto"
-       refY="0.0"
-       refX="0.0"
-       id="marker5113"
-       style="overflow:visible;"
+       refY="0"
+       refX="0"
+       id="Arrow2Lend-5"
+       style="overflow:visible"
+       inkscape:isstock="true">
+      <path
+         inkscape:connector-curvature="0"
+         id="path2284-8"
+         style="fill:#000000;fill-opacity:1;fill-rule:evenodd;stroke:#000000;stroke-width:0.625;stroke-linejoin:round;stroke-opacity:1"
+         d="M 8.7185878,4.0337352 -2.2072895,0.01601326 8.7185884,-4.0017078 c -1.7454984,2.3720609 -1.7354408,5.6174519 -6e-7,8.035443 z"
+         transform="matrix(-1.1,0,0,-1.1,-1.1,0)" />
+    </marker>
+    <marker
+       inkscape:stockid="Arrow2Lend"
+       orient="auto"
+       refY="0"
+       refX="0"
+       id="marker4059-8-1"
+       style="overflow:visible"
        inkscape:isstock="true">
       <path
-         id="path5115"
-         d="M 0.0,0.0 L 5.0,-5.0 L -12.5,0.0 L 5.0,5.0 L 0.0,0.0 z "
-         style="fill-rule:evenodd;stroke:#000000;stroke-width:1pt;stroke-opacity:1;fill:#000000;fill-opacity:1"
-         transform="scale(0.8) rotate(180) translate(12.5,0)" />
+         inkscape:connector-curvature="0"
+         id="path4057-0-9"
+         style="fill:#000000;fill-opacity:1;fill-rule:evenodd;stroke:#000000;stroke-width:0.625;stroke-linejoin:round;stroke-opacity:1"
+         d="M 8.7185878,4.0337352 -2.2072895,0.01601326 8.7185884,-4.0017078 c -1.7454984,2.3720609 -1.7354408,5.6174519 -6e-7,8.035443 z"
+         transform="matrix(-1.1,0,0,-1.1,-1.1,0)" />
+    </marker>
+    <marker
+       inkscape:stockid="Arrow2Lend"
+       orient="auto"
+       refY="0"
+       refX="0"
+       id="marker4059-8-1-6"
+       style="overflow:visible"
+       inkscape:isstock="true">
+      <path
+         inkscape:connector-curvature="0"
+         id="path4057-0-9-1"
+         style="fill:#000000;fill-opacity:1;fill-rule:evenodd;stroke:#000000;stroke-width:0.625;stroke-linejoin:round;stroke-opacity:1"
+         d="M 8.7185878,4.0337352 -2.2072895,0.01601326 8.7185884,-4.0017078 c -1.7454984,2.3720609 -1.7354408,5.6174519 -6e-7,8.035443 z"
+         transform="matrix(-1.1,0,0,-1.1,-1.1,0)" />
+    </marker>
+    <marker
+       inkscape:stockid="Arrow2Lend"
+       orient="auto"
+       refY="0"
+       refX="0"
+       id="Arrow2Lend-2-4-1"
+       style="overflow:visible"
+       inkscape:isstock="true">
+      <path
+         inkscape:connector-curvature="0"
+         id="path2284-6-0-0"
+         style="fill:#000000;fill-opacity:1;fill-rule:evenodd;stroke:#000000;stroke-width:0.625;stroke-linejoin:round;stroke-opacity:1"
+         d="M 8.7185878,4.0337352 -2.2072895,0.01601326 8.7185884,-4.0017078 c -1.7454984,2.3720609 -1.7354408,5.6174519 -6e-7,8.035443 z"
+         transform="matrix(-1.1,0,0,-1.1,-1.1,0)" />
+    </marker>
+    <marker
+       inkscape:stockid="Arrow2Lend"
+       orient="auto"
+       refY="0"
+       refX="0"
+       id="Arrow2Lend-2-4-1-9"
+       style="overflow:visible"
+       inkscape:isstock="true">
+      <path
+         inkscape:connector-curvature="0"
+         id="path2284-6-0-0-3"
+         style="fill:#000000;fill-opacity:1;fill-rule:evenodd;stroke:#000000;stroke-width:0.625;stroke-linejoin:round;stroke-opacity:1"
+         d="M 8.7185878,4.0337352 -2.2072895,0.01601326 8.7185884,-4.0017078 c -1.7454984,2.3720609 -1.7354408,5.6174519 -6e-7,8.035443 z"
+         transform="matrix(-1.1,0,0,-1.1,-1.1,0)" />
+    </marker>
+    <marker
+       inkscape:stockid="Arrow2Lend"
+       orient="auto"
+       refY="0"
+       refX="0"
+       id="Arrow2Lend-2-4-1-7"
+       style="overflow:visible"
+       inkscape:isstock="true">
+      <path
+         inkscape:connector-curvature="0"
+         id="path2284-6-0-0-0"
+         style="fill:#000000;fill-opacity:1;fill-rule:evenodd;stroke:#000000;stroke-width:0.625;stroke-linejoin:round;stroke-opacity:1"
+         d="M 8.7185878,4.0337352 -2.2072895,0.01601326 8.7185884,-4.0017078 c -1.7454984,2.3720609 -1.7354408,5.6174519 -6e-7,8.035443 z"
+         transform="matrix(-1.1,0,0,-1.1,-1.1,0)" />
+    </marker>
+    <marker
+       inkscape:stockid="Arrow2Lend"
+       orient="auto"
+       refY="0"
+       refX="0"
+       id="Arrow2Lend-2-4-1-7-7"
+       style="overflow:visible"
+       inkscape:isstock="true">
+      <path
+         inkscape:connector-curvature="0"
+         id="path2284-6-0-0-0-8"
+         style="fill:#000000;fill-opacity:1;fill-rule:evenodd;stroke:#000000;stroke-width:0.625;stroke-linejoin:round;stroke-opacity:1"
+         d="M 8.7185878,4.0337352 -2.2072895,0.01601326 8.7185884,-4.0017078 c -1.7454984,2.3720609 -1.7354408,5.6174519 -6e-7,8.035443 z"
+         transform="matrix(-1.1,0,0,-1.1,-1.1,0)" />
     </marker>
     <marker
        inkscape:isstock="true"
-       style="overflow:visible;"
-       id="marker5009"
-       refX="0.0"
-       refY="0.0"
+       style="overflow:visible"
+       id="marker5180-9"
+       refX="0"
+       refY="0"
        orient="auto"
-       inkscape:stockid="Arrow1Lend"
-       inkscape:collect="always">
+       inkscape:stockid="Arrow1Lend">
       <path
-         transform="scale(0.8) rotate(180) translate(12.5,0)"
-         style="fill-rule:evenodd;stroke:#000000;stroke-width:1pt;stroke-opacity:1;fill:#000000;fill-opacity:1"
-         d="M 0.0,0.0 L 5.0,-5.0 L -12.5,0.0 L 5.0,5.0 L 0.0,0.0 z "
-         id="path5011" />
+         inkscape:connector-curvature="0"
+         transform="matrix(-0.8,0,0,-0.8,-10,0)"
+         style="fill:#000000;fill-opacity:1;fill-rule:evenodd;stroke:#000000;stroke-width:1.00000003pt;stroke-opacity:1"
+         d="M 0,0 5,-5 -12.5,0 5,5 Z"
+         id="path5178-1" />
     </marker>
     <marker
-       inkscape:stockid="Arrow1Lend"
+       inkscape:isstock="true"
+       style="overflow:visible"
+       id="marker5180-9-9"
+       refX="0"
+       refY="0"
+       orient="auto"
+       inkscape:stockid="Arrow1Lend">
+      <path
+         inkscape:connector-curvature="0"
+         transform="matrix(-0.8,0,0,-0.8,-10,0)"
+         style="fill:#000000;fill-opacity:1;fill-rule:evenodd;stroke:#000000;stroke-width:1.00000003pt;stroke-opacity:1"
+         d="M 0,0 5,-5 -12.5,0 5,5 Z"
+         id="path5178-1-4" />
+    </marker>
+    <marker
+       inkscape:stockid="Arrow2Lstart"
        orient="auto"
-       refY="0.0"
-       refX="0.0"
-       id="marker4963"
-       style="overflow:visible;"
+       refY="0"
+       refX="0"
+       id="Arrow2Lstart-6"
+       style="overflow:visible"
+       inkscape:isstock="true">
+      <path
+         inkscape:connector-curvature="0"
+         id="path1110-1"
+         style="fill:#000000;fill-opacity:1;fill-rule:evenodd;stroke:#000000;stroke-width:0.625;stroke-linejoin:round;stroke-opacity:1"
+         d="M 8.7185878,4.0337352 -2.2072895,0.01601326 8.7185884,-4.0017078 c -1.7454984,2.3720609 -1.7354408,5.6174519 -6e-7,8.035443 z"
+         transform="matrix(1.1,0,0,1.1,1.1,0)" />
+    </marker>
+    <marker
        inkscape:isstock="true"
-       inkscape:collect="always">
+       style="overflow:visible"
+       id="marker14793-9"
+       refX="0"
+       refY="0"
+       orient="auto"
+       inkscape:stockid="Arrow2Lend">
       <path
-         id="path4965"
-         d="M 0.0,0.0 L 5.0,-5.0 L -12.5,0.0 L 5.0,5.0 L 0.0,0.0 z "
-         style="fill-rule:evenodd;stroke:#000000;stroke-width:1pt;stroke-opacity:1;fill:#000000;fill-opacity:1"
-         transform="scale(0.8) rotate(180) translate(12.5,0)" />
+         inkscape:connector-curvature="0"
+         transform="matrix(-1.1,0,0,-1.1,-1.1,0)"
+         d="M 8.7185878,4.0337352 -2.2072895,0.01601326 8.7185884,-4.0017078 c -1.7454984,2.3720609 -1.7354408,5.6174519 -6e-7,8.035443 z"
+         style="fill:#000000;fill-opacity:1;fill-rule:evenodd;stroke:#000000;stroke-width:0.625;stroke-linejoin:round;stroke-opacity:1"
+         id="path14791-9" />
     </marker>
     <marker
        inkscape:isstock="true"
-       style="overflow:visible;"
-       id="marker4923"
-       refX="0.0"
-       refY="0.0"
+       style="overflow:visible"
+       id="marker14793-5"
+       refX="0"
+       refY="0"
        orient="auto"
-       inkscape:stockid="Arrow1Lend"
-       inkscape:collect="always">
+       inkscape:stockid="Arrow2Lend">
       <path
-         transform="scale(0.8) rotate(180) translate(12.5,0)"
-         style="fill-rule:evenodd;stroke:#000000;stroke-width:1pt;stroke-opacity:1;fill:#000000;fill-opacity:1"
-         d="M 0.0,0.0 L 5.0,-5.0 L -12.5,0.0 L 5.0,5.0 L 0.0,0.0 z "
-         id="path4925" />
+         inkscape:connector-curvature="0"
+         transform="matrix(-1.1,0,0,-1.1,-1.1,0)"
+         d="M 8.7185878,4.0337352 -2.2072895,0.01601326 8.7185884,-4.0017078 c -1.7454984,2.3720609 -1.7354408,5.6174519 -6e-7,8.035443 z"
+         style="fill:#000000;fill-opacity:1;fill-rule:evenodd;stroke:#000000;stroke-width:0.625;stroke-linejoin:round;stroke-opacity:1"
+         id="path14791-0" />
     </marker>
     <marker
-       inkscape:stockid="Arrow1Lend"
+       inkscape:isstock="true"
+       style="overflow:visible"
+       id="marker14793-1"
+       refX="0"
+       refY="0"
        orient="auto"
-       refY="0.0"
-       refX="0.0"
-       id="Arrow1Lend"
-       style="overflow:visible;"
+       inkscape:stockid="Arrow2Lend">
+      <path
+         inkscape:connector-curvature="0"
+         transform="matrix(-1.1,0,0,-1.1,-1.1,0)"
+         d="M 8.7185878,4.0337352 -2.2072895,0.01601326 8.7185884,-4.0017078 c -1.7454984,2.3720609 -1.7354408,5.6174519 -6e-7,8.035443 z"
+         style="fill:#000000;fill-opacity:1;fill-rule:evenodd;stroke:#000000;stroke-width:0.625;stroke-linejoin:round;stroke-opacity:1"
+         id="path14791-4" />
+    </marker>
+    <marker
        inkscape:isstock="true"
-       inkscape:collect="always">
+       style="overflow:visible"
+       id="marker22960-5"
+       refX="0"
+       refY="0"
+       orient="auto"
+       inkscape:stockid="Arrow2Lstart">
       <path
-         id="path4612"
-         d="M 0.0,0.0 L 5.0,-5.0 L -12.5,0.0 L 5.0,5.0 L 0.0,0.0 z "
-         style="fill-rule:evenodd;stroke:#000000;stroke-width:1pt;stroke-opacity:1;fill:#000000;fill-opacity:1"
-         transform="scale(0.8) rotate(180) translate(12.5,0)" />
+         inkscape:connector-curvature="0"
+         transform="matrix(1.1,0,0,1.1,1.1,0)"
+         d="M 8.7185878,4.0337352 -2.2072895,0.01601326 8.7185884,-4.0017078 c -1.7454984,2.3720609 -1.7354408,5.6174519 -6e-7,8.035443 z"
+         style="fill:#000000;fill-opacity:1;fill-rule:evenodd;stroke:#000000;stroke-width:0.625;stroke-linejoin:round;stroke-opacity:1"
+         id="path22958-6" />
     </marker>
     <marker
-       inkscape:stockid="Arrow2Mend"
+       inkscape:stockid="Arrow2Lend"
        orient="auto"
-       refY="0.0"
-       refX="0.0"
-       id="Arrow2Mend"
-       style="overflow:visible;"
+       refY="0"
+       refX="0"
+       id="marker1560-3"
+       style="overflow:visible"
        inkscape:isstock="true">
       <path
-         id="path4636"
-         style="fill-rule:evenodd;stroke-width:0.625;stroke-linejoin:round;stroke:#000000;stroke-opacity:1;fill:#000000;fill-opacity:1"
-         d="M 8.7185878,4.0337352 L -2.2072895,0.016013256 L 8.7185884,-4.0017078 C 6.9730900,-1.6296469 6.9831476,1.6157441 8.7185878,4.0337352 z "
-         transform="scale(0.6) rotate(180) translate(0,0)" />
+         inkscape:connector-curvature="0"
+         id="path1558-3"
+         style="fill:#000000;fill-opacity:1;fill-rule:evenodd;stroke:#000000;stroke-width:0.625;stroke-linejoin:round;stroke-opacity:1"
+         d="M 8.7185878,4.0337352 -2.2072895,0.01601326 8.7185884,-4.0017078 c -1.7454984,2.3720609 -1.7354408,5.6174519 -6e-7,8.035443 z"
+         transform="matrix(-1.1,0,0,-1.1,-1.1,0)" />
+    </marker>
+    <marker
+       inkscape:isstock="true"
+       style="overflow:visible"
+       id="marker22960-7"
+       refX="0"
+       refY="0"
+       orient="auto"
+       inkscape:stockid="Arrow2Lstart">
+      <path
+         inkscape:connector-curvature="0"
+         transform="matrix(1.1,0,0,1.1,1.1,0)"
+         d="M 8.7185878,4.0337352 -2.2072895,0.01601326 8.7185884,-4.0017078 c -1.7454984,2.3720609 -1.7354408,5.6174519 -6e-7,8.035443 z"
+         style="fill:#000000;fill-opacity:1;fill-rule:evenodd;stroke:#000000;stroke-width:0.625;stroke-linejoin:round;stroke-opacity:1"
+         id="path22958-61" />
+    </marker>
+    <marker
+       inkscape:isstock="true"
+       style="overflow:visible"
+       id="marker22960-5-6"
+       refX="0"
+       refY="0"
+       orient="auto"
+       inkscape:stockid="Arrow2Lstart">
+      <path
+         inkscape:connector-curvature="0"
+         transform="matrix(1.1,0,0,1.1,1.1,0)"
+         d="M 8.7185878,4.0337352 -2.2072895,0.01601326 8.7185884,-4.0017078 c -1.7454984,2.3720609 -1.7354408,5.6174519 -6e-7,8.035443 z"
+         style="fill:#000000;fill-opacity:1;fill-rule:evenodd;stroke:#000000;stroke-width:0.625;stroke-linejoin:round;stroke-opacity:1"
+         id="path22958-6-8" />
+    </marker>
+    <marker
+       inkscape:isstock="true"
+       style="overflow:visible"
+       id="marker14793-1-4"
+       refX="0"
+       refY="0"
+       orient="auto"
+       inkscape:stockid="Arrow2Lend">
+      <path
+         inkscape:connector-curvature="0"
+         transform="matrix(-1.1,0,0,-1.1,-1.1,0)"
+         d="M 8.7185878,4.0337352 -2.2072895,0.01601326 8.7185884,-4.0017078 c -1.7454984,2.3720609 -1.7354408,5.6174519 -6e-7,8.035443 z"
+         style="fill:#000000;fill-opacity:1;fill-rule:evenodd;stroke:#000000;stroke-width:0.625;stroke-linejoin:round;stroke-opacity:1"
+         id="path14791-4-5" />
+    </marker>
+    <marker
+       inkscape:isstock="true"
+       style="overflow:visible"
+       id="marker22960-9"
+       refX="0"
+       refY="0"
+       orient="auto"
+       inkscape:stockid="Arrow2Lstart">
+      <path
+         inkscape:connector-curvature="0"
+         transform="matrix(1.1,0,0,1.1,1.1,0)"
+         d="M 8.7185878,4.0337352 -2.2072895,0.01601326 8.7185884,-4.0017078 c -1.7454984,2.3720609 -1.7354408,5.6174519 -6e-7,8.035443 z"
+         style="fill:#000000;fill-opacity:1;fill-rule:evenodd;stroke:#000000;stroke-width:0.625;stroke-linejoin:round;stroke-opacity:1"
+         id="path22958-60" />
+    </marker>
+    <marker
+       inkscape:isstock="true"
+       style="overflow:visible"
+       id="marker14793-1-9"
+       refX="0"
+       refY="0"
+       orient="auto"
+       inkscape:stockid="Arrow2Lend"
+       inkscape:collect="always">
+      <path
+         inkscape:connector-curvature="0"
+         transform="matrix(-1.1,0,0,-1.1,-1.1,0)"
+         d="M 8.7185878,4.0337352 -2.2072895,0.01601326 8.7185884,-4.0017078 c -1.7454984,2.3720609 -1.7354408,5.6174519 -6e-7,8.035443 z"
+         style="fill:#000000;fill-opacity:1;fill-rule:evenodd;stroke:#000000;stroke-width:0.625;stroke-linejoin:round;stroke-opacity:1"
+         id="path14791-4-1" />
+    </marker>
+    <marker
+       inkscape:isstock="true"
+       style="overflow:visible"
+       id="marker14793-1-9-6"
+       refX="0"
+       refY="0"
+       orient="auto"
+       inkscape:stockid="Arrow2Lend">
+      <path
+         inkscape:connector-curvature="0"
+         transform="matrix(-1.1,0,0,-1.1,-1.1,0)"
+         d="M 8.7185878,4.0337352 -2.2072895,0.01601326 8.7185884,-4.0017078 c -1.7454984,2.3720609 -1.7354408,5.6174519 -6e-7,8.035443 z"
+         style="fill:#000000;fill-opacity:1;fill-rule:evenodd;stroke:#000000;stroke-width:0.625;stroke-linejoin:round;stroke-opacity:1"
+         id="path14791-4-1-5" />
+    </marker>
+    <marker
+       inkscape:isstock="true"
+       style="overflow:visible"
+       id="marker22960-9-7"
+       refX="0"
+       refY="0"
+       orient="auto"
+       inkscape:stockid="Arrow2Lstart">
+      <path
+         inkscape:connector-curvature="0"
+         transform="matrix(1.1,0,0,1.1,1.1,0)"
+         d="M 8.7185878,4.0337352 -2.2072895,0.01601326 8.7185884,-4.0017078 c -1.7454984,2.3720609 -1.7354408,5.6174519 -6e-7,8.035443 z"
+         style="fill:#000000;fill-opacity:1;fill-rule:evenodd;stroke:#000000;stroke-width:0.625;stroke-linejoin:round;stroke-opacity:1"
+         id="path22958-60-6" />
     </marker>
   </defs>
   <sodipodi:namedview
@@ -215,579 +974,777 @@
      borderopacity="1.0"
      inkscape:pageopacity="0.0"
      inkscape:pageshadow="2"
-     inkscape:zoom="0.49497475"
-     inkscape:cx="123.1929"
-     inkscape:cy="463.15501"
-     inkscape:document-units="px"
-     inkscape:current-layer="layer2"
+     inkscape:zoom="0.7"
+     inkscape:cx="176.84477"
+     inkscape:cy="58.190232"
+     inkscape:document-units="mm"
+     inkscape:current-layer="layer1"
      showgrid="false"
-     inkscape:window-width="1331"
-     inkscape:window-height="840"
-     inkscape:window-x="255"
-     inkscape:window-y="0"
-     inkscape:window-maximized="0" />
+     inkscape:window-width="1920"
+     inkscape:window-height="1138"
+     inkscape:window-x="-8"
+     inkscape:window-y="-8"
+     inkscape:window-maximized="1"
+     fit-margin-top="0"
+     fit-margin-left="0"
+     fit-margin-right="0"
+     fit-margin-bottom="0" />
   <metadata
-     id="metadata7">
+     id="metadata4743">
     <rdf:RDF>
       <cc:Work
          rdf:about="">
         <dc:format>image/svg+xml</dc:format>
         <dc:type
            rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
-        <dc:title />
+        <dc:title></dc:title>
       </cc:Work>
     </rdf:RDF>
   </metadata>
   <g
-     inkscape:groupmode="layer"
-     id="layer2"
      inkscape:label="host"
-     style="display:inline">
+     inkscape:groupmode="layer"
+     id="layer1"
+     style="display:inline;opacity:0.98999999"
+     transform="translate(22.342263,-3.6416683)">
     <rect
-       id="rect3397"
-       width="515.59247"
-       height="371.01962"
-       x="199.04526"
-       y="-494.46774"
-       rx="0"
-       ry="0"
-       style="fill:#f9f9f9;stroke:#000000;stroke-width:1;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
-       transform="scale(1,-1)" />
-    <image
-       y="188.82965"
-       x="199.5847"
-       id="image4253"
-       xlink:href="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAACQAAAAkCAYAAADhAJiYAAAABHNCSVQICAgIfAhkiAAAAJdJREFU WIXtzrEJwkAYBeB33pFOd7CQ4AwSwSLgMIcoOIe9jQtIIDiArQppHOEC4gjpPHubV/4W75vgc9NF lV05h7WhT4ir5TZ8ZiXS4Wj9gb80eN2vk5F15JdCjEKMQoxCjEKMQoxCjEKMQoxCjEKMQoxCjEKM QszfhcLQJ6A9Wz+A7gHvfQ77db15P29j648rXI5xd/oCgL0bFKgMdsQAAAAASUVORK5CYII= "
-       style="fill:#ffff00;fill-opacity:1;stroke:#000000;stroke-opacity:1;image-rendering:optimizeSpeed"
-       preserveAspectRatio="none"
-       height="29.383257"
-       width="32.579395" />
-    <image
-       y="397.5441"
-       x="198.29185"
-       id="image4273"
-       xlink:href="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAACQAAAAkCAIAAABuYg/PAAAAA3NCSVQICAjb4U/gAAAAbUlEQVRI iWNUtLZlVNdkoDH4/ujhxrZmln+q6g/7ZtLaMuZNa9+8ecNEa2uQwahlo5aNWjZq2ahlo5aNWjZq 2ahlo5aNWjZq2ahlOAHL90cPGTasprk9Z04y+bgynj179t27d7S2i5GR0cHBAQDdpBlSwJ9IHwAA AABJRU5ErkJggg== "
-       style="fill:#ffff00;fill-opacity:1;stroke:#000000;stroke-opacity:1;image-rendering:optimizeSpeed"
-       preserveAspectRatio="none"
-       height="29.383257"
-       width="32.579395" />
-    <image
-       y="670.39264"
-       x="208.19046"
-       id="image4254"
-       xlink:href="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAgUAAAF0CAYAAACzCkr0AAAABHNCSVQICAgIfAhkiAAABixJREFU
-eJzt1jGRmgEABtElc9j4W3xQIBIfEYEBZKS4juKGNJ8HMpP3FGy5p/P5/D6OIwDg//T9/d3tdvv9
-dRxHz+fz0z0AwIfc7/cej8fp16dDAIB/gykAACpTAACMKQAAKlMAAIwpAAAqUwAAjCkAACpTAACM
-KQAAKlMAAIwpAAAqUwAAjCkAACpTAACMKQAAKlMAAIwpAAAqUwAAjCkAACpTAACMKQAAKlMAAIwp
-AAAqUwAAjCkAACpTAACMKQAAKlMAAIwpAAAqUwAAjCkAACpTAACMKQAAKlMAAIwpAAAqUwAAjCkA
-ACpTAACMKQAAKlMAAIwpAAAqUwAAjCkAACpTAACMKQAAKlMAAIwpAAAqUwAAjCkAACpTAACMKQAA
-KlMAAIwpAAAqUwAAjCkAACpTAACMKQAAKlMAAIwpAAAqUwAAjCkAACpTAACMKQAAKlMAAIwpAAAq
-UwAAjCkAACpTAACMKQAAKlMAAIwpAAAqUwAAjCkAACpTAACMKQAAKlMAAIwpAAAqUwAAjCkAACpT
-AACMKQAAKlMAAIwpAAAqUwAAjCkAACpTAACMKQAAKlMAAIwpAAAqUwAAjCkAACpTAACMKQAAKlMA
-AIwpAAAqUwAAjCkAACpTAACMKQAAKlMAAIwpAAAqUwAAjCkAACpTAACMKQAAKlMAAIwpAAAqUwAA
-jCkAACpTAACMKQAAKlMAAIwpAAAqUwAAjCkAACpTAACMKQAAKlMAAIwpAAAqUwAAjCkAACpTAACM
-KQAAKlMAAIwpAAAqUwAAjCkAACpTAACMKQAAKlMAAIwpAAAqUwAAjCkAACpTAACMKQAAKlMAAIwp
-AAAqUwAAjCkAACpTAACMKQAAKlMAAIwpAAAqUwAAjCkAACpTAACMKQAAKlMAAIwpAAAqUwAAjCkA
-ACpTAACMKQAAKlMAAIwpAAAqUwAAjCkAACpTAACMKQAAKlMAAIwpAAAqUwAAjCkAACpTAACMKQAA
-KlMAAIwpAAAqUwAAjCkAACpTAACMKQAAKlMAAIwpAAAqUwAAjCkAACpTAACMKQAAKlMAAIwpAAAq
-UwAAjCkAACpTAACMKQAAKlMAAIwpAAAqUwAAjCkAACpTAACMKQAAKlMAAIwpAAAqUwAAjCkAACpT
-AACMKQAAKlMAAIwpAAAqUwAAjCkAACpTAACMKQAAKlMAAIwpAAAqUwAAjCkAACpTAACMKQAAKlMA
-AIwpAAAqUwAAjCkAACpTAACMKQAAKlMAAIwpAAAqUwAAjCkAACpTAACMKQAAKlMAAIwpAAAqUwAA
-jCkAACpTAACMKQAAKlMAAIwpAAAqUwAAjCkAACpTAACMKQAAKlMAAIwpAAAqUwAAjCkAACpTAACM
-KQAAKlMAAIwpAAAqUwAAjCkAACpTAACMKQAAKlMAAIwpAAAqUwAAjCkAACpTAACMKQAAKlMAAIwp
-AAAqUwAAjCkAACpTAACMKQAAKlMAAIwpAAAqUwAAjCkAACpTAACMKQAAKlMAAIwpAAAqUwAAjCkA
-ACpTAACMKQAAKlMAAIwpAAAqUwAAjCkAACpTAACMKQAAKlMAAIwpAAAqUwAAjCkAACpTAACMKQAA
-KlMAAIwpAAAqUwAAjCkAACpTAACMKQAAKlMAAIwpAAAqUwAAjCkAACpTAACMKQAAKlMAAIwpAAAq
-UwAAjCkAACpTAACMKQAAKlMAAIwpAAAqUwAAjCkAACpTAACMKQAAKlMAAIwpAAAqUwAAjCkAACpT
-AACMKQAAKlMAAIwpAAAqUwAAjCkAACpTAACMKQAAKlMAAIwpAAAqUwAAjCkAACpTAACMKQAAKlMA
-AIwpAAAqUwAAjCkAACpTAACMKQAAKlMAAIwpAAAqUwAAjCkAACpTAACMKQAAKlMAAIwpAAAqUwAA
-jCkAACpTAACMKQAAKlMAAIwpAAAqUwAAjCkAACpTAACMKQAAKlMAAIwpAAAqUwAAjCkAACpTAACM
-KQAAKlMAAIwpAAAqUwAAjCkAACpTAACMKQAAKlMAAIwpAAAqUwAAjCkAACpTAACMKQAAKlMAAIwp
-AAAqUwAAjCkAACpTAADM1+v1+rlcLqdPhwAAn/F+v7ter3/+At56GMaw9bmuAAAAAElFTkSuQmCC
-
-"
-       style="stroke:#000000;stroke-width:1;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1;image-rendering:optimizeSpeed"
-       preserveAspectRatio="none"
-       height="232.59895"
-       width="498.81723" />
-    <image
-       y="728.25555"
-       x="207.75386"
-       id="image4294"
-       xlink:href="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAACEAAAAeCAYAAACiyHcXAAAABHNCSVQICAgIfAhkiAAAAIRJREFU
-SIljVLS2/c+orskwEOD7o4cMC8uKj7D8U1VneNg3c0AcwbxpLcOLFy9YmQbEdjQw6ggYGHUEDIw6
-AgZGHQEDo46AgVFHwMCoI2Bg1BEwMOoIGBh1BAyMOgIGRh0BA4PCESzfHz1kYNiwemBsP3OSgcnC
-kIHx////SQPjAji4BgCwERjrIQkp5wAAAABJRU5ErkJggg==
-"
-       style="image-rendering:optimizeSpeed"
-       preserveAspectRatio="none"
-       height="30"
-       width="33" />
-    <image
-       y="829.27075"
-       x="207.75388"
-       id="image4314"
-       xlink:href="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAACEAAAAeCAYAAACiyHcXAAAABHNCSVQICAgIfAhkiAAAAH5JREFU
-SIntzqENhEAYROFZoBEEIVfDBYm7KmiFBImnhgvJQRckaPyi1+NY1CCugR8xXwPvufxdRVe+YOHY
-PaauRXYWJXw/mEyk84gQAhKT+h9NkCZIE6QJ0gRpgjRBmiBNkCZIE6QJesREduwe+H1t6uuC5FPD
-xRgbm4PbdgF0sBiGQ2sxrAAAAABJRU5ErkJggg==
-"
-       style="image-rendering:optimizeSpeed"
-       preserveAspectRatio="none"
-       height="30"
-       width="33" />
-    <path
-       style="fill:none;fill-rule:evenodd;stroke:#000000;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
-       d="M 208.09142,741.23523 C 175.04704,701.33452 142.10284,661.21343 135.36044,563.44837 135.73123,495.86243 158.93068,440.2096 197.9899,411.92549"
-       id="path4317"
-       inkscape:connector-curvature="0"
-       sodipodi:nodetypes="ccc" />
-    <path
-       style="fill:none;fill-rule:evenodd;stroke:#000000;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
-       d="M 195.96959,211.91529 C 90.766866,304.85183 82.207898,365.56976 74.751289,533.14379 80.131674,656.66835 90.106723,745.84772 207.75388,849.16922"
-       id="path4339"
-       inkscape:connector-curvature="0"
-       sodipodi:nodetypes="ccc" />
-    <path
-       style="fill:#ffff00;fill-opacity:1;stroke:#000000;stroke-width:1;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
-       d="m 200.36855,202.93062 0,-13.13199 15.15229,0 15.15229,0 0,13.13199 0,13.13198 -15.15229,0 -15.15229,0 0,-13.13198 z"
-       id="path4365"
-       inkscape:connector-curvature="0" />
-    <path
-       style="fill:#ffff00;fill-opacity:1;stroke:#000000;stroke-width:1;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
-       d="m 198.34825,412.03219 0,-14.14213 15.15228,0 15.15229,0 0,14.14213 0,14.14214 -15.15229,0 -15.15228,0 0,-14.14214 z"
-       id="path4367"
-       inkscape:connector-curvature="0" />
-    <path
-       style="fill:#ffff00;fill-opacity:1;stroke:#000000;stroke-width:1;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
-       d="m 208.44977,742.35208 0,-13.13199 15.15229,0 15.15229,0 0,13.13199 0,13.13198 -15.15229,0 -15.15229,0 0,-13.13198 z"
-       id="path4371"
-       inkscape:connector-curvature="0" />
-    <path
-       style="fill:#ffff00;fill-opacity:1;stroke:#000000;stroke-width:1;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
-       d="m 208.44977,843.36733 0,-13.13198 15.15229,0 15.15229,0 0,13.13198 0,13.13198 -15.15229,0 -15.15229,0 0,-13.13198 z"
-       id="path4373"
-       inkscape:connector-curvature="0" />
+       style="fill:#ffffff;fill-opacity:1;stroke:#000000;stroke-width:0.40874681;stroke-miterlimit:4;stroke-dasharray:none"
+       id="rect5291"
+       width="178.01804"
+       height="110.73827"
+       x="29.562109"
+       y="3.8460417"
+       ry="0" />
     <text
        xml:space="preserve"
-       style="font-style:normal;font-weight:normal;font-size:17.5px;line-height:125%;font-family:sans-serif;letter-spacing:0px;word-spacing:0px;fill:#000000;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
-       x="214.07114"
-       y="698.42303"
-       id="text4427"
-       sodipodi:linespacing="125%"><tspan
+       style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:6.3499999px;line-height:1.25;font-family:sans-serif;-inkscape-font-specification:'sans-serif, Normal';font-variant-ligatures:normal;font-variant-caps:normal;font-variant-numeric:normal;font-feature-settings:normal;text-align:start;letter-spacing:0px;word-spacing:0px;writing-mode:lr-tb;text-anchor:start;fill:#000000;fill-opacity:1;stroke:none;stroke-width:0.26458332"
+       x="31.447617"
+       y="10.645233"
+       id="text5577"><tspan
          sodipodi:role="line"
-         id="tspan4429"
-         x="214.07114"
-         y="698.42303">host2</tspan></text>
-    <text
+         id="tspan5575"
+         x="31.447617"
+         y="10.645233"
+         style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:6.3499999px;font-family:sans-serif;-inkscape-font-specification:'sans-serif, Normal';font-variant-ligatures:normal;font-variant-caps:normal;font-variant-numeric:normal;font-feature-settings:normal;text-align:start;writing-mode:lr-tb;text-anchor:start;stroke-width:0.26458332">host1</tspan></text>
+    <flowRoot
        xml:space="preserve"
-       style="font-style:normal;font-weight:normal;font-size:17.5px;line-height:125%;font-family:sans-serif;letter-spacing:0px;word-spacing:0px;fill:#000000;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
-       x="203.96959"
-       y="144.92035"
-       id="text4431"
-       sodipodi:linespacing="125%"><tspan
-         sodipodi:role="line"
-         id="tspan4433"
-         x="203.96959"
-         y="144.92035">host1</tspan></text>
+       id="flowRoot5610"
+       style="font-style:normal;font-weight:normal;font-size:40px;line-height:1.25;font-family:sans-serif;letter-spacing:0px;word-spacing:0px;fill:#000000;fill-opacity:1;stroke:none"
+       transform="scale(0.26458333)"><flowRegion
+         id="flowRegion5612"><rect
+           id="rect5614"
+           width="12.857142"
+           height="94.285713"
+           x="147.14285"
+           y="89.662544" /></flowRegion><flowPara
+         id="flowPara5616" /></flowRoot>    <rect
+       style="opacity:1;fill:#ffff00;fill-opacity:1;stroke:#000000;stroke-width:0.15749259;stroke-miterlimit:4;stroke-dasharray:none"
+       id="rect1139-1-3"
+       width="12.284646"
+       height="22.0905"
+       x="29.61422"
+       y="50.24823" />
     <text
        xml:space="preserve"
-       style="font-style:normal;font-weight:normal;font-size:17.5px;line-height:125%;font-family:sans-serif;letter-spacing:0px;word-spacing:0px;fill:#000000;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
-       x="209.5847"
-       y="208.82965"
-       id="text4435"
-       sodipodi:linespacing="125%"><tspan
+       style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:4.93888903px;line-height:1.25;font-family:sans-serif;-inkscape-font-specification:'sans-serif, Normal';font-variant-ligatures:normal;font-variant-caps:normal;font-variant-numeric:normal;font-feature-settings:normal;text-align:start;letter-spacing:0px;word-spacing:0px;writing-mode:lr-tb;text-anchor:start;fill:#000000;fill-opacity:1;stroke:none;stroke-width:0.26458332"
+       x="31.113701"
+       y="62.265713"
+       id="text2024-9-4-2"><tspan
          sodipodi:role="line"
-         id="tspan4437"
-         x="209.5847"
-         y="208.82965">rx</tspan></text>
+         id="tspan1471"
+         x="31.113701"
+         y="62.265713">NIC</tspan></text>
+    <rect
+       style="display:inline;fill:#ffffff;fill-opacity:1;stroke:#000000;stroke-width:0.17385828;stroke-miterlimit:4;stroke-dasharray:none"
+       id="rect5291-3"
+       width="89.598312"
+       height="39.805573"
+       x="28.648361"
+       y="123.32521"
+       ry="0" />
     <text
        xml:space="preserve"
-       style="font-style:normal;font-weight:normal;font-size:17.5px;line-height:125%;font-family:sans-serif;letter-spacing:0px;word-spacing:0px;fill:#000000;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
-       x="204.05083"
-       y="420.00671"
-       id="text4439"
-       sodipodi:linespacing="125%"><tspan
+       style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:6.3499999px;line-height:1.25;font-family:sans-serif;-inkscape-font-specification:'sans-serif, Normal';font-variant-ligatures:normal;font-variant-caps:normal;font-variant-numeric:normal;font-feature-settings:normal;text-align:start;letter-spacing:0px;word-spacing:0px;writing-mode:lr-tb;text-anchor:start;display:inline;fill:#000000;fill-opacity:1;stroke:none;stroke-width:0.26458332"
+       x="30.379715"
+       y="130.27429"
+       id="text5577-4"><tspan
          sodipodi:role="line"
-         id="tspan4441"
-         x="204.05083"
-         y="420.00671">tx</tspan></text>
+         id="tspan29058"
+         x="30.379715"
+         y="130.27429">host2</tspan></text>
     <rect
-       style="fill:#ffeeaa;fill-opacity:1;stroke:#000000;stroke-width:1;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
-       id="rect4445"
-       width="139.40105"
-       height="121.21831"
-       x="28.284271"
-       y="494.758" />
+       style="display:inline;opacity:1;fill:#ffff00;fill-opacity:1;stroke:#000000;stroke-width:0.14192471;stroke-miterlimit:4;stroke-dasharray:none"
+       id="rect1139-1-3-3"
+       width="12.318476"
+       height="17.889858"
+       x="28.756187"
+       y="134.93675" />
     <text
        xml:space="preserve"
-       style="font-style:normal;font-weight:normal;font-size:22.39949417px;line-height:125%;font-family:sans-serif;letter-spacing:0px;word-spacing:0px;fill:#000000;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
-       x="48.699158"
-       y="555.4043"
-       id="text4455"
-       sodipodi:linespacing="125%"
-       transform="scale(0.985853,1.01435)"><tspan
+       style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:4.93888903px;line-height:1.25;font-family:sans-serif;-inkscape-font-specification:'sans-serif, Normal';font-variant-ligatures:normal;font-variant-caps:normal;font-variant-numeric:normal;font-feature-settings:normal;text-align:start;letter-spacing:0px;word-spacing:0px;writing-mode:lr-tb;text-anchor:start;display:inline;fill:#000000;fill-opacity:1;stroke:none;stroke-width:0.26458332"
+       x="29.824566"
+       y="144.7765"
+       id="text2024-9-4-2-1"><tspan
          sodipodi:role="line"
-         id="tspan4457"
-         x="48.699158"
-         y="555.4043">network</tspan></text>
+         id="tspan3496"
+         x="29.824566"
+         y="144.7765">NIC</tspan></text>
+    <path
+       style="fill:none;stroke:#000000;stroke-width:0.30599999;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1;marker-end:url(#marker6219)"
+       d="m -4.009306,100.27164 c 0,0 3.23928417,-32.79676 33.380621,-44.354729"
+       id="path29105"
+       inkscape:connector-curvature="0" />
+    <path
+       style="display:inline;fill:none;stroke:#000000;stroke-width:0.21055813;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
+       d="m 7.418426,100.11915 c 0,0 2.1555199,-23.348561 22.212484,-31.576878"
+       id="path29105-6"
+       inkscape:connector-curvature="0" />
+    <path
+       style="display:inline;opacity:1;fill:#fff6d5;fill-opacity:1;stroke:#000000;stroke-width:0.37257931;stroke-miterlimit:4;stroke-dasharray:none"
+       d="m -0.48373683,81.021671 a 6.3984709,4.6624236 0 0 0 -6.27253387,3.743049 6.3984709,4.6624236 0 0 0 -2.8094903,-0.479359 6.3984709,4.6624236 0 0 0 -6.398387,4.662252 6.3984709,4.6624236 0 0 0 0.8889,2.359802 6.3984709,4.6624236 0 0 0 -0.682338,-0.02869 6.3984709,4.6624236 0 0 0 -6.398387,4.662891 6.3984709,4.6624236 0 0 0 3.020001,3.952152 6.3984709,4.6624236 0 0 0 -2.194312,3.507202 6.3984709,4.6624236 0 0 0 4.721047,4.49395 6.3984709,4.6624236 0 0 0 -1.005726,2.50004 6.3984709,4.6624236 0 0 0 6.398385,4.66225 6.3984709,4.6624236 0 0 0 3.5166639,-0.77004 6.3984709,4.6624236 0 0 0 6.3904879,4.50035 6.3984709,4.6624236 0 0 0 5.8678712,-2.80856 6.3984709,4.6624236 0 0 0 2.8010237,0.4768 6.3984709,4.6624236 0 0 0 6.3983903,-4.66225 6.3984709,4.6624236 0 0 0 -5.68e-4,-0.008 6.3984709,4.6624236 0 0 0 0.207129,0.008 6.3984709,4.6624236 0 0 0 6.398393,-4.66224 6.3984709,4.6624236 0 0 0 -1.543584,-3.02912 6.3984709,4.6624236 0 0 0 4.433215,-4.43086 6.3984709,4.6624236 0 0 !
 0 -3.140218,-4.006328 6.3984709,4.6624236 0 0 0 0.663148,-2.055112 6.3984709,4.6624236 0 0 0 -5.209239,-4.578099 6.3984709,4.6624236 0 0 0 0.04966,-0.550116 6.3984709,4.6624236 0 0 0 -6.3989562,-4.662874 6.3984709,4.6624236 0 0 0 -3.4923868,0.757914 6.3984709,4.6624236 0 0 0 -6.20819523,-3.555001 z"
+       id="path3410"
+       inkscape:connector-curvature="0" />
     <text
        xml:space="preserve"
-       style="font-style:normal;font-weight:normal;font-size:17.5px;line-height:125%;font-family:sans-serif;letter-spacing:0px;word-spacing:0px;fill:#000000;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
-       x="212.13203"
-       y="743.25549"
-       id="text4459"
-       sodipodi:linespacing="125%"><tspan
+       style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:6.3499999px;line-height:1.25;font-family:sans-serif;-inkscape-font-specification:'sans-serif, Normal';font-variant-ligatures:normal;font-variant-caps:normal;font-variant-numeric:normal;font-feature-settings:normal;text-align:start;letter-spacing:0px;word-spacing:0px;writing-mode:lr-tb;text-anchor:start;display:inline;fill:#000000;fill-opacity:1;stroke:none;stroke-width:0.26458332"
+       x="-12.727088"
+       y="103.29467"
+       id="text5577-1"><tspan
          sodipodi:role="line"
-         id="tspan4461"
-         x="212.13203"
-         y="743.25549">rx</tspan></text>
+         id="tspan28860"
+         x="-12.727088"
+         y="103.29467">network</tspan></text>
+    <path
+       style="fill:none;stroke:#000000;stroke-width:0.2374312px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;marker-end:url(#marker8593)"
+       d="m 6.6332697,116.02444 c 0,0 1.8657623,22.06334 21.9335053,23.14219"
+       id="path3498"
+       inkscape:connector-curvature="0" />
+    <path
+       style="display:inline;opacity:0.98999999;fill:none;stroke:#000000;stroke-width:0.31829059px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
+       d="m -2.154263,118.70072 c 0,0 2.63281346,28.09834 30.950739,29.47229"
+       id="path3498-4"
+       inkscape:connector-curvature="0" />
+  </g>
+  <g
+     inkscape:groupmode="layer"
+     id="layer3"
+     inkscape:label="spp_vf_process"
+     style="display:inline"
+     transform="translate(22.342263,-3.6416683)">
+    <rect
+       style="fill:#ffccaa;fill-opacity:1;stroke:#000000;stroke-width:0.27500245;stroke-miterlimit:4;stroke-dasharray:none"
+       id="rect1763"
+       width="89.898491"
+       height="84.881256"
+       x="45.238247"
+       y="20.835232"
+       ry="4.4250889" />
     <text
        xml:space="preserve"
-       style="font-style:normal;font-weight:normal;font-size:17.5px;line-height:125%;font-family:sans-serif;letter-spacing:0px;word-spacing:0px;fill:#000000;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
-       x="214.15234"
-       y="848.3114"
-       id="text4463"
-       sodipodi:linespacing="125%"><tspan
+       style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:4.93888903px;line-height:1.25;font-family:sans-serif;-inkscape-font-specification:'sans-serif, Normal';font-variant-ligatures:normal;font-variant-caps:normal;font-variant-numeric:normal;font-feature-settings:normal;text-align:start;letter-spacing:0px;word-spacing:0px;writing-mode:lr-tb;text-anchor:start;fill:#000000;fill-opacity:1;stroke:none;stroke-width:0.26458332"
+       x="49.590477"
+       y="27.276197"
+       id="text1767"><tspan
          sodipodi:role="line"
-         id="tspan4465"
-         x="214.15234"
-         y="848.3114">tx</tspan></text>
+         id="tspan1765"
+         x="49.590477"
+         y="27.276197"
+         style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:4.93888903px;font-family:sans-serif;-inkscape-font-specification:'sans-serif, Normal';font-variant-ligatures:normal;font-variant-caps:normal;font-variant-numeric:normal;font-feature-settings:normal;text-align:start;writing-mode:lr-tb;text-anchor:start;stroke-width:0.26458332">spp_vf</tspan></text>
   </g>
   <g
      inkscape:groupmode="layer"
      id="layer4"
      inkscape:label="guests"
      style="display:inline"
-     sodipodi:insensitive="true">
+     transform="translate(22.342263,-3.6416683)">
     <rect
-       style="fill:#ececec;fill-opacity:1;stroke:#000000;stroke-width:0.74355245;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
-       id="rect4385"
-       width="155.18895"
-       height="272.38342"
-       x="544.70715"
-       y="193.82353" />
-    <rect
-       style="fill:#ffff00;fill-opacity:1;stroke:#000000;stroke-width:0.85944676;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
-       id="rect4387"
-       width="31.027994"
-       height="27.984053"
-       x="546.06403"
-       y="243.84534" />
-    <rect
-       style="fill:#ffff00;fill-opacity:1;stroke:#000000;stroke-width:0.85944676;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
-       id="rect4389"
-       width="32.320827"
-       height="27.984053"
-       x="546.06403"
-       y="281.98343" />
-    <rect
-       style="fill:#ffff00;fill-opacity:1;stroke:#000000;stroke-width:0.85944676;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
-       id="rect4391"
-       width="32.320827"
-       height="29.150057"
-       x="546.06403"
-       y="356.95554" />
-    <rect
-       style="fill:#ffff00;fill-opacity:1;stroke:#000000;stroke-width:0.85944676;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
-       id="rect4393"
-       width="34.906494"
-       height="26.818052"
-       x="544.77112"
-       y="397.75766" />
+       style="fill:#f9f9f9;fill-opacity:1;stroke:#000000;stroke-width:0.2328189;stroke-miterlimit:4;stroke-dasharray:none"
+       id="rect2020"
+       width="37.802731"
+       height="44.68745"
+       x="166.01413"
+       y="10.521609"
+       ry="3.7239535" />
     <text
        xml:space="preserve"
-       style="font-style:normal;font-weight:normal;font-size:19.04654694px;line-height:125%;font-family:sans-serif;letter-spacing:0px;word-spacing:0px;fill:#000000;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
-       x="558.37213"
-       y="210.79575"
-       id="text4395"
-       sodipodi:linespacing="125%"
-       transform="scale(0.98137951,1.0189738)"><tspan
+       style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:4.93888903px;line-height:1.25;font-family:sans-serif;-inkscape-font-specification:'sans-serif, Normal';font-variant-ligatures:normal;font-variant-caps:normal;font-variant-numeric:normal;font-feature-settings:normal;text-align:start;letter-spacing:0px;word-spacing:0px;writing-mode:lr-tb;text-anchor:start;fill:#000000;fill-opacity:1;stroke:none;stroke-width:0.26458332"
+       x="167.14098"
+       y="21.077375"
+       id="text2024"><tspan
          sodipodi:role="line"
-         id="tspan4397"
-         x="558.37213"
-         y="210.79575">guest</tspan></text>
+         id="tspan2022"
+         x="167.14098"
+         y="21.077375"
+         style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:4.93888903px;font-family:sans-serif;-inkscape-font-specification:'sans-serif, Normal';font-variant-ligatures:normal;font-variant-caps:normal;font-variant-numeric:normal;font-feature-settings:normal;text-align:start;writing-mode:lr-tb;text-anchor:start;stroke-width:0.26458332">guest vm1</tspan></text>
     <rect
-       style="fill:none;fill-opacity:1;stroke:#000000;stroke-width:1;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
-       id="rect4375"
-       width="48.773148"
-       height="81.09803"
-       x="539.2785"
-       y="236.01605" />
-    <rect
-       style="fill:#cccccc;fill-opacity:0;stroke:#000000;stroke-width:1;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
-       id="rect4397"
-       width="46.589622"
-       height="82.955116"
-       x="539.38049"
-       y="349.23471" />
+       style="fill:#f9f9f9;fill-opacity:1;stroke:#000000;stroke-width:0.23468868;stroke-miterlimit:4;stroke-dasharray:none"
+       id="rect2020-5"
+       width="38.168907"
+       height="44.972477"
+       x="165.62701"
+       y="63.981018"
+       ry="3.7477062" />
     <text
        xml:space="preserve"
-       style="font-style:normal;font-weight:normal;font-size:17.5px;line-height:125%;font-family:sans-serif;letter-spacing:0px;word-spacing:0px;fill:#000000;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
-       x="551.50269"
-       y="258.30109"
-       id="text4399"
-       sodipodi:linespacing="125%"><tspan
+       style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:4.93888903px;line-height:1.25;font-family:sans-serif;-inkscape-font-specification:'sans-serif, Normal';font-variant-ligatures:normal;font-variant-caps:normal;font-variant-numeric:normal;font-feature-settings:normal;text-align:start;letter-spacing:0px;word-spacing:0px;writing-mode:lr-tb;text-anchor:start;fill:#000000;fill-opacity:1;stroke:none;stroke-width:0.26458332"
+       x="166.74794"
+       y="70.292007"
+       id="text2024-5"><tspan
          sodipodi:role="line"
-         id="tspan4401"
-         x="551.50269"
-         y="258.30109">rx</tspan></text>
+         id="tspan2202"
+         x="166.74794"
+         y="70.292007">guest vm2</tspan></text>
+    <rect
+       style="opacity:1;fill:#ffff00;fill-opacity:1;stroke:#000000;stroke-width:0.14875925;stroke-miterlimit:4;stroke-dasharray:none"
+       id="rect1139"
+       width="13.798667"
+       height="17.546024"
+       x="166.01764"
+       y="29.789093" />
     <text
        xml:space="preserve"
-       style="font-style:normal;font-weight:normal;font-size:17.5px;line-height:125%;font-family:sans-serif;letter-spacing:0px;word-spacing:0px;fill:#000000;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
-       x="551.54327"
-       y="298.78842"
-       id="text4403"
-       sodipodi:linespacing="125%"><tspan
+       style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:4.93888903px;line-height:1.25;font-family:sans-serif;-inkscape-font-specification:'sans-serif, Normal';font-variant-ligatures:normal;font-variant-caps:normal;font-variant-numeric:normal;font-feature-settings:normal;text-align:start;letter-spacing:0px;word-spacing:0px;writing-mode:lr-tb;text-anchor:start;fill:#000000;fill-opacity:1;stroke:none;stroke-width:0.26458332"
+       x="166.83788"
+       y="40.360432"
+       id="text2024-9"><tspan
          sodipodi:role="line"
-         id="tspan4405"
-         x="551.54327"
-         y="298.78842">tx</tspan></text>
+         id="tspan1504"
+         x="166.83788"
+         y="40.360432">vNIC</tspan></text>
+    <rect
+       style="opacity:1;fill:#ffff00;fill-opacity:1;stroke:#000000;stroke-width:0.15045834;stroke-miterlimit:4;stroke-dasharray:none"
+       id="rect1139-1"
+       width="13.805234"
+       height="17.94058"
+       x="165.57541"
+       y="77.986526" />
     <text
        xml:space="preserve"
-       style="font-style:normal;font-weight:normal;font-size:17.5px;line-height:125%;font-family:sans-serif;letter-spacing:0px;word-spacing:0px;fill:#000000;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
-       x="549.52295"
-       y="375.56"
-       id="text4407"
-       sodipodi:linespacing="125%"><tspan
+       style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:4.93888903px;line-height:1.25;font-family:sans-serif;-inkscape-font-specification:'sans-serif, Normal';font-variant-ligatures:normal;font-variant-caps:normal;font-variant-numeric:normal;font-feature-settings:normal;text-align:start;letter-spacing:0px;word-spacing:0px;writing-mode:lr-tb;text-anchor:start;fill:#000000;fill-opacity:1;stroke:none;stroke-width:0.26458332"
+       x="166.39893"
+       y="88.495567"
+       id="text2024-9-4"><tspan
          sodipodi:role="line"
-         id="tspan4409"
-         x="549.52295"
-         y="375.56">rx</tspan></text>
+         id="tspan1502"
+         x="166.39893"
+         y="88.495567">vNIC</tspan></text>
+  </g>
+  <g
+     inkscape:groupmode="layer"
+     id="layer2"
+     inkscape:label="spp_vf_threads"
+     style="display:inline"
+     transform="translate(22.342263,-3.6416683)">
     <text
        xml:space="preserve"
-       style="font-style:normal;font-weight:normal;font-size:17.5px;line-height:125%;font-family:sans-serif;letter-spacing:0px;word-spacing:0px;fill:#000000;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
-       x="551.54327"
-       y="415.96606"
-       id="text4411"
-       sodipodi:linespacing="125%"><tspan
+       style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:4.93888903px;line-height:1.25;font-family:sans-serif;-inkscape-font-specification:'sans-serif, Normal';font-variant-ligatures:normal;font-variant-caps:normal;font-variant-numeric:normal;font-feature-settings:normal;text-align:start;letter-spacing:0px;word-spacing:0px;writing-mode:lr-tb;text-anchor:start;fill:#d7f4e3;fill-opacity:1;stroke:none;stroke-width:0.26458332"
+       x="83.429108"
+       y="34.468502"
+       id="text16968"><tspan
          sodipodi:role="line"
-         id="tspan4413"
-         x="551.54327"
-         y="415.96606">tx</tspan></text>
+         id="tspan16966"
+         x="83.429108"
+         y="34.468502"
+         style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:4.93888903px;font-family:sans-serif;-inkscape-font-specification:'sans-serif, Normal';font-variant-ligatures:normal;font-variant-caps:normal;font-variant-numeric:normal;font-feature-settings:normal;text-align:start;writing-mode:lr-tb;text-anchor:start;fill:#d7f4e3;stroke-width:0.26458332">ring</tspan></text>
+    <rect
+       style="fill:#ffe6d5;fill-opacity:1;stroke:#000000;stroke-width:0.17908682;stroke-miterlimit:4;stroke-dasharray:none"
+       id="rect1769"
+       width="28.397127"
+       height="7.9864125"
+       x="48.280895"
+       y="33.148167"
+       ry="1.8033863" />
     <text
        xml:space="preserve"
-       style="font-style:normal;font-weight:normal;font-size:17.5px;line-height:125%;font-family:sans-serif;letter-spacing:0px;word-spacing:0px;fill:#000000;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
-       x="594.03064"
-       y="266.46353"
-       id="text4415"
-       sodipodi:linespacing="125%"><tspan
-         sodipodi:role="line"
-         id="tspan4417"
-         x="594.03064"
-         y="266.46353">vNIC</tspan><tspan
+       style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:4.93888903px;line-height:1.25;font-family:sans-serif;-inkscape-font-specification:'sans-serif, Normal';font-variant-ligatures:normal;font-variant-caps:normal;font-variant-numeric:normal;font-feature-settings:normal;text-align:start;letter-spacing:0px;word-spacing:0px;writing-mode:lr-tb;text-anchor:start;fill:#000000;fill-opacity:1;stroke:none;stroke-width:0.26458332"
+       x="51.631538"
+       y="38.464291"
+       id="text1773"><tspan
          sodipodi:role="line"
-         x="594.03064"
-         y="288.33853"
-         id="tspan4425">(vhost)</tspan></text>
+         id="tspan1461"
+         x="51.631538"
+         y="38.464291">classifier</tspan></text>
+    <g
+       id="g1969"
+       transform="matrix(0.9931638,0,0,3.5726314,15.375,-412.81686)"
+       style="fill:#eef4d7">
+      <rect
+         ry="1.8106976"
+         y="122.52335"
+         x="124.54029"
+         height="8.0187912"
+         width="18.980101"
+         id="rect1769-3-2-7"
+         style="fill:#eef4d7;stroke:#000000;stroke-width:0.14670815;stroke-miterlimit:4;stroke-dasharray:none" />
+    </g>
     <text
        xml:space="preserve"
-       style="font-style:normal;font-weight:normal;font-size:17.5px;line-height:125%;font-family:sans-serif;letter-spacing:0px;word-spacing:0px;fill:#000000;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
-       x="596.07123"
-       y="381.62091"
-       id="text4419"
-       sodipodi:linespacing="125%"><tspan
+       style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:4.93888903px;line-height:1.25;font-family:sans-serif;-inkscape-font-specification:'sans-serif, Normal';font-variant-ligatures:normal;font-variant-caps:normal;font-variant-numeric:normal;font-feature-settings:normal;text-align:start;letter-spacing:0px;word-spacing:0px;writing-mode:lr-tb;text-anchor:start;fill:#000000;fill-opacity:1;stroke:none;stroke-width:0.28356495"
+       x="152.11028"
+       y="38.115993"
+       id="text1773-6-6-5-2"
+       transform="scale(0.93214046,1.0727997)"><tspan
+         y="38.115993"
+         x="152.11028"
          sodipodi:role="line"
-         id="tspan4421"
-         x="596.07123"
-         y="381.62091">vNIC</tspan><tspan
-         sodipodi:role="line"
-         x="596.07123"
-         y="403.49591"
-         id="tspan4423">(vhost)</tspan></text>
-  </g>
-  <g
-     inkscape:groupmode="layer"
-     id="layer3"
-     inkscape:label="spp_vf_process"
-     style="display:inline"
-     sodipodi:insensitive="true">
-    <rect
-       style="fill:#f4e3d7;fill-opacity:1;stroke:#000000;stroke-width:0.87971044;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
-       id="rect4399"
-       width="223.64525"
-       height="265.71939"
-       x="277.04822"
-       y="179.91371"
-       ry="13.91201"
-       rx="10.217305" />
+         id="tspan1964-1"
+         style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:4.93888903px;font-family:sans-serif;-inkscape-font-specification:'sans-serif, Normal';font-variant-ligatures:normal;font-variant-caps:normal;font-variant-numeric:normal;font-feature-settings:normal;text-align:start;writing-mode:lr-tb;text-anchor:start;stroke-width:0.28356495">vhost</tspan></text>
+    <g
+       id="g1969-0"
+       transform="matrix(0.9931638,0,0,3.5726314,14.96627,-364.49553)"
+       style="fill:#dedbe3">
+      <rect
+         ry="1.8106976"
+         y="122.52335"
+         x="124.54029"
+         height="8.0187912"
+         width="18.980101"
+         id="rect1769-3-2-7-7"
+         style="fill:#eef4d7;stroke:#000000;stroke-width:0.14670815;stroke-miterlimit:4;stroke-dasharray:none" />
+    </g>
     <text
        xml:space="preserve"
-       style="font-style:normal;font-weight:normal;font-size:17.5px;line-height:125%;font-family:sans-serif;letter-spacing:0px;word-spacing:0px;fill:#000000;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
-       x="292.96454"
-       y="203.81377"
-       id="text5769"
-       sodipodi:linespacing="125%"><tspan
+       style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:4.93888903px;line-height:1.25;font-family:sans-serif;-inkscape-font-specification:'sans-serif, Normal';font-variant-ligatures:normal;font-variant-caps:normal;font-variant-numeric:normal;font-feature-settings:normal;text-align:start;letter-spacing:0px;word-spacing:0px;writing-mode:lr-tb;text-anchor:start;fill:#000000;fill-opacity:1;stroke:none;stroke-width:0.28356495"
+       x="151.67178"
+       y="82.664948"
+       id="text1773-6-6-5-2-7"
+       transform="scale(0.93214046,1.0727997)"><tspan
+         y="82.664948"
+         x="151.67178"
          sodipodi:role="line"
-         id="tspan5771"
-         x="292.96454"
-         y="203.81377">spp_vf</tspan></text>
-  </g>
-  <g
-     inkscape:label="spp_vf_threads"
-     inkscape:groupmode="layer"
-     id="layer1"
-     style="display:inline"
-     sodipodi:insensitive="true">
-    <rect
-       style="fill:#ffeeaa;fill-opacity:1;fill-rule:evenodd;stroke:#000000;stroke-width:1.056795;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
-       id="rect3338"
-       width="88.294899"
-       height="41.616783"
-       x="291.37378"
-       y="228.27687"
-       rx="14.345392"
-       ry="8.049448" />
+         id="tspan1964-1-7"
+         style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:4.93888903px;font-family:sans-serif;-inkscape-font-specification:'sans-serif, Normal';font-variant-ligatures:normal;font-variant-caps:normal;font-variant-numeric:normal;font-feature-settings:normal;text-align:start;writing-mode:lr-tb;text-anchor:start;stroke-width:0.28356495">vhost</tspan></text>
     <path
-       style="fill:#ffeeaa;fill-opacity:1;stroke:#000000;stroke-width:1.00371253;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
-       d="m 300.46715,378.46629 c -4.32888,-2.69254 -5.14237,-5.33087 -5.14237,-16.678 0,-18.70818 -0.47456,-18.50573 43.37958,-18.50573 24.02629,0 36.284,0.61286 38.38411,1.91912 1.97847,1.23059 3.08541,7.52178 3.08541,17.53559 0,13.80279 -0.5776,15.80876 -4.97333,17.27202 -2.73534,0.91054 -19.51231,1.65552 -37.28218,1.65552 -28.8806,0 -32.8545,-0.33939 -37.45122,-3.19852 z"
-       id="path4551"
+       style="fill:none;stroke:#000000;stroke-width:0.32100001;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1;marker-end:url(#marker13092)"
+       d="M 42.335746,51.022012 48.285474,39.502744"
+       id="path4812"
        inkscape:connector-curvature="0" />
     <path
-       style="fill:#ffeeaa;fill-opacity:1;stroke:#000000;stroke-width:1;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
-       d="m 423.06161,258.14039 c -3.47945,-3.47946 -3.22798,-24.79967 0.32732,-27.75031 1.88343,-1.5631 11.35671,-2.1431 28.78935,-1.7626 l 25.98222,0.5671 0,15.15229 0,15.15229 -26.30954,0.56052 c -18.74837,0.39942 -27.02222,-0.15217 -28.78935,-1.91929 z"
-       id="path4553"
+       style="fill:none;stroke:#000000;stroke-width:0.32100001;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1;marker-end:url(#marker14793)"
+       d="m 157.3851,33.909754 c 8.28536,0 8.28536,0 8.28536,0"
+       id="path14783"
        inkscape:connector-curvature="0" />
     <path
-       style="fill:#ffeeaa;fill-opacity:1;stroke:#000000;stroke-width:1;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
-       d="m 423.00617,302.53166 c -3.14772,-3.14772 -3.14772,-24.32844 0,-27.47615 2.54806,-2.54806 46.84009,-3.54987 52.96879,-1.19806 4.63563,1.77886 4.63563,28.09341 0,29.87227 -6.1287,2.3518 -50.42073,1.34999 -52.96879,-1.19806 z"
-       id="path4555"
+       style="display:inline;fill:none;stroke:#000000;stroke-width:0.32100001;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1;marker-start:url(#marker22960)"
+       d="m 157.50554,90.770923 c 8.28536,0 8.28536,0 8.28536,0"
+       id="path14783-8"
        inkscape:connector-curvature="0" />
     <path
-       style="fill:#ffeeaa;fill-opacity:1;stroke:#000000;stroke-width:1;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
-       d="m 423.08192,351.07442 c -3.1916,-3.19159 -3.23421,-24.35282 -0.0554,-27.53158 2.80195,-2.80196 49.46626,-3.40751 53.73879,-0.69736 1.84322,1.1692 2.44496,5.8234 2.02031,15.62643 l -0.60478,13.96129 -26.30954,0.56051 c -18.74837,0.39943 -27.02222,-0.15217 -28.78934,-1.91929 z"
-       id="path4557"
+       style="fill:none;stroke:#000000;stroke-width:0.32100001;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1;marker-end:url(#marker26660)"
+       d="M 49.003632,85.315415 42.335746,68.542273"
+       id="path26650"
        inkscape:connector-curvature="0" />
     <path
-       style="fill:#ffeeaa;fill-opacity:1;stroke:#000000;stroke-width:1;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
-       d="m 425.04678,399.5063 c -3.43282,-3.43282 -3.13788,-24.77299 0.38276,-27.69486 1.88343,-1.56311 11.35671,-2.1431 28.78935,-1.7626 l 25.98222,0.5671 0.60477,13.96129 c 0.42465,9.80303 -0.17708,14.45723 -2.0203,15.62642 -4.27253,2.71016 -50.93684,2.10461 -53.7388,-0.69735 z"
-       id="path4559"
+       style="display:inline;fill:none;stroke:#000000;stroke-width:0.32100001;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1;marker-end:url(#marker14793-1)"
+       d="m 157.03474,82.371116 c 8.28536,0 8.28536,0 8.28536,0"
+       id="path14783-87"
        inkscape:connector-curvature="0" />
+    <path
+       style="display:inline;fill:none;stroke:#000000;stroke-width:0.32100001;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1;marker-start:url(#marker22960-5)"
+       d="m 157.84517,42.31872 c 8.28536,0 8.28536,0 8.28536,0"
+       id="path14783-8-7"
+       inkscape:connector-curvature="0" />
+    <path
+       style="fill:none;stroke:#000000;stroke-width:0.32100001;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1;marker-end:url(#marker1560)"
+       d="m 129.87263,29.014883 c 8.88244,0 8.88244,0 8.88244,0"
+       id="path1556"
+       inkscape:connector-curvature="0" />
+    <path
+       style="display:inline;fill:none;stroke:#000000;stroke-width:0.30693886;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1;marker-start:url(#marker22960-7)"
+       d="m 131.14821,97.427195 c 7.57539,0 7.57539,0 7.57539,0"
+       id="path14783-8-2"
+       inkscape:connector-curvature="0" />
+    <path
+       style="fill:none;stroke:#000000;stroke-width:0.32100001;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1;marker-end:url(#marker1608)"
+       d="m 129.53108,49.653739 c 8.59493,27.28568 8.59493,27.28568 8.59493,27.28568"
+       id="path1604"
+       inkscape:connector-curvature="0" />
+    <path
+       style="display:inline;fill:none;stroke:#000000;stroke-width:0.32100001;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1;marker-end:url(#marker1516)"
+       d="M 76.678022,36.901244 102.43288,28.78674"
+       id="path1506"
+       inkscape:connector-curvature="0" />
+    <path
+       style="display:inline;fill:none;stroke:#000000;stroke-width:0.32100001;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1;marker-end:url(#marker1864)"
+       d="M 76.678022,36.852335 C 102.47067,49.653739 102.47067,49.653739 102.47067,49.653739"
+       id="path1854"
+       inkscape:connector-curvature="0" />
+    <path
+       style="display:inline;fill:none;stroke:#000000;stroke-width:0.32100001;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1;marker-end:url(#marker2218)"
+       d="M 102.69746,77.094814 C 73.622505,86.323333 73.622505,86.323333 73.622505,86.323333"
+       id="path2208"
+       inkscape:connector-curvature="0" />
+    <path
+       style="fill:none;stroke:#000000;stroke-width:0.32100001;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1;marker-end:url(#marker2605)"
+       d="M 103.07543,97.956372 C 73.622505,86.913582 73.622505,86.913582 73.622505,86.913582"
+       id="path2595"
+       inkscape:connector-curvature="0" />
+    <path
+       style="fill:none;stroke:#000000;stroke-width:0.32100001;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1;marker-end:url(#marker1620)"
+       d="m 139.06391,49.857935 c -8.77687,27.838926 -8.77687,27.838926 -8.77687,27.838926"
+       id="path1616"
+       inkscape:connector-curvature="0" />
+    <rect
+       style="fill:#ffe6d5;fill-opacity:1;stroke:#000000;stroke-width:0.16691115;stroke-miterlimit:4;stroke-dasharray:none"
+       id="rect1769-3"
+       width="24.629539"
+       height="7.9985881"
+       x="48.992966"
+       y="82.619164"
+       ry="1.8061357" />
     <text
        xml:space="preserve"
-       style="font-style:normal;font-weight:normal;font-size:17.5px;line-height:125%;font-family:sans-serif;letter-spacing:0px;word-spacing:0px;fill:#000000;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
-       x="296.98483"
-       y="252.3214"
-       id="text4561"
-       sodipodi:linespacing="125%"><tspan
-         sodipodi:role="line"
-         id="tspan4563"
-         x="296.98483"
-         y="252.3214">classifier</tspan></text>
-    <text
-       xml:space="preserve"
-       style="font-style:normal;font-weight:normal;font-size:17.5px;line-height:125%;font-family:sans-serif;letter-spacing:0px;word-spacing:0px;fill:#000000;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
-       x="304.98483"
-       y="365.4585"
-       id="text4565"
-       sodipodi:linespacing="125%"><tspan
-         sodipodi:role="line"
-         id="tspan4567"
-         x="304.98483"
-         y="365.4585">merger</tspan></text>
-    <text
-       xml:space="preserve"
-       style="font-style:normal;font-weight:normal;font-size:17.5px;line-height:125%;font-family:sans-serif;letter-spacing:0px;word-spacing:0px;fill:#000000;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
-       x="436.42651"
-       y="246.17924"
-       id="text4569"
-       sodipodi:linespacing="125%"><tspan
+       style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:4.93888903px;line-height:1.25;font-family:sans-serif;-inkscape-font-specification:'sans-serif, Normal';font-variant-ligatures:normal;font-variant-caps:normal;font-variant-numeric:normal;font-feature-settings:normal;text-align:start;letter-spacing:0px;word-spacing:0px;writing-mode:lr-tb;text-anchor:start;fill:#000000;fill-opacity:1;stroke:none;stroke-width:0.26458332"
+       x="51.820534"
+       y="87.412201"
+       id="text1773-6"><tspan
          sodipodi:role="line"
-         id="tspan4571"
-         x="436.42651"
-         y="246.17924">fwd</tspan></text>
+         id="tspan1463"
+         x="51.820534"
+         y="87.412201">merger</tspan></text>
+    <g
+       id="g2295"
+       transform="translate(-4.2333335)">
+      <rect
+         ry="1.8039205"
+         y="25.020494"
+         x="106.67704"
+         height="7.9887786"
+         width="27.643539"
+         id="rect1769-3-2"
+         style="fill:#ffe6d5;fill-opacity:1;stroke:#000000;stroke-width:0.17672074;stroke-miterlimit:4;stroke-dasharray:none" />
+      <text
+         id="text1773-6-6"
+         y="30.337786"
+         x="107.9122"
+         style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:4.93888903px;line-height:1.25;font-family:sans-serif;-inkscape-font-specification:'sans-serif, Normal';font-variant-ligatures:normal;font-variant-caps:normal;font-variant-numeric:normal;font-feature-settings:normal;text-align:start;letter-spacing:0px;word-spacing:0px;writing-mode:lr-tb;text-anchor:start;fill:#000000;fill-opacity:1;stroke:none;stroke-width:0.26458332"
+         xml:space="preserve"><tspan
+           id="tspan3024"
+           sodipodi:role="line"
+           x="107.9122"
+           y="30.337786">forwarder</tspan></text>
+    </g>
+    <g
+       transform="translate(-3.9795536,47.840984)"
+       style="display:inline"
+       id="g2295-3">
+      <rect
+         ry="1.8039205"
+         y="25.020494"
+         x="106.67704"
+         height="7.9887786"
+         width="27.643539"
+         id="rect1769-3-2-4"
+         style="fill:#ffe6d5;fill-opacity:1;stroke:#000000;stroke-width:0.17672074;stroke-miterlimit:4;stroke-dasharray:none" />
+      <text
+         id="text1773-6-6-0"
+         y="30.337786"
+         x="107.9122"
+         style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:4.93888903px;line-height:1.25;font-family:sans-serif;-inkscape-font-specification:'sans-serif, Normal';font-variant-ligatures:normal;font-variant-caps:normal;font-variant-numeric:normal;font-feature-settings:normal;text-align:start;letter-spacing:0px;word-spacing:0px;writing-mode:lr-tb;text-anchor:start;fill:#000000;fill-opacity:1;stroke:none;stroke-width:0.26458332"
+         xml:space="preserve"><tspan
+           id="tspan3024-5"
+           sodipodi:role="line"
+           x="107.9122"
+           y="30.337786">forwarder</tspan></text>
+    </g>
+    <g
+       transform="translate(-4.2063436,20.399909)"
+       style="display:inline"
+       id="g2295-5">
+      <rect
+         ry="1.8039205"
+         y="25.020494"
+         x="106.67704"
+         height="7.9887786"
+         width="27.643539"
+         id="rect1769-3-2-2"
+         style="fill:#ffe6d5;fill-opacity:1;stroke:#000000;stroke-width:0.17672074;stroke-miterlimit:4;stroke-dasharray:none" />
+      <text
+         id="text1773-6-6-6"
+         y="30.337786"
+         x="107.9122"
+         style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:4.93888903px;line-height:1.25;font-family:sans-serif;-inkscape-font-specification:'sans-serif, Normal';font-variant-ligatures:normal;font-variant-caps:normal;font-variant-numeric:normal;font-feature-settings:normal;text-align:start;letter-spacing:0px;word-spacing:0px;writing-mode:lr-tb;text-anchor:start;fill:#000000;fill-opacity:1;stroke:none;stroke-width:0.26458332"
+         xml:space="preserve"><tspan
+           id="tspan3024-9"
+           sodipodi:role="line"
+           x="107.9122"
+           y="30.337786">forwarder</tspan></text>
+    </g>
+    <g
+       transform="translate(-3.6015836,68.702542)"
+       style="display:inline"
+       id="g2295-0">
+      <rect
+         ry="1.8039205"
+         y="25.020494"
+         x="106.67704"
+         height="7.9887786"
+         width="27.643539"
+         id="rect1769-3-2-8"
+         style="fill:#ffe6d5;fill-opacity:1;stroke:#000000;stroke-width:0.17672074;stroke-miterlimit:4;stroke-dasharray:none" />
+      <text
+         id="text1773-6-6-8"
+         y="30.337786"
+         x="107.9122"
+         style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:4.93888903px;line-height:1.25;font-family:sans-serif;-inkscape-font-specification:'sans-serif, Normal';font-variant-ligatures:normal;font-variant-caps:normal;font-variant-numeric:normal;font-feature-settings:normal;text-align:start;letter-spacing:0px;word-spacing:0px;writing-mode:lr-tb;text-anchor:start;fill:#000000;fill-opacity:1;stroke:none;stroke-width:0.26458332"
+         xml:space="preserve"><tspan
+           id="tspan3024-96"
+           sodipodi:role="line"
+           x="107.9122"
+           y="30.337786">forwarder</tspan></text>
+    </g>
+    <g
+       id="g1263"
+       transform="translate(-4.2333335,-104.8506)">
+      <g
+         id="g2377-5-42"
+         style="display:inline;fill:#eef4d7"
+         transform="translate(-6.7279778,-3.9309553)">
+        <ellipse
+           style="display:inline;fill:#eef4d7;fill-opacity:1;stroke:#000000;stroke-width:0.35376999;stroke-miterlimit:4;stroke-dasharray:none"
+           id="path1780-3-7-12-8"
+           cx="100.0881"
+           cy="141.425"
+           rx="6.5516987"
+           ry="3.1499126"
+           inkscape:transform-center-x="13.229167"
+           inkscape:transform-center-y="-59.720238" />
+        <text
+           xml:space="preserve"
+           style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:4.93888903px;line-height:1.25;font-family:sans-serif;-inkscape-font-specification:'sans-serif, Normal';font-variant-ligatures:normal;font-variant-caps:normal;font-variant-numeric:normal;font-feature-settings:normal;text-align:start;letter-spacing:0px;word-spacing:0px;writing-mode:lr-tb;text-anchor:start;display:inline;fill:#eef4d7;fill-opacity:1;stroke:none;stroke-width:0.28356495"
+           x="102.67519"
+           y="132.96213"
+           id="text1773-6-6-5-2-7-4-3-60"
+           transform="scale(0.93214046,1.0727997)"><tspan
+             sodipodi:role="line"
+             id="tspan2372-8-0"
+             x="102.67519"
+             y="132.96213">ring</tspan></text>
+      </g>
+      <text
+         transform="scale(0.93214046,1.0727997)"
+         id="text1773-6-6-5-2-7-4-4-2"
+         y="129.157"
+         x="95.700722"
+         style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:4.93888903px;line-height:1.25;font-family:sans-serif;-inkscape-font-specification:'sans-serif, Normal';font-variant-ligatures:normal;font-variant-caps:normal;font-variant-numeric:normal;font-feature-settings:normal;text-align:start;letter-spacing:0px;word-spacing:0px;writing-mode:lr-tb;text-anchor:start;display:inline;fill:#000000;fill-opacity:1;stroke:none;stroke-width:0.28356495"
+         xml:space="preserve"><tspan
+           y="129.157"
+           x="95.700722"
+           id="tspan2372-2-3"
+           sodipodi:role="line">ring</tspan></text>
+    </g>
+    <g
+       style="display:inline"
+       id="g1263-5"
+       transform="translate(-3.855357,-94.796429)">
+      <g
+         id="g2377-5-42-7"
+         style="display:inline;fill:#eef4d7"
+         transform="translate(-6.7279778,-3.9309553)">
+        <ellipse
+           style="display:inline;fill:#eef4d7;fill-opacity:1;stroke:#000000;stroke-width:0.35376999;stroke-miterlimit:4;stroke-dasharray:none"
+           id="path1780-3-7-12-8-4"
+           cx="100.0881"
+           cy="141.425"
+           rx="6.5516987"
+           ry="3.1499126"
+           inkscape:transform-center-x="13.229167"
+           inkscape:transform-center-y="-59.720238" />
+        <text
+           xml:space="preserve"
+           style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:4.93888903px;line-height:1.25;font-family:sans-serif;-inkscape-font-specification:'sans-serif, Normal';font-variant-ligatures:normal;font-variant-caps:normal;font-variant-numeric:normal;font-feature-settings:normal;text-align:start;letter-spacing:0px;word-spacing:0px;writing-mode:lr-tb;text-anchor:start;display:inline;fill:#eef4d7;fill-opacity:1;stroke:none;stroke-width:0.28356495"
+           x="102.67519"
+           y="132.96213"
+           id="text1773-6-6-5-2-7-4-3-60-1"
+           transform="scale(0.93214046,1.0727997)"><tspan
+             sodipodi:role="line"
+             id="tspan2372-8-0-0"
+             x="102.67519"
+             y="132.96213">ring</tspan></text>
+      </g>
+      <text
+         transform="scale(0.93214046,1.0727997)"
+         id="text1773-6-6-5-2-7-4-4-2-6"
+         y="129.157"
+         x="95.700722"
+         style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:4.93888903px;line-height:1.25;font-family:sans-serif;-inkscape-font-specification:'sans-serif, Normal';font-variant-ligatures:normal;font-variant-caps:normal;font-variant-numeric:normal;font-feature-settings:normal;text-align:start;letter-spacing:0px;word-spacing:0px;writing-mode:lr-tb;text-anchor:start;display:inline;fill:#000000;fill-opacity:1;stroke:none;stroke-width:0.28356495"
+         xml:space="preserve"><tspan
+           y="129.157"
+           x="95.700722"
+           id="tspan2372-2-3-9"
+           sodipodi:role="line">ring</tspan></text>
+    </g>
+    <g
+       style="display:inline"
+       id="g1263-1"
+       transform="translate(-3.6995481,-55.96114)">
+      <g
+         id="g2377-5-42-1"
+         style="display:inline;fill:#eef4d7"
+         transform="translate(-6.7279778,-3.9309553)">
+        <ellipse
+           style="display:inline;fill:#eef4d7;fill-opacity:1;stroke:#000000;stroke-width:0.35376999;stroke-miterlimit:4;stroke-dasharray:none"
+           id="path1780-3-7-12-8-5"
+           cx="100.0881"
+           cy="141.425"
+           rx="6.5516987"
+           ry="3.1499126"
+           inkscape:transform-center-x="13.229167"
+           inkscape:transform-center-y="-59.720238" />
+        <text
+           xml:space="preserve"
+           style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:4.93888903px;line-height:1.25;font-family:sans-serif;-inkscape-font-specification:'sans-serif, Normal';font-variant-ligatures:normal;font-variant-caps:normal;font-variant-numeric:normal;font-feature-settings:normal;text-align:start;letter-spacing:0px;word-spacing:0px;writing-mode:lr-tb;text-anchor:start;display:inline;fill:#eef4d7;fill-opacity:1;stroke:none;stroke-width:0.28356495"
+           x="102.67519"
+           y="132.96213"
+           id="text1773-6-6-5-2-7-4-3-60-6"
+           transform="scale(0.93214046,1.0727997)"><tspan
+             sodipodi:role="line"
+             id="tspan2372-8-0-1"
+             x="102.67519"
+             y="132.96213">ring</tspan></text>
+      </g>
+      <text
+         transform="scale(0.93214046,1.0727997)"
+         id="text1773-6-6-5-2-7-4-4-2-8"
+         y="129.157"
+         x="95.700722"
+         style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:4.93888903px;line-height:1.25;font-family:sans-serif;-inkscape-font-specification:'sans-serif, Normal';font-variant-ligatures:normal;font-variant-caps:normal;font-variant-numeric:normal;font-feature-settings:normal;text-align:start;letter-spacing:0px;word-spacing:0px;writing-mode:lr-tb;text-anchor:start;display:inline;fill:#000000;fill-opacity:1;stroke:none;stroke-width:0.28356495"
+         xml:space="preserve"><tspan
+           y="129.157"
+           x="95.700722"
+           id="tspan2372-2-3-6"
+           sodipodi:role="line">ring</tspan></text>
+    </g>
+    <g
+       style="display:inline"
+       id="g1263-52"
+       transform="translate(-3.6995481,-44.470663)">
+      <g
+         id="g2377-5-42-19"
+         style="display:inline;fill:#eef4d7"
+         transform="translate(-6.7279778,-3.9309553)">
+        <ellipse
+           style="display:inline;fill:#eef4d7;fill-opacity:1;stroke:#000000;stroke-width:0.35376999;stroke-miterlimit:4;stroke-dasharray:none"
+           id="path1780-3-7-12-8-0"
+           cx="100.0881"
+           cy="141.425"
+           rx="6.5516987"
+           ry="3.1499126"
+           inkscape:transform-center-x="13.229167"
+           inkscape:transform-center-y="-59.720238" />
+        <text
+           xml:space="preserve"
+           style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:4.93888903px;line-height:1.25;font-family:sans-serif;-inkscape-font-specification:'sans-serif, Normal';font-variant-ligatures:normal;font-variant-caps:normal;font-variant-numeric:normal;font-feature-settings:normal;text-align:start;letter-spacing:0px;word-spacing:0px;writing-mode:lr-tb;text-anchor:start;display:inline;fill:#eef4d7;fill-opacity:1;stroke:none;stroke-width:0.28356495"
+           x="102.67519"
+           y="132.96213"
+           id="text1773-6-6-5-2-7-4-3-60-0"
+           transform="scale(0.93214046,1.0727997)"><tspan
+             sodipodi:role="line"
+             id="tspan2372-8-0-3"
+             x="102.67519"
+             y="132.96213">ring</tspan></text>
+      </g>
+      <text
+         transform="scale(0.93214046,1.0727997)"
+         id="text1773-6-6-5-2-7-4-4-2-0"
+         y="129.157"
+         x="95.700722"
+         style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:4.93888903px;line-height:1.25;font-family:sans-serif;-inkscape-font-specification:'sans-serif, Normal';font-variant-ligatures:normal;font-variant-caps:normal;font-variant-numeric:normal;font-feature-settings:normal;text-align:start;letter-spacing:0px;word-spacing:0px;writing-mode:lr-tb;text-anchor:start;display:inline;fill:#000000;fill-opacity:1;stroke:none;stroke-width:0.28356495"
+         xml:space="preserve"><tspan
+           y="129.157"
+           x="95.700722"
+           id="tspan2372-2-3-8"
+           sodipodi:role="line">ring</tspan></text>
+    </g>
+    <rect
+       style="display:inline;fill:#ffccaa;fill-opacity:1;stroke:#000000;stroke-width:0.34002537;stroke-miterlimit:4;stroke-dasharray:none"
+       id="rect1769-5"
+       width="53.147232"
+       height="15.382997"
+       x="50.403591"
+       y="134.48639"
+       ry="3.4735854" />
     <text
        xml:space="preserve"
-       style="font-style:normal;font-weight:normal;font-size:17.5px;line-height:125%;font-family:sans-serif;letter-spacing:0px;word-spacing:0px;fill:#000000;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
-       x="436.42651"
-       y="290.64627"
-       id="text4573"
-       sodipodi:linespacing="125%"><tspan
+       style="font-style:normal;font-weight:normal;font-size:5.17880344px;line-height:125%;font-family:sans-serif;letter-spacing:0px;word-spacing:0px;fill:#000000;fill-opacity:1;stroke:none;stroke-width:0.1294701px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
+       x="60.681969"
+       y="135.07045"
+       id="text237"
+       transform="scale(0.93752888,1.0666338)"><tspan
          sodipodi:role="line"
-         id="tspan4575"
-         x="436.42651"
-         y="290.64627">fwd</tspan></text>
+         id="tspan235"
+         x="60.681969"
+         y="135.07045"
+         style="stroke-width:0.1294701px">traffic generator</tspan></text>
+    <path
+       style="display:inline;fill:none;stroke:#000000;stroke-width:0.32100001;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1;marker-start:url(#marker22960-5-6)"
+       d="m 41.584293,147.74173 c 8.28536,0 8.28536,0 8.28536,0"
+       id="path14783-8-7-9"
+       inkscape:connector-curvature="0" />
+    <path
+       style="display:inline;fill:none;stroke:#000000;stroke-width:0.32100001;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1;marker-end:url(#marker14793-1-4)"
+       d="m 41.496586,139.02471 c 8.28536,0 8.28536,0 8.28536,0"
+       id="path14783-87-8"
+       inkscape:connector-curvature="0" />
+    <rect
+       style="display:inline;fill:#ffccaa;fill-opacity:1;stroke:#000000;stroke-width:0.15743089;stroke-miterlimit:4;stroke-dasharray:none"
+       id="rect1769-5-6-3"
+       width="13.631977"
+       height="12.856415"
+       x="187.85887"
+       y="79.732826"
+       ry="2.9030659" />
     <text
        xml:space="preserve"
-       style="font-style:normal;font-weight:normal;font-size:17.5px;line-height:125%;font-family:sans-serif;letter-spacing:0px;word-spacing:0px;fill:#000000;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
-       x="436.40619"
-       y="343.19452"
-       id="text4577"
-       sodipodi:linespacing="125%"><tspan
+       style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:4.93888903px;line-height:1.25;font-family:sans-serif;-inkscape-font-specification:'sans-serif, Normal';font-variant-ligatures:normal;font-variant-caps:normal;font-variant-numeric:normal;font-feature-settings:normal;text-align:start;letter-spacing:0px;word-spacing:0px;writing-mode:lr-tb;text-anchor:start;display:inline;fill:#000000;fill-opacity:1;stroke:none;stroke-width:0.28356495"
+       x="202.26404"
+       y="81.874725"
+       id="text1773-6-6-5-2-7-8"
+       transform="scale(0.93214045,1.0727997)"><tspan
+         y="81.874725"
+         x="202.26404"
          sodipodi:role="line"
-         id="tspan4579"
-         x="436.40619"
-         y="343.19452">fwd</tspan></text>
+         id="tspan1964-1-7-0"
+         style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:4.93888903px;font-family:sans-serif;-inkscape-font-specification:'sans-serif, Normal';font-variant-ligatures:normal;font-variant-caps:normal;font-variant-numeric:normal;font-feature-settings:normal;text-align:start;writing-mode:lr-tb;text-anchor:start;stroke-width:0.28356495">app2</tspan></text>
+    <path
+       style="display:inline;fill:none;stroke:#000000;stroke-width:0.32100001;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1;marker-start:url(#marker22960-9)"
+       d="m 179.63809,89.30645 c 8.28536,0 8.28536,0 8.28536,0"
+       id="path14783-8-5"
+       inkscape:connector-curvature="0" />
+    <path
+       style="display:inline;fill:none;stroke:#000000;stroke-width:0.32100001;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1;marker-end:url(#marker14793-1-9)"
+       d="m 179.16729,84.081645 c 8.28536,0 8.28536,0 8.28536,0"
+       id="path14783-87-5"
+       inkscape:connector-curvature="0" />
+    <rect
+       style="display:inline;fill:#ffccaa;fill-opacity:1;stroke:#000000;stroke-width:0.15743089;stroke-miterlimit:4;stroke-dasharray:none"
+       id="rect1769-5-6-3-4"
+       width="13.631977"
+       height="12.856415"
+       x="188.56624"
+       y="30.353153"
+       ry="2.9030659" />
     <text
        xml:space="preserve"
-       style="font-style:normal;font-weight:normal;font-size:17.5px;line-height:125%;font-family:sans-serif;letter-spacing:0px;word-spacing:0px;fill:#000000;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
-       x="436.42651"
-       y="393.6412"
-       id="text4581"
-       sodipodi:linespacing="125%"><tspan
+       style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:4.93888903px;line-height:1.25;font-family:sans-serif;-inkscape-font-specification:'sans-serif, Normal';font-variant-ligatures:normal;font-variant-caps:normal;font-variant-numeric:normal;font-feature-settings:normal;text-align:start;letter-spacing:0px;word-spacing:0px;writing-mode:lr-tb;text-anchor:start;display:inline;fill:#000000;fill-opacity:1;stroke:none;stroke-width:0.28356495"
+       x="203.0229"
+       y="35.845913"
+       id="text1773-6-6-5-2-7-8-7"
+       transform="scale(0.93214045,1.0727997)"><tspan
+         y="35.845913"
+         x="203.0229"
          sodipodi:role="line"
-         id="tspan4583"
-         x="436.42651"
-         y="393.6412">fwd</tspan></text>
-    <path
-       style="fill:none;fill-rule:evenodd;stroke:#000000;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;marker-end:url(#marker5365)"
-       d="m 232.1641,200.95148 60.78014,49.34961"
-       id="path4585"
-       inkscape:connector-curvature="0"
-       sodipodi:nodetypes="cc" />
-    <path
-       style="fill:none;fill-rule:evenodd;stroke:#000000;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;marker-start:url(#marker5641)"
-       d="m 230.87125,409.66593 64.09329,-48.24807"
-       id="path4587"
-       inkscape:connector-curvature="0"
-       sodipodi:nodetypes="cc" />
-    <path
-       style="fill:none;fill-rule:evenodd;stroke:#000000;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;marker-end:url(#Arrow2Lend)"
-       d="M 545.48238,294.7478 476.792,288.68688"
-       id="path4589"
-       inkscape:connector-curvature="0"
-       sodipodi:nodetypes="cc" />
+         id="tspan1964-1-7-0-4"
+         style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:4.93888903px;font-family:sans-serif;-inkscape-font-specification:'sans-serif, Normal';font-variant-ligatures:normal;font-variant-caps:normal;font-variant-numeric:normal;font-feature-settings:normal;text-align:start;writing-mode:lr-tb;text-anchor:start;stroke-width:0.28356495">app1</tspan></text>
     <path
-       style="fill:none;fill-rule:evenodd;stroke:#000000;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;marker-end:url(#marker5009)"
-       d="m 474.7717,339.19451 66.67007,30.30458"
-       id="path4591"
-       inkscape:connector-curvature="0"
-       sodipodi:nodetypes="cc" />
-    <path
-       style="fill:none;fill-rule:evenodd;stroke:#000000;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;marker-start:url(#Arrow1Lstart)"
-       d="m 480.83262,383.64122 64.64975,28.28427"
-       id="path4593"
-       inkscape:connector-curvature="0"
-       sodipodi:nodetypes="cc" />
-    <path
-       style="fill:none;fill-rule:evenodd;stroke:#000000;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;marker-end:url(#marker4963)"
-       d="m 478.81231,244.24016 66.67007,10.10154"
-       id="path4595"
-       inkscape:connector-curvature="0"
-       sodipodi:nodetypes="cc" />
-    <path
-       style="fill:none;fill-rule:evenodd;stroke:#000000;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;marker-end:url(#Arrow1Lend)"
-       d="m 377.79705,248.28078 42.42641,-6.06091"
-       id="path4597"
-       inkscape:connector-curvature="0"
-       sodipodi:nodetypes="cc" />
-    <path
-       style="fill:none;fill-rule:evenodd;stroke:#000000;stroke-width:0.9164362px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;marker-end:url(#marker4923)"
-       d="m 377.75479,246.23771 42.51093,90.95926"
-       id="path4599"
-       inkscape:connector-curvature="0"
-       sodipodi:nodetypes="cc" />
-    <path
-       style="fill:none;fill-rule:evenodd;stroke:#000000;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;marker-start:url(#marker5465)"
-       d="m 379.79706,363.43817 40.40609,-74.75129"
-       id="path4601"
-       inkscape:connector-curvature="0"
-       sodipodi:nodetypes="cc" />
+       style="display:inline;fill:none;stroke:#000000;stroke-width:0.32100001;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1;marker-start:url(#marker22960-9-7)"
+       d="m 180.34547,39.926779 c 8.28536,0 8.28536,0 8.28536,0"
+       id="path14783-8-5-3"
+       inkscape:connector-curvature="0" />
     <path
-       style="fill:none;fill-rule:evenodd;stroke:#000000;stroke-width:1.15162241px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;marker-start:url(#marker5547)"
-       d="m 377.82552,361.46823 48.43039,24.14292"
-       id="path4603"
-       inkscape:connector-curvature="0"
-       sodipodi:nodetypes="cc" />
+       style="display:inline;fill:none;stroke:#000000;stroke-width:0.32100001;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1;marker-end:url(#marker14793-1-9-6)"
+       d="m 179.87467,34.701979 c 8.28536,0 8.28536,0 8.28536,0"
+       id="path14783-87-5-1"
+       inkscape:connector-curvature="0" />
   </g>
 </svg>
-- 
1.9.1

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

* [spp] [PATCH 09/30] doc: fix figure in spp_vf_overview
  2018-01-15 11:04 ` [spp] Proposal - spp_vf(SR-IOV like feature) addition to SPP Ferruh Yigit
                     ` (7 preceding siblings ...)
  2018-01-16  5:16   ` [spp] [PATCH 08/30] doc: modify figure in spp_vf_overview x-fn-spp
@ 2018-01-16  5:16   ` x-fn-spp
  2018-01-16  5:16   ` [spp] [PATCH 10/30] doc: fix figure in overview x-fn-spp
                     ` (20 subsequent siblings)
  29 siblings, 0 replies; 97+ messages in thread
From: x-fn-spp @ 2018-01-16  5:16 UTC (permalink / raw)
  To: spp

From: Hiroyuki Nakamura <nakamura.hioryuki@po.ntt-tx.co.jp>

Fix arrow in spp_vf_overview.svg.

Signed-off-by: Tomoyuki Mizuguchi <mizuguchi.tomoyuki@po.ntt-tx.co.jp>
Signed-off-by: Naoki Takada <takada.naoki@lab.ntt.co.jp>
---
 docs/spp_vf/spp_vf_overview.svg | 586 +++++++++++++++++++++-------------------
 1 file changed, 307 insertions(+), 279 deletions(-)

diff --git a/docs/spp_vf/spp_vf_overview.svg b/docs/spp_vf/spp_vf_overview.svg
index 9115e66..adfe93e 100644
--- a/docs/spp_vf/spp_vf_overview.svg
+++ b/docs/spp_vf/spp_vf_overview.svg
@@ -9,13 +9,13 @@
    xmlns="http://www.w3.org/2000/svg"
    xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
    xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
-   width="230.12679mm"
-   height="159.57605mm"
-   viewBox="0 0 230.12679 159.57605"
+   width="172.52679mm"
+   height="120.57605mm"
+   viewBox="0 0 172.52679 120.57605"
    version="1.1"
    id="svg4746"
-   inkscape:version="0.92.1 r15371"
-   sodipodi:docname="spp_vf_overview.svg">
+   inkscape:version="0.92.2 (5c3e80d, 2017-08-06)"
+   sodipodi:docname="spp_vf_overview_r1.svg">
   <defs
      id="defs4740">
     <marker
@@ -23,6 +23,21 @@
        orient="auto"
        refY="0"
        refX="0"
+       id="marker6489"
+       style="overflow:visible"
+       inkscape:isstock="true">
+      <path
+         inkscape:connector-curvature="0"
+         id="path6487"
+         style="fill:#000000;fill-opacity:1;fill-rule:evenodd;stroke:#000000;stroke-width:0.625;stroke-linejoin:round;stroke-opacity:1"
+         d="M 8.7185878,4.0337352 -2.2072895,0.01601326 8.7185884,-4.0017078 c -1.7454984,2.3720609 -1.7354408,5.6174519 -6e-7,8.035443 z"
+         transform="matrix(-1.1,0,0,-1.1,-1.1,0)" />
+    </marker>
+    <marker
+       inkscape:stockid="Arrow2Lend"
+       orient="auto"
+       refY="0"
+       refX="0"
        id="marker8593"
        style="overflow:visible"
        inkscape:isstock="true">
@@ -974,21 +989,23 @@
      borderopacity="1.0"
      inkscape:pageopacity="0.0"
      inkscape:pageshadow="2"
-     inkscape:zoom="0.7"
-     inkscape:cx="176.84477"
-     inkscape:cy="58.190232"
+     inkscape:zoom="0.9899495"
+     inkscape:cx="457.38747"
+     inkscape:cy="223.84187"
      inkscape:document-units="mm"
      inkscape:current-layer="layer1"
      showgrid="false"
-     inkscape:window-width="1920"
-     inkscape:window-height="1138"
-     inkscape:window-x="-8"
-     inkscape:window-y="-8"
+     inkscape:window-width="1084"
+     inkscape:window-height="664"
+     inkscape:window-x="148"
+     inkscape:window-y="1047"
      inkscape:window-maximized="1"
      fit-margin-top="0"
      fit-margin-left="0"
      fit-margin-right="0"
-     fit-margin-bottom="0" />
+     fit-margin-bottom="0"
+     viewbox-x="0"
+     scale-x="1" />
   <metadata
      id="metadata4743">
     <rdf:RDF>
@@ -1006,26 +1023,26 @@
      inkscape:groupmode="layer"
      id="layer1"
      style="display:inline;opacity:0.98999999"
-     transform="translate(22.342263,-3.6416683)">
+     transform="translate(22.342263,-42.641668)">
     <rect
-       style="fill:#ffffff;fill-opacity:1;stroke:#000000;stroke-width:0.40874681;stroke-miterlimit:4;stroke-dasharray:none"
+       style="fill:#ffffff;fill-opacity:1;stroke:#000000;stroke-width:0.3065601;stroke-miterlimit:4;stroke-dasharray:none"
        id="rect5291"
-       width="178.01804"
-       height="110.73827"
-       x="29.562109"
-       y="3.8460417"
+       width="133.51352"
+       height="83.053703"
+       x="16.513613"
+       y="43.498409"
        ry="0" />
     <text
        xml:space="preserve"
-       style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:6.3499999px;line-height:1.25;font-family:sans-serif;-inkscape-font-specification:'sans-serif, Normal';font-variant-ligatures:normal;font-variant-caps:normal;font-variant-numeric:normal;font-feature-settings:normal;text-align:start;letter-spacing:0px;word-spacing:0px;writing-mode:lr-tb;text-anchor:start;fill:#000000;fill-opacity:1;stroke:none;stroke-width:0.26458332"
-       x="31.447617"
-       y="10.645233"
+       style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:4.76249981px;line-height:1.25;font-family:sans-serif;-inkscape-font-specification:'sans-serif, Normal';font-variant-ligatures:normal;font-variant-caps:normal;font-variant-numeric:normal;font-feature-settings:normal;text-align:start;letter-spacing:0px;word-spacing:0px;writing-mode:lr-tb;text-anchor:start;fill:#000000;fill-opacity:1;stroke:none;stroke-width:0.19843748"
+       x="17.927746"
+       y="48.597805"
        id="text5577"><tspan
          sodipodi:role="line"
          id="tspan5575"
-         x="31.447617"
-         y="10.645233"
-         style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:6.3499999px;font-family:sans-serif;-inkscape-font-specification:'sans-serif, Normal';font-variant-ligatures:normal;font-variant-caps:normal;font-variant-numeric:normal;font-feature-settings:normal;text-align:start;writing-mode:lr-tb;text-anchor:start;stroke-width:0.26458332">host1</tspan></text>
+         x="17.927746"
+         y="48.597805"
+         style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:4.76249981px;font-family:sans-serif;-inkscape-font-specification:'sans-serif, Normal';font-variant-ligatures:normal;font-variant-caps:normal;font-variant-numeric:normal;font-feature-settings:normal;text-align:start;writing-mode:lr-tb;text-anchor:start;stroke-width:0.19843748">host1</tspan></text>
     <flowRoot
        xml:space="preserve"
        id="flowRoot5610"
@@ -1038,90 +1055,94 @@
            x="147.14285"
            y="89.662544" /></flowRegion><flowPara
          id="flowPara5616" /></flowRoot>    <rect
-       style="opacity:1;fill:#ffff00;fill-opacity:1;stroke:#000000;stroke-width:0.15749259;stroke-miterlimit:4;stroke-dasharray:none"
+       style="opacity:1;fill:#ffff00;fill-opacity:1;stroke:#000000;stroke-width:0.11811945;stroke-miterlimit:4;stroke-dasharray:none"
        id="rect1139-1-3"
-       width="12.284646"
-       height="22.0905"
-       x="29.61422"
-       y="50.24823" />
+       width="9.2134848"
+       height="16.567875"
+       x="16.552696"
+       y="78.300049" />
     <text
        xml:space="preserve"
-       style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:4.93888903px;line-height:1.25;font-family:sans-serif;-inkscape-font-specification:'sans-serif, Normal';font-variant-ligatures:normal;font-variant-caps:normal;font-variant-numeric:normal;font-feature-settings:normal;text-align:start;letter-spacing:0px;word-spacing:0px;writing-mode:lr-tb;text-anchor:start;fill:#000000;fill-opacity:1;stroke:none;stroke-width:0.26458332"
-       x="31.113701"
-       y="62.265713"
+       style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:3.70416689px;line-height:1.25;font-family:sans-serif;-inkscape-font-specification:'sans-serif, Normal';font-variant-ligatures:normal;font-variant-caps:normal;font-variant-numeric:normal;font-feature-settings:normal;text-align:start;letter-spacing:0px;word-spacing:0px;writing-mode:lr-tb;text-anchor:start;fill:#000000;fill-opacity:1;stroke:none;stroke-width:0.19843748"
+       x="17.677307"
+       y="87.313164"
        id="text2024-9-4-2"><tspan
          sodipodi:role="line"
          id="tspan1471"
-         x="31.113701"
-         y="62.265713">NIC</tspan></text>
+         x="17.677307"
+         y="87.313164"
+         style="stroke-width:0.19843748">NIC</tspan></text>
     <rect
-       style="display:inline;fill:#ffffff;fill-opacity:1;stroke:#000000;stroke-width:0.17385828;stroke-miterlimit:4;stroke-dasharray:none"
+       style="display:inline;fill:#ffffff;fill-opacity:1;stroke:#000000;stroke-width:0.13039371;stroke-miterlimit:4;stroke-dasharray:none"
        id="rect5291-3"
-       width="89.598312"
-       height="39.805573"
-       x="28.648361"
-       y="123.32521"
+       width="67.19873"
+       height="29.854179"
+       x="15.828302"
+       y="133.1078"
        ry="0" />
     <text
        xml:space="preserve"
-       style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:6.3499999px;line-height:1.25;font-family:sans-serif;-inkscape-font-specification:'sans-serif, Normal';font-variant-ligatures:normal;font-variant-caps:normal;font-variant-numeric:normal;font-feature-settings:normal;text-align:start;letter-spacing:0px;word-spacing:0px;writing-mode:lr-tb;text-anchor:start;display:inline;fill:#000000;fill-opacity:1;stroke:none;stroke-width:0.26458332"
-       x="30.379715"
-       y="130.27429"
+       style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:4.76249981px;line-height:1.25;font-family:sans-serif;-inkscape-font-specification:'sans-serif, Normal';font-variant-ligatures:normal;font-variant-caps:normal;font-variant-numeric:normal;font-feature-settings:normal;text-align:start;letter-spacing:0px;word-spacing:0px;writing-mode:lr-tb;text-anchor:start;display:inline;fill:#000000;fill-opacity:1;stroke:none;stroke-width:0.19843748"
+       x="17.12682"
+       y="138.31961"
        id="text5577-4"><tspan
          sodipodi:role="line"
          id="tspan29058"
-         x="30.379715"
-         y="130.27429">host2</tspan></text>
+         x="17.12682"
+         y="138.31961"
+         style="stroke-width:0.19843748">host2</tspan></text>
     <rect
-       style="display:inline;opacity:1;fill:#ffff00;fill-opacity:1;stroke:#000000;stroke-width:0.14192471;stroke-miterlimit:4;stroke-dasharray:none"
+       style="display:inline;opacity:1;fill:#ffff00;fill-opacity:1;stroke:#000000;stroke-width:0.10644353;stroke-miterlimit:4;stroke-dasharray:none"
        id="rect1139-1-3-3"
-       width="12.318476"
-       height="17.889858"
-       x="28.756187"
-       y="134.93675" />
+       width="9.2388563"
+       height="13.417394"
+       x="15.90917"
+       y="141.81644" />
     <text
        xml:space="preserve"
-       style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:4.93888903px;line-height:1.25;font-family:sans-serif;-inkscape-font-specification:'sans-serif, Normal';font-variant-ligatures:normal;font-variant-caps:normal;font-variant-numeric:normal;font-feature-settings:normal;text-align:start;letter-spacing:0px;word-spacing:0px;writing-mode:lr-tb;text-anchor:start;display:inline;fill:#000000;fill-opacity:1;stroke:none;stroke-width:0.26458332"
-       x="29.824566"
-       y="144.7765"
+       style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:3.70416689px;line-height:1.25;font-family:sans-serif;-inkscape-font-specification:'sans-serif, Normal';font-variant-ligatures:normal;font-variant-caps:normal;font-variant-numeric:normal;font-feature-settings:normal;text-align:start;letter-spacing:0px;word-spacing:0px;writing-mode:lr-tb;text-anchor:start;display:inline;fill:#000000;fill-opacity:1;stroke:none;stroke-width:0.19843748"
+       x="16.710455"
+       y="149.19623"
        id="text2024-9-4-2-1"><tspan
          sodipodi:role="line"
          id="tspan3496"
-         x="29.824566"
-         y="144.7765">NIC</tspan></text>
+         x="16.710455"
+         y="149.19623"
+         style="stroke-width:0.19843748">NIC</tspan></text>
     <path
-       style="fill:none;stroke:#000000;stroke-width:0.30599999;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1;marker-end:url(#marker6219)"
-       d="m -4.009306,100.27164 c 0,0 3.23928417,-32.79676 33.380621,-44.354729"
+       style="fill:none;stroke:#000000;stroke-width:0.2295;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1;marker-end:url(#marker6219)"
+       d="m -8.6649471,115.81761 c 0,0 2.429464,-24.597571 25.0354661,-33.266048"
        id="path29105"
        inkscape:connector-curvature="0" />
     <path
-       style="display:inline;fill:none;stroke:#000000;stroke-width:0.21055813;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
-       d="m 7.418426,100.11915 c 0,0 2.1555199,-23.348561 22.212484,-31.576878"
+       style="display:inline;fill:none;stroke:#000000;stroke-width:0.1579186;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
+       d="m -0.09414816,115.70324 c 0,0 1.61663996,-17.511419 16.65936316,-23.682657"
        id="path29105-6"
        inkscape:connector-curvature="0" />
     <path
-       style="display:inline;opacity:1;fill:#fff6d5;fill-opacity:1;stroke:#000000;stroke-width:0.37257931;stroke-miterlimit:4;stroke-dasharray:none"
-       d="m -0.48373683,81.021671 a 6.3984709,4.6624236 0 0 0 -6.27253387,3.743049 6.3984709,4.6624236 0 0 0 -2.8094903,-0.479359 6.3984709,4.6624236 0 0 0 -6.398387,4.662252 6.3984709,4.6624236 0 0 0 0.8889,2.359802 6.3984709,4.6624236 0 0 0 -0.682338,-0.02869 6.3984709,4.6624236 0 0 0 -6.398387,4.662891 6.3984709,4.6624236 0 0 0 3.020001,3.952152 6.3984709,4.6624236 0 0 0 -2.194312,3.507202 6.3984709,4.6624236 0 0 0 4.721047,4.49395 6.3984709,4.6624236 0 0 0 -1.005726,2.50004 6.3984709,4.6624236 0 0 0 6.398385,4.66225 6.3984709,4.6624236 0 0 0 3.5166639,-0.77004 6.3984709,4.6624236 0 0 0 6.3904879,4.50035 6.3984709,4.6624236 0 0 0 5.8678712,-2.80856 6.3984709,4.6624236 0 0 0 2.8010237,0.4768 6.3984709,4.6624236 0 0 0 6.3983903,-4.66225 6.3984709,4.6624236 0 0 0 -5.68e-4,-0.008 6.3984709,4.6624236 0 0 0 0.207129,0.008 6.3984709,4.6624236 0 0 0 6.398393,-4.66224 6.3984709,4.6624236 0 0 0 -1.543584,-3.02912 6.3984709,4.6624236 0 0 0 4.433215,-4.43086 6.3984709,4.6624236 0 0 !
 0 -3.140218,-4.006328 6.3984709,4.6624236 0 0 0 0.663148,-2.055112 6.3984709,4.6624236 0 0 0 -5.209239,-4.578099 6.3984709,4.6624236 0 0 0 0.04966,-0.550116 6.3984709,4.6624236 0 0 0 -6.3989562,-4.662874 6.3984709,4.6624236 0 0 0 -3.4923868,0.757914 6.3984709,4.6624236 0 0 0 -6.20819523,-3.555001 z"
+       style="display:inline;opacity:1;fill:#fff6d5;fill-opacity:1;stroke:#000000;stroke-width:0.27943447;stroke-miterlimit:4;stroke-dasharray:none"
+       d="m -6.0207701,101.38013 a 4.7988532,3.4968177 0 0 0 -4.7043999,2.80729 4.7988532,3.4968177 0 0 0 -2.107118,-0.35952 4.7988532,3.4968177 0 0 0 -4.798788,3.49669 4.7988532,3.4968177 0 0 0 0.666675,1.76985 4.7988532,3.4968177 0 0 0 -0.511754,-0.0215 4.7988532,3.4968177 0 0 0 -4.798789,3.49716 4.7988532,3.4968177 0 0 0 2.265001,2.96412 4.7988532,3.4968177 0 0 0 -1.645734,2.6304 4.7988532,3.4968177 0 0 0 3.540784,3.37048 4.7988532,3.4968177 0 0 0 -0.754294,1.87503 4.7988532,3.4968177 0 0 0 4.798786,3.49669 4.7988532,3.4968177 0 0 0 2.637498,-0.57753 4.7988532,3.4968177 0 0 0 4.7928659,3.37526 4.7988532,3.4968177 0 0 0 4.400904,-2.10642 4.7988532,3.4968177 0 0 0 2.10076694,0.3576 4.7988532,3.4968177 0 0 0 4.79879306,-3.49669 4.7988532,3.4968177 0 0 0 -4.26e-4,-0.006 4.7988532,3.4968177 0 0 0 0.155347,0.006 4.7988532,3.4968177 0 0 0 4.798795,-3.49668 4.7988532,3.4968177 0 0 0 -1.157688,-2.27185 4.7988532,3.4968177 0 0 0 3.3249111,-3.32315 4.7988532,3.4968177 0 0 0 -2.3551!
 641,-3.00475 4.7988532,3.4968177 0 0 0 0.497361,-1.54133 4.7988532,3.4968177 0 0 0 -3.906929,-3.43357 4.7988532,3.4968177 0 0 0 0.03724,-0.41259 4.7988532,3.4968177 0 0 0 -4.7992171,-3.49716 4.7988532,3.4968177 0 0 0 -2.6192899,0.56844 4.7988532,3.4968177 0 0 0 -4.656146,-2.66625 z"
        id="path3410"
        inkscape:connector-curvature="0" />
     <text
        xml:space="preserve"
-       style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:6.3499999px;line-height:1.25;font-family:sans-serif;-inkscape-font-specification:'sans-serif, Normal';font-variant-ligatures:normal;font-variant-caps:normal;font-variant-numeric:normal;font-feature-settings:normal;text-align:start;letter-spacing:0px;word-spacing:0px;writing-mode:lr-tb;text-anchor:start;display:inline;fill:#000000;fill-opacity:1;stroke:none;stroke-width:0.26458332"
-       x="-12.727088"
-       y="103.29467"
+       style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:4.76249981px;line-height:1.25;font-family:sans-serif;-inkscape-font-specification:'sans-serif, Normal';font-variant-ligatures:normal;font-variant-caps:normal;font-variant-numeric:normal;font-feature-settings:normal;text-align:start;letter-spacing:0px;word-spacing:0px;writing-mode:lr-tb;text-anchor:start;display:inline;fill:#000000;fill-opacity:1;stroke:none;stroke-width:0.19843748"
+       x="-15.203279"
+       y="118.08487"
        id="text5577-1"><tspan
          sodipodi:role="line"
          id="tspan28860"
-         x="-12.727088"
-         y="103.29467">network</tspan></text>
+         x="-15.203279"
+         y="118.08487"
+         style="stroke-width:0.19843748">network</tspan></text>
     <path
-       style="fill:none;stroke:#000000;stroke-width:0.2374312px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;marker-end:url(#marker8593)"
-       d="m 6.6332697,116.02444 c 0,0 1.8657623,22.06334 21.9335053,23.14219"
+       style="fill:none;stroke:#000000;stroke-width:0.17807341px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;marker-end:url(#marker8593)"
+       d="m -0.68301513,127.63222 c 0,0 1.39932195,16.54751 16.45012913,17.35664"
        id="path3498"
        inkscape:connector-curvature="0" />
     <path
-       style="display:inline;opacity:0.98999999;fill:none;stroke:#000000;stroke-width:0.31829059px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
-       d="m -2.154263,118.70072 c 0,0 2.63281346,28.09834 30.950739,29.47229"
+       style="display:inline;opacity:0.98999999;fill:none;stroke:#000000;stroke-width:0.23871794px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
+       d="m -7.2736641,129.63943 c 0,0 1.97461,21.07376 23.2130541,22.10422"
        id="path3498-4"
        inkscape:connector-curvature="0" />
   </g>
@@ -1130,168 +1151,147 @@
      id="layer3"
      inkscape:label="spp_vf_process"
      style="display:inline"
-     transform="translate(22.342263,-3.6416683)">
+     transform="translate(22.342263,-42.641668)">
     <rect
-       style="fill:#ffccaa;fill-opacity:1;stroke:#000000;stroke-width:0.27500245;stroke-miterlimit:4;stroke-dasharray:none"
+       style="fill:#ffccaa;fill-opacity:1;stroke:#000000;stroke-width:0.20625183;stroke-miterlimit:4;stroke-dasharray:none"
        id="rect1763"
-       width="89.898491"
-       height="84.881256"
-       x="45.238247"
-       y="20.835232"
-       ry="4.4250889" />
+       width="67.423866"
+       height="63.660942"
+       x="28.270718"
+       y="56.240303"
+       ry="3.3188167" />
     <text
        xml:space="preserve"
-       style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:4.93888903px;line-height:1.25;font-family:sans-serif;-inkscape-font-specification:'sans-serif, Normal';font-variant-ligatures:normal;font-variant-caps:normal;font-variant-numeric:normal;font-feature-settings:normal;text-align:start;letter-spacing:0px;word-spacing:0px;writing-mode:lr-tb;text-anchor:start;fill:#000000;fill-opacity:1;stroke:none;stroke-width:0.26458332"
-       x="49.590477"
-       y="27.276197"
+       style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:3.70416689px;line-height:1.25;font-family:sans-serif;-inkscape-font-specification:'sans-serif, Normal';font-variant-ligatures:normal;font-variant-caps:normal;font-variant-numeric:normal;font-feature-settings:normal;text-align:start;letter-spacing:0px;word-spacing:0px;writing-mode:lr-tb;text-anchor:start;fill:#000000;fill-opacity:1;stroke:none;stroke-width:0.19843748"
+       x="31.534889"
+       y="61.07103"
        id="text1767"><tspan
          sodipodi:role="line"
          id="tspan1765"
-         x="49.590477"
-         y="27.276197"
-         style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:4.93888903px;font-family:sans-serif;-inkscape-font-specification:'sans-serif, Normal';font-variant-ligatures:normal;font-variant-caps:normal;font-variant-numeric:normal;font-feature-settings:normal;text-align:start;writing-mode:lr-tb;text-anchor:start;stroke-width:0.26458332">spp_vf</tspan></text>
+         x="31.534889"
+         y="61.07103"
+         style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:3.70416689px;font-family:sans-serif;-inkscape-font-specification:'sans-serif, Normal';font-variant-ligatures:normal;font-variant-caps:normal;font-variant-numeric:normal;font-feature-settings:normal;text-align:start;writing-mode:lr-tb;text-anchor:start;stroke-width:0.19843748">spp_vf</tspan></text>
   </g>
   <g
      inkscape:groupmode="layer"
      id="layer4"
      inkscape:label="guests"
      style="display:inline"
-     transform="translate(22.342263,-3.6416683)">
+     transform="translate(22.342263,-42.641668)">
     <rect
-       style="fill:#f9f9f9;fill-opacity:1;stroke:#000000;stroke-width:0.2328189;stroke-miterlimit:4;stroke-dasharray:none"
+       style="fill:#f9f9f9;fill-opacity:1;stroke:#000000;stroke-width:0.17461418;stroke-miterlimit:4;stroke-dasharray:none"
        id="rect2020"
-       width="37.802731"
-       height="44.68745"
-       x="166.01413"
-       y="10.521609"
-       ry="3.7239535" />
+       width="28.352047"
+       height="33.515587"
+       x="118.85268"
+       y="48.505085"
+       ry="2.7929652" />
     <text
        xml:space="preserve"
-       style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:4.93888903px;line-height:1.25;font-family:sans-serif;-inkscape-font-specification:'sans-serif, Normal';font-variant-ligatures:normal;font-variant-caps:normal;font-variant-numeric:normal;font-feature-settings:normal;text-align:start;letter-spacing:0px;word-spacing:0px;writing-mode:lr-tb;text-anchor:start;fill:#000000;fill-opacity:1;stroke:none;stroke-width:0.26458332"
-       x="167.14098"
-       y="21.077375"
+       style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:3.70416689px;line-height:1.25;font-family:sans-serif;-inkscape-font-specification:'sans-serif, Normal';font-variant-ligatures:normal;font-variant-caps:normal;font-variant-numeric:normal;font-feature-settings:normal;text-align:start;letter-spacing:0px;word-spacing:0px;writing-mode:lr-tb;text-anchor:start;fill:#000000;fill-opacity:1;stroke:none;stroke-width:0.19843748"
+       x="119.69781"
+       y="56.421913"
        id="text2024"><tspan
          sodipodi:role="line"
          id="tspan2022"
-         x="167.14098"
-         y="21.077375"
-         style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:4.93888903px;font-family:sans-serif;-inkscape-font-specification:'sans-serif, Normal';font-variant-ligatures:normal;font-variant-caps:normal;font-variant-numeric:normal;font-feature-settings:normal;text-align:start;writing-mode:lr-tb;text-anchor:start;stroke-width:0.26458332">guest vm1</tspan></text>
+         x="119.69781"
+         y="56.421913"
+         style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:3.70416689px;font-family:sans-serif;-inkscape-font-specification:'sans-serif, Normal';font-variant-ligatures:normal;font-variant-caps:normal;font-variant-numeric:normal;font-feature-settings:normal;text-align:start;writing-mode:lr-tb;text-anchor:start;stroke-width:0.19843748">guest vm1</tspan></text>
     <rect
-       style="fill:#f9f9f9;fill-opacity:1;stroke:#000000;stroke-width:0.23468868;stroke-miterlimit:4;stroke-dasharray:none"
+       style="fill:#f9f9f9;fill-opacity:1;stroke:#000000;stroke-width:0.17601651;stroke-miterlimit:4;stroke-dasharray:none"
        id="rect2020-5"
-       width="38.168907"
-       height="44.972477"
-       x="165.62701"
-       y="63.981018"
-       ry="3.7477062" />
+       width="28.62668"
+       height="33.729359"
+       x="118.56235"
+       y="88.59964"
+       ry="2.8107796" />
     <text
        xml:space="preserve"
-       style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:4.93888903px;line-height:1.25;font-family:sans-serif;-inkscape-font-specification:'sans-serif, Normal';font-variant-ligatures:normal;font-variant-caps:normal;font-variant-numeric:normal;font-feature-settings:normal;text-align:start;letter-spacing:0px;word-spacing:0px;writing-mode:lr-tb;text-anchor:start;fill:#000000;fill-opacity:1;stroke:none;stroke-width:0.26458332"
-       x="166.74794"
-       y="70.292007"
+       style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:3.70416689px;line-height:1.25;font-family:sans-serif;-inkscape-font-specification:'sans-serif, Normal';font-variant-ligatures:normal;font-variant-caps:normal;font-variant-numeric:normal;font-feature-settings:normal;text-align:start;letter-spacing:0px;word-spacing:0px;writing-mode:lr-tb;text-anchor:start;fill:#000000;fill-opacity:1;stroke:none;stroke-width:0.19843748"
+       x="119.40305"
+       y="93.332886"
        id="text2024-5"><tspan
          sodipodi:role="line"
          id="tspan2202"
-         x="166.74794"
-         y="70.292007">guest vm2</tspan></text>
+         x="119.40305"
+         y="93.332886"
+         style="stroke-width:0.19843748">guest vm2</tspan></text>
     <rect
-       style="opacity:1;fill:#ffff00;fill-opacity:1;stroke:#000000;stroke-width:0.14875925;stroke-miterlimit:4;stroke-dasharray:none"
+       style="opacity:1;fill:#ffff00;fill-opacity:1;stroke:#000000;stroke-width:0.11156943;stroke-miterlimit:4;stroke-dasharray:none"
        id="rect1139"
-       width="13.798667"
-       height="17.546024"
-       x="166.01764"
-       y="29.789093" />
+       width="10.349"
+       height="13.159518"
+       x="118.85532"
+       y="62.9557" />
     <text
        xml:space="preserve"
-       style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:4.93888903px;line-height:1.25;font-family:sans-serif;-inkscape-font-specification:'sans-serif, Normal';font-variant-ligatures:normal;font-variant-caps:normal;font-variant-numeric:normal;font-feature-settings:normal;text-align:start;letter-spacing:0px;word-spacing:0px;writing-mode:lr-tb;text-anchor:start;fill:#000000;fill-opacity:1;stroke:none;stroke-width:0.26458332"
-       x="166.83788"
-       y="40.360432"
+       style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:3.70416689px;line-height:1.25;font-family:sans-serif;-inkscape-font-specification:'sans-serif, Normal';font-variant-ligatures:normal;font-variant-caps:normal;font-variant-numeric:normal;font-feature-settings:normal;text-align:start;letter-spacing:0px;word-spacing:0px;writing-mode:lr-tb;text-anchor:start;fill:#000000;fill-opacity:1;stroke:none;stroke-width:0.19843748"
+       x="119.4705"
+       y="70.884201"
        id="text2024-9"><tspan
          sodipodi:role="line"
          id="tspan1504"
-         x="166.83788"
-         y="40.360432">vNIC</tspan></text>
+         x="119.4705"
+         y="70.884201"
+         style="stroke-width:0.19843748">vNIC</tspan></text>
     <rect
-       style="opacity:1;fill:#ffff00;fill-opacity:1;stroke:#000000;stroke-width:0.15045834;stroke-miterlimit:4;stroke-dasharray:none"
+       style="opacity:1;fill:#ffff00;fill-opacity:1;stroke:#000000;stroke-width:0.11284375;stroke-miterlimit:4;stroke-dasharray:none"
        id="rect1139-1"
-       width="13.805234"
-       height="17.94058"
-       x="165.57541"
-       y="77.986526" />
+       width="10.353926"
+       height="13.455435"
+       x="118.52364"
+       y="99.103775" />
     <text
        xml:space="preserve"
-       style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:4.93888903px;line-height:1.25;font-family:sans-serif;-inkscape-font-specification:'sans-serif, Normal';font-variant-ligatures:normal;font-variant-caps:normal;font-variant-numeric:normal;font-feature-settings:normal;text-align:start;letter-spacing:0px;word-spacing:0px;writing-mode:lr-tb;text-anchor:start;fill:#000000;fill-opacity:1;stroke:none;stroke-width:0.26458332"
-       x="166.39893"
-       y="88.495567"
+       style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:3.70416689px;line-height:1.25;font-family:sans-serif;-inkscape-font-specification:'sans-serif, Normal';font-variant-ligatures:normal;font-variant-caps:normal;font-variant-numeric:normal;font-feature-settings:normal;text-align:start;letter-spacing:0px;word-spacing:0px;writing-mode:lr-tb;text-anchor:start;fill:#000000;fill-opacity:1;stroke:none;stroke-width:0.19843748"
+       x="119.14127"
+       y="106.98555"
        id="text2024-9-4"><tspan
          sodipodi:role="line"
          id="tspan1502"
-         x="166.39893"
-         y="88.495567">vNIC</tspan></text>
+         x="119.14127"
+         y="106.98555"
+         style="stroke-width:0.19843748">vNIC</tspan></text>
   </g>
   <g
      inkscape:groupmode="layer"
      id="layer2"
      inkscape:label="spp_vf_threads"
-     style="display:inline"
-     transform="translate(22.342263,-3.6416683)">
+     style="display:inline;opacity:0.98999999"
+     transform="translate(22.342263,-42.641668)">
     <text
        xml:space="preserve"
-       style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:4.93888903px;line-height:1.25;font-family:sans-serif;-inkscape-font-specification:'sans-serif, Normal';font-variant-ligatures:normal;font-variant-caps:normal;font-variant-numeric:normal;font-feature-settings:normal;text-align:start;letter-spacing:0px;word-spacing:0px;writing-mode:lr-tb;text-anchor:start;fill:#d7f4e3;fill-opacity:1;stroke:none;stroke-width:0.26458332"
-       x="83.429108"
-       y="34.468502"
+       style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:3.70416689px;line-height:1.25;font-family:sans-serif;-inkscape-font-specification:'sans-serif, Normal';font-variant-ligatures:normal;font-variant-caps:normal;font-variant-numeric:normal;font-feature-settings:normal;text-align:start;letter-spacing:0px;word-spacing:0px;writing-mode:lr-tb;text-anchor:start;fill:#d7f4e3;fill-opacity:1;stroke:none;stroke-width:0.19843748"
+       x="56.913864"
+       y="66.465256"
        id="text16968"><tspan
          sodipodi:role="line"
          id="tspan16966"
-         x="83.429108"
-         y="34.468502"
-         style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:4.93888903px;font-family:sans-serif;-inkscape-font-specification:'sans-serif, Normal';font-variant-ligatures:normal;font-variant-caps:normal;font-variant-numeric:normal;font-feature-settings:normal;text-align:start;writing-mode:lr-tb;text-anchor:start;fill:#d7f4e3;stroke-width:0.26458332">ring</tspan></text>
+         x="56.913864"
+         y="66.465256"
+         style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:3.70416689px;font-family:sans-serif;-inkscape-font-specification:'sans-serif, Normal';font-variant-ligatures:normal;font-variant-caps:normal;font-variant-numeric:normal;font-feature-settings:normal;text-align:start;writing-mode:lr-tb;text-anchor:start;fill:#d7f4e3;stroke-width:0.19843748">ring</tspan></text>
     <rect
-       style="fill:#ffe6d5;fill-opacity:1;stroke:#000000;stroke-width:0.17908682;stroke-miterlimit:4;stroke-dasharray:none"
+       style="fill:#ffe6d5;fill-opacity:1;stroke:#000000;stroke-width:0.13431512;stroke-miterlimit:4;stroke-dasharray:none"
        id="rect1769"
-       width="28.397127"
-       height="7.9864125"
-       x="48.280895"
-       y="33.148167"
-       ry="1.8033863" />
+       width="21.297846"
+       height="5.9898095"
+       x="30.552704"
+       y="65.475006"
+       ry="1.3525398" />
     <text
        xml:space="preserve"
-       style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:4.93888903px;line-height:1.25;font-family:sans-serif;-inkscape-font-specification:'sans-serif, Normal';font-variant-ligatures:normal;font-variant-caps:normal;font-variant-numeric:normal;font-feature-settings:normal;text-align:start;letter-spacing:0px;word-spacing:0px;writing-mode:lr-tb;text-anchor:start;fill:#000000;fill-opacity:1;stroke:none;stroke-width:0.26458332"
-       x="51.631538"
-       y="38.464291"
+       style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:3.70416689px;line-height:1.25;font-family:sans-serif;-inkscape-font-specification:'sans-serif, Normal';font-variant-ligatures:normal;font-variant-caps:normal;font-variant-numeric:normal;font-feature-settings:normal;text-align:start;letter-spacing:0px;word-spacing:0px;writing-mode:lr-tb;text-anchor:start;fill:#000000;fill-opacity:1;stroke:none;stroke-width:0.19843748"
+       x="33.065685"
+       y="69.462097"
        id="text1773"><tspan
          sodipodi:role="line"
          id="tspan1461"
-         x="51.631538"
-         y="38.464291">classifier</tspan></text>
-    <g
-       id="g1969"
-       transform="matrix(0.9931638,0,0,3.5726314,15.375,-412.81686)"
-       style="fill:#eef4d7">
-      <rect
-         ry="1.8106976"
-         y="122.52335"
-         x="124.54029"
-         height="8.0187912"
-         width="18.980101"
-         id="rect1769-3-2-7"
-         style="fill:#eef4d7;stroke:#000000;stroke-width:0.14670815;stroke-miterlimit:4;stroke-dasharray:none" />
-    </g>
-    <text
-       xml:space="preserve"
-       style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:4.93888903px;line-height:1.25;font-family:sans-serif;-inkscape-font-specification:'sans-serif, Normal';font-variant-ligatures:normal;font-variant-caps:normal;font-variant-numeric:normal;font-feature-settings:normal;text-align:start;letter-spacing:0px;word-spacing:0px;writing-mode:lr-tb;text-anchor:start;fill:#000000;fill-opacity:1;stroke:none;stroke-width:0.28356495"
-       x="152.11028"
-       y="38.115993"
-       id="text1773-6-6-5-2"
-       transform="scale(0.93214046,1.0727997)"><tspan
-         y="38.115993"
-         x="152.11028"
-         sodipodi:role="line"
-         id="tspan1964-1"
-         style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:4.93888903px;font-family:sans-serif;-inkscape-font-specification:'sans-serif, Normal';font-variant-ligatures:normal;font-variant-caps:normal;font-variant-numeric:normal;font-feature-settings:normal;text-align:start;writing-mode:lr-tb;text-anchor:start;stroke-width:0.28356495">vhost</tspan></text>
+         x="33.065685"
+         y="69.462097"
+         style="stroke-width:0.19843748">classifier</tspan></text>
     <g
        id="g1969-0"
-       transform="matrix(0.9931638,0,0,3.5726314,14.96627,-364.49553)"
+       transform="matrix(0.74487285,0,0,2.6794736,5.5667349,-232.75776)"
        style="fill:#dedbe3">
       <rect
          ry="1.8106976"
@@ -1304,107 +1304,98 @@
     </g>
     <text
        xml:space="preserve"
-       style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:4.93888903px;line-height:1.25;font-family:sans-serif;-inkscape-font-specification:'sans-serif, Normal';font-variant-ligatures:normal;font-variant-caps:normal;font-variant-numeric:normal;font-feature-settings:normal;text-align:start;letter-spacing:0px;word-spacing:0px;writing-mode:lr-tb;text-anchor:start;fill:#000000;fill-opacity:1;stroke:none;stroke-width:0.28356495"
-       x="151.67178"
-       y="82.664948"
+       style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:3.70416689px;line-height:1.25;font-family:sans-serif;-inkscape-font-specification:'sans-serif, Normal';font-variant-ligatures:normal;font-variant-caps:normal;font-variant-numeric:normal;font-feature-settings:normal;text-align:start;letter-spacing:0px;word-spacing:0px;writing-mode:lr-tb;text-anchor:start;fill:#000000;fill-opacity:1;stroke:none;stroke-width:0.21267372"
+       x="107.68398"
+       y="99.856544"
        id="text1773-6-6-5-2-7"
        transform="scale(0.93214046,1.0727997)"><tspan
-         y="82.664948"
-         x="151.67178"
+         y="99.856544"
+         x="107.68398"
          sodipodi:role="line"
          id="tspan1964-1-7"
-         style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:4.93888903px;font-family:sans-serif;-inkscape-font-specification:'sans-serif, Normal';font-variant-ligatures:normal;font-variant-caps:normal;font-variant-numeric:normal;font-feature-settings:normal;text-align:start;writing-mode:lr-tb;text-anchor:start;stroke-width:0.28356495">vhost</tspan></text>
+         style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:3.70416689px;font-family:sans-serif;-inkscape-font-specification:'sans-serif, Normal';font-variant-ligatures:normal;font-variant-caps:normal;font-variant-numeric:normal;font-feature-settings:normal;text-align:start;writing-mode:lr-tb;text-anchor:start;stroke-width:0.21267372">vhost</tspan></text>
     <path
-       style="fill:none;stroke:#000000;stroke-width:0.32100001;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1;marker-end:url(#marker13092)"
-       d="M 42.335746,51.022012 48.285474,39.502744"
+       style="fill:none;stroke:#000000;stroke-width:0.24075001;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1;marker-end:url(#marker13092)"
+       d="m 24.862305,78.74278 6.068157,-7.598004"
        id="path4812"
        inkscape:connector-curvature="0" />
     <path
-       style="fill:none;stroke:#000000;stroke-width:0.32100001;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1;marker-end:url(#marker14793)"
-       d="m 157.3851,33.909754 c 8.28536,0 8.28536,0 8.28536,0"
+       style="fill:none;stroke:#000000;stroke-width:0.24075001;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1;marker-end:url(#marker14793)"
+       d="m 112.38085,66.046195 c 6.21402,0 6.21402,0 6.21402,0"
        id="path14783"
        inkscape:connector-curvature="0" />
     <path
-       style="display:inline;fill:none;stroke:#000000;stroke-width:0.32100001;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1;marker-start:url(#marker22960)"
-       d="m 157.50554,90.770923 c 8.28536,0 8.28536,0 8.28536,0"
+       style="display:inline;fill:none;stroke:#000000;stroke-width:0.24075001;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1;marker-start:url(#marker22960)"
+       d="m 112.47118,108.69207 c 6.21402,0 6.21402,0 6.21402,0"
        id="path14783-8"
        inkscape:connector-curvature="0" />
     <path
-       style="fill:none;stroke:#000000;stroke-width:0.32100001;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1;marker-end:url(#marker26660)"
-       d="M 49.003632,85.315415 42.335746,68.542273"
+       style="fill:none;stroke:#000000;stroke-width:0.24075001;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1;marker-end:url(#marker26660)"
+       d="M 35.08879,104.73064 25.534813,95.139839"
        id="path26650"
        inkscape:connector-curvature="0" />
     <path
-       style="display:inline;fill:none;stroke:#000000;stroke-width:0.32100001;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1;marker-end:url(#marker14793-1)"
-       d="m 157.03474,82.371116 c 8.28536,0 8.28536,0 8.28536,0"
+       style="display:inline;fill:none;stroke:#000000;stroke-width:0.24075001;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1;marker-end:url(#marker14793-1)"
+       d="m 112.11808,102.39221 c 6.21402,0 6.21402,0 6.21402,0"
        id="path14783-87"
        inkscape:connector-curvature="0" />
     <path
-       style="display:inline;fill:none;stroke:#000000;stroke-width:0.32100001;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1;marker-start:url(#marker22960-5)"
-       d="m 157.84517,42.31872 c 8.28536,0 8.28536,0 8.28536,0"
+       style="display:inline;fill:none;stroke:#000000;stroke-width:0.24075001;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1;marker-start:url(#marker22960-5)"
+       d="m 112.7259,72.352919 c 6.21402,0 6.21402,0 6.21402,0"
        id="path14783-8-7"
        inkscape:connector-curvature="0" />
     <path
-       style="fill:none;stroke:#000000;stroke-width:0.32100001;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1;marker-end:url(#marker1560)"
-       d="m 129.87263,29.014883 c 8.88244,0 8.88244,0 8.88244,0"
+       style="fill:none;stroke:#000000;stroke-width:0.24075001;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1;marker-end:url(#marker1560)"
+       d="m 91.74648,62.375041 c 6.66183,0 6.66183,0 6.66183,0"
        id="path1556"
        inkscape:connector-curvature="0" />
     <path
-       style="display:inline;fill:none;stroke:#000000;stroke-width:0.30693886;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1;marker-start:url(#marker22960-7)"
-       d="m 131.14821,97.427195 c 7.57539,0 7.57539,0 7.57539,0"
+       style="display:inline;fill:none;stroke:#000000;stroke-width:0.23020414;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1;marker-start:url(#marker22960-7)"
+       d="m 92.70317,113.68427 c 5.68154,0 5.68154,0 5.68154,0"
        id="path14783-8-2"
        inkscape:connector-curvature="0" />
     <path
-       style="fill:none;stroke:#000000;stroke-width:0.32100001;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1;marker-end:url(#marker1608)"
-       d="m 129.53108,49.653739 c 8.59493,27.28568 8.59493,27.28568 8.59493,27.28568"
-       id="path1604"
-       inkscape:connector-curvature="0" />
-    <path
-       style="display:inline;fill:none;stroke:#000000;stroke-width:0.32100001;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1;marker-end:url(#marker1516)"
-       d="M 76.678022,36.901244 102.43288,28.78674"
+       style="display:inline;fill:none;stroke:#000000;stroke-width:0.24075001;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1;marker-end:url(#marker1516)"
+       d="M 51.850549,68.289812 71.166691,62.203934"
        id="path1506"
        inkscape:connector-curvature="0" />
     <path
-       style="display:inline;fill:none;stroke:#000000;stroke-width:0.32100001;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1;marker-end:url(#marker1864)"
-       d="M 76.678022,36.852335 C 102.47067,49.653739 102.47067,49.653739 102.47067,49.653739"
+       style="display:inline;fill:none;stroke:#000000;stroke-width:0.24075001;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1;marker-end:url(#marker1864)"
+       d="m 51.850549,68.25313 c 19.344482,9.601053 19.344482,9.601053 19.344482,9.601053"
        id="path1854"
        inkscape:connector-curvature="0" />
     <path
-       style="display:inline;fill:none;stroke:#000000;stroke-width:0.32100001;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1;marker-end:url(#marker2218)"
-       d="M 102.69746,77.094814 C 73.622505,86.323333 73.622505,86.323333 73.622505,86.323333"
+       style="display:inline;fill:none;stroke:#000000;stroke-width:0.24075001;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1;marker-end:url(#marker2218)"
+       d="m 71.365131,98.43499 c -21.806219,6.92139 -21.806219,6.92139 -21.806219,6.92139"
        id="path2208"
        inkscape:connector-curvature="0" />
     <path
-       style="fill:none;stroke:#000000;stroke-width:0.32100001;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1;marker-end:url(#marker2605)"
-       d="M 103.07543,97.956372 C 73.622505,86.913582 73.622505,86.913582 73.622505,86.913582"
+       style="fill:none;stroke:#000000;stroke-width:0.24075001;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1;marker-end:url(#marker2605)"
+       d="M 71.648601,114.47803 C 49.558912,106.19594 49.558912,106.19594 49.558912,106.19594"
        id="path2595"
        inkscape:connector-curvature="0" />
-    <path
-       style="fill:none;stroke:#000000;stroke-width:0.32100001;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1;marker-end:url(#marker1620)"
-       d="m 139.06391,49.857935 c -8.77687,27.838926 -8.77687,27.838926 -8.77687,27.838926"
-       id="path1616"
-       inkscape:connector-curvature="0" />
     <rect
-       style="fill:#ffe6d5;fill-opacity:1;stroke:#000000;stroke-width:0.16691115;stroke-miterlimit:4;stroke-dasharray:none"
+       style="fill:#ffe6d5;fill-opacity:1;stroke:#000000;stroke-width:0.12518337;stroke-miterlimit:4;stroke-dasharray:none"
        id="rect1769-3"
-       width="24.629539"
-       height="7.9985881"
-       x="48.992966"
-       y="82.619164"
-       ry="1.8061357" />
+       width="18.472155"
+       height="5.9989409"
+       x="31.086758"
+       y="102.57824"
+       ry="1.3546017" />
     <text
        xml:space="preserve"
-       style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:4.93888903px;line-height:1.25;font-family:sans-serif;-inkscape-font-specification:'sans-serif, Normal';font-variant-ligatures:normal;font-variant-caps:normal;font-variant-numeric:normal;font-feature-settings:normal;text-align:start;letter-spacing:0px;word-spacing:0px;writing-mode:lr-tb;text-anchor:start;fill:#000000;fill-opacity:1;stroke:none;stroke-width:0.26458332"
-       x="51.820534"
-       y="87.412201"
+       style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:3.70416689px;line-height:1.25;font-family:sans-serif;-inkscape-font-specification:'sans-serif, Normal';font-variant-ligatures:normal;font-variant-caps:normal;font-variant-numeric:normal;font-feature-settings:normal;text-align:start;letter-spacing:0px;word-spacing:0px;writing-mode:lr-tb;text-anchor:start;fill:#000000;fill-opacity:1;stroke:none;stroke-width:0.19843748"
+       x="33.207432"
+       y="106.17302"
        id="text1773-6"><tspan
          sodipodi:role="line"
          id="tspan1463"
-         x="51.820534"
-         y="87.412201">merger</tspan></text>
+         x="33.207432"
+         y="106.17302"
+         style="stroke-width:0.19843748">merger</tspan></text>
     <g
        id="g2295"
-       transform="translate(-4.2333335)">
+       transform="matrix(0.75,0,0,0.75,-8.8329671,40.613879)">
       <rect
          ry="1.8039205"
          y="25.020494"
@@ -1425,7 +1416,7 @@
            y="30.337786">forwarder</tspan></text>
     </g>
     <g
-       transform="translate(-3.9795536,47.840984)"
+       transform="matrix(0.75,0,0,0.75,-8.6426321,76.494617)"
        style="display:inline"
        id="g2295-3">
       <rect
@@ -1448,7 +1439,7 @@
            y="30.337786">forwarder</tspan></text>
     </g>
     <g
-       transform="translate(-4.2063436,20.399909)"
+       transform="matrix(0.75,0,0,0.75,-8.8127251,55.913811)"
        style="display:inline"
        id="g2295-5">
       <rect
@@ -1471,7 +1462,7 @@
            y="30.337786">forwarder</tspan></text>
     </g>
     <g
-       transform="translate(-3.6015836,68.702542)"
+       transform="matrix(0.75,0,0,0.75,-8.3591551,92.140786)"
        style="display:inline"
        id="g2295-0">
       <rect
@@ -1495,7 +1486,7 @@
     </g>
     <g
        id="g1263"
-       transform="translate(-4.2333335,-104.8506)">
+       transform="matrix(0.75,0,0,0.75,-8.8329671,-38.024071)">
       <g
          id="g2377-5-42"
          style="display:inline;fill:#eef4d7"
@@ -1536,7 +1527,7 @@
     <g
        style="display:inline"
        id="g1263-5"
-       transform="translate(-3.855357,-94.796429)">
+       transform="matrix(0.75,0,0,0.75,-8.5494851,-30.483443)">
       <g
          id="g2377-5-42-7"
          style="display:inline;fill:#eef4d7"
@@ -1577,7 +1568,7 @@
     <g
        style="display:inline"
        id="g1263-1"
-       transform="translate(-3.6995481,-55.96114)">
+       transform="matrix(0.75,0,0,0.75,-8.4326281,-1.356976)">
       <g
          id="g2377-5-42-1"
          style="display:inline;fill:#eef4d7"
@@ -1618,7 +1609,7 @@
     <g
        style="display:inline"
        id="g1263-52"
-       transform="translate(-3.6995481,-44.470663)">
+       transform="matrix(0.75,0,0,0.75,-8.4326281,7.2608817)">
       <g
          id="g2377-5-42-19"
          style="display:inline;fill:#eef4d7"
@@ -1657,94 +1648,131 @@
            sodipodi:role="line">ring</tspan></text>
     </g>
     <rect
-       style="display:inline;fill:#ffccaa;fill-opacity:1;stroke:#000000;stroke-width:0.34002537;stroke-miterlimit:4;stroke-dasharray:none"
+       style="display:inline;fill:#ffccaa;fill-opacity:1;stroke:#000000;stroke-width:0.25501901;stroke-miterlimit:4;stroke-dasharray:none"
        id="rect1769-5"
-       width="53.147232"
-       height="15.382997"
-       x="50.403591"
-       y="134.48639"
-       ry="3.4735854" />
+       width="39.860424"
+       height="11.537248"
+       x="32.144726"
+       y="141.47868"
+       ry="2.6051891" />
     <text
        xml:space="preserve"
-       style="font-style:normal;font-weight:normal;font-size:5.17880344px;line-height:125%;font-family:sans-serif;letter-spacing:0px;word-spacing:0px;fill:#000000;fill-opacity:1;stroke:none;stroke-width:0.1294701px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
-       x="60.681969"
-       y="135.07045"
+       style="font-style:normal;font-weight:normal;font-size:3.88410258px;line-height:125%;font-family:sans-serif;letter-spacing:0px;word-spacing:0px;fill:#000000;fill-opacity:1;stroke:none;stroke-width:0.09710257px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
+       x="39.476479"
+       y="139.37953"
        id="text237"
        transform="scale(0.93752888,1.0666338)"><tspan
          sodipodi:role="line"
          id="tspan235"
-         x="60.681969"
-         y="135.07045"
-         style="stroke-width:0.1294701px">traffic generator</tspan></text>
+         x="39.476479"
+         y="139.37953"
+         style="stroke-width:0.09710257px">traffic generator</tspan></text>
     <path
-       style="display:inline;fill:none;stroke:#000000;stroke-width:0.32100001;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1;marker-start:url(#marker22960-5-6)"
-       d="m 41.584293,147.74173 c 8.28536,0 8.28536,0 8.28536,0"
+       style="display:inline;fill:none;stroke:#000000;stroke-width:0.24075001;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1;marker-start:url(#marker22960-5-6)"
+       d="m 25.530253,151.42019 c 6.21402,0 6.21402,0 6.21402,0"
        id="path14783-8-7-9"
        inkscape:connector-curvature="0" />
     <path
-       style="display:inline;fill:none;stroke:#000000;stroke-width:0.32100001;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1;marker-end:url(#marker14793-1-4)"
-       d="m 41.496586,139.02471 c 8.28536,0 8.28536,0 8.28536,0"
+       style="display:inline;fill:none;stroke:#000000;stroke-width:0.24075001;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1;marker-end:url(#marker14793-1-4)"
+       d="m 25.464472,144.88242 c 6.21402,0 6.21402,0 6.21402,0"
        id="path14783-87-8"
        inkscape:connector-curvature="0" />
     <rect
-       style="display:inline;fill:#ffccaa;fill-opacity:1;stroke:#000000;stroke-width:0.15743089;stroke-miterlimit:4;stroke-dasharray:none"
+       style="display:inline;fill:#ffccaa;fill-opacity:1;stroke:#000000;stroke-width:0.11807317;stroke-miterlimit:4;stroke-dasharray:none"
        id="rect1769-5-6-3"
-       width="13.631977"
-       height="12.856415"
-       x="187.85887"
-       y="79.732826"
-       ry="2.9030659" />
+       width="10.223983"
+       height="9.6423111"
+       x="135.23622"
+       y="100.41351"
+       ry="2.1772995" />
     <text
        xml:space="preserve"
-       style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:4.93888903px;line-height:1.25;font-family:sans-serif;-inkscape-font-specification:'sans-serif, Normal';font-variant-ligatures:normal;font-variant-caps:normal;font-variant-numeric:normal;font-feature-settings:normal;text-align:start;letter-spacing:0px;word-spacing:0px;writing-mode:lr-tb;text-anchor:start;display:inline;fill:#000000;fill-opacity:1;stroke:none;stroke-width:0.28356495"
-       x="202.26404"
-       y="81.874725"
+       style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:3.70416665px;line-height:1.25;font-family:sans-serif;-inkscape-font-specification:'sans-serif, Normal';font-variant-ligatures:normal;font-variant-caps:normal;font-variant-numeric:normal;font-feature-settings:normal;text-align:start;letter-spacing:0px;word-spacing:0px;writing-mode:lr-tb;text-anchor:start;display:inline;fill:#000000;fill-opacity:1;stroke:none;stroke-width:0.21267371"
+       x="145.62817"
+       y="99.263878"
        id="text1773-6-6-5-2-7-8"
        transform="scale(0.93214045,1.0727997)"><tspan
-         y="81.874725"
-         x="202.26404"
+         y="99.263878"
+         x="145.62817"
          sodipodi:role="line"
          id="tspan1964-1-7-0"
-         style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:4.93888903px;font-family:sans-serif;-inkscape-font-specification:'sans-serif, Normal';font-variant-ligatures:normal;font-variant-caps:normal;font-variant-numeric:normal;font-feature-settings:normal;text-align:start;writing-mode:lr-tb;text-anchor:start;stroke-width:0.28356495">app2</tspan></text>
+         style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:3.70416665px;font-family:sans-serif;-inkscape-font-specification:'sans-serif, Normal';font-variant-ligatures:normal;font-variant-caps:normal;font-variant-numeric:normal;font-feature-settings:normal;text-align:start;writing-mode:lr-tb;text-anchor:start;stroke-width:0.21267371">app2</tspan></text>
     <path
-       style="display:inline;fill:none;stroke:#000000;stroke-width:0.32100001;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1;marker-start:url(#marker22960-9)"
-       d="m 179.63809,89.30645 c 8.28536,0 8.28536,0 8.28536,0"
+       style="display:inline;fill:none;stroke:#000000;stroke-width:0.24075001;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1;marker-start:url(#marker22960-9)"
+       d="m 129.07059,107.59371 c 6.21402,0 6.21402,0 6.21402,0"
        id="path14783-8-5"
        inkscape:connector-curvature="0" />
     <path
-       style="display:inline;fill:none;stroke:#000000;stroke-width:0.32100001;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1;marker-end:url(#marker14793-1-9)"
-       d="m 179.16729,84.081645 c 8.28536,0 8.28536,0 8.28536,0"
+       style="display:inline;fill:none;stroke:#000000;stroke-width:0.24075001;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1;marker-end:url(#marker14793-1-9)"
+       d="m 128.71749,103.67511 c 6.21402,0 6.21402,0 6.21402,0"
        id="path14783-87-5"
        inkscape:connector-curvature="0" />
     <rect
-       style="display:inline;fill:#ffccaa;fill-opacity:1;stroke:#000000;stroke-width:0.15743089;stroke-miterlimit:4;stroke-dasharray:none"
+       style="display:inline;fill:#ffccaa;fill-opacity:1;stroke:#000000;stroke-width:0.11807317;stroke-miterlimit:4;stroke-dasharray:none"
        id="rect1769-5-6-3-4"
-       width="13.631977"
-       height="12.856415"
-       x="188.56624"
-       y="30.353153"
-       ry="2.9030659" />
+       width="10.223983"
+       height="9.6423111"
+       x="135.76675"
+       y="63.378746"
+       ry="2.1772995" />
     <text
        xml:space="preserve"
-       style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:4.93888903px;line-height:1.25;font-family:sans-serif;-inkscape-font-specification:'sans-serif, Normal';font-variant-ligatures:normal;font-variant-caps:normal;font-variant-numeric:normal;font-feature-settings:normal;text-align:start;letter-spacing:0px;word-spacing:0px;writing-mode:lr-tb;text-anchor:start;display:inline;fill:#000000;fill-opacity:1;stroke:none;stroke-width:0.28356495"
-       x="203.0229"
-       y="35.845913"
+       style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:3.70416665px;line-height:1.25;font-family:sans-serif;-inkscape-font-specification:'sans-serif, Normal';font-variant-ligatures:normal;font-variant-caps:normal;font-variant-numeric:normal;font-feature-settings:normal;text-align:start;letter-spacing:0px;word-spacing:0px;writing-mode:lr-tb;text-anchor:start;display:inline;fill:#000000;fill-opacity:1;stroke:none;stroke-width:0.21267371"
+       x="146.19733"
+       y="64.742287"
        id="text1773-6-6-5-2-7-8-7"
        transform="scale(0.93214045,1.0727997)"><tspan
-         y="35.845913"
-         x="203.0229"
+         y="64.742287"
+         x="146.19733"
          sodipodi:role="line"
          id="tspan1964-1-7-0-4"
-         style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:4.93888903px;font-family:sans-serif;-inkscape-font-specification:'sans-serif, Normal';font-variant-ligatures:normal;font-variant-caps:normal;font-variant-numeric:normal;font-feature-settings:normal;text-align:start;writing-mode:lr-tb;text-anchor:start;stroke-width:0.28356495">app1</tspan></text>
+         style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:3.70416665px;font-family:sans-serif;-inkscape-font-specification:'sans-serif, Normal';font-variant-ligatures:normal;font-variant-caps:normal;font-variant-numeric:normal;font-feature-settings:normal;text-align:start;writing-mode:lr-tb;text-anchor:start;stroke-width:0.21267371">app1</tspan></text>
     <path
-       style="display:inline;fill:none;stroke:#000000;stroke-width:0.32100001;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1;marker-start:url(#marker22960-9-7)"
-       d="m 180.34547,39.926779 c 8.28536,0 8.28536,0 8.28536,0"
+       style="display:inline;fill:none;stroke:#000000;stroke-width:0.24075001;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1;marker-start:url(#marker22960-9-7)"
+       d="m 129.60112,70.558963 c 6.21402,0 6.21402,0 6.21402,0"
        id="path14783-8-5-3"
        inkscape:connector-curvature="0" />
     <path
-       style="display:inline;fill:none;stroke:#000000;stroke-width:0.32100001;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1;marker-end:url(#marker14793-1-9-6)"
-       d="m 179.87467,34.701979 c 8.28536,0 8.28536,0 8.28536,0"
+       style="display:inline;fill:none;stroke:#000000;stroke-width:0.24075001;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1;marker-end:url(#marker14793-1-9-6)"
+       d="m 129.24802,66.640363 c 6.21402,0 6.21402,0 6.21402,0"
        id="path14783-87-5-1"
        inkscape:connector-curvature="0" />
+    <path
+       style="display:inline;opacity:0.98999999;fill:none;stroke:#000000;stroke-width:0.24075001;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1;marker-end:url(#Arrow2Lend)"
+       d="M 102.20059,79.998337 C 88.91589,95.161133 88.91589,95.161133 88.91589,95.161133"
+       id="path5936"
+       inkscape:connector-curvature="0"
+       inkscape:transform-center-x="1.7108"
+       inkscape:transform-center-y="-0.86607933" />
+    <g
+       id="g1969"
+       transform="matrix(0.74487285,0,0,2.6794736,5.8732829,-268.99875)"
+       style="fill:#eef4d7">
+      <rect
+         ry="1.8106976"
+         y="122.52335"
+         x="124.54029"
+         height="8.0187912"
+         width="18.980101"
+         id="rect1769-3-2-7"
+         style="fill:#eef4d7;stroke:#000000;stroke-width:0.14670815;stroke-miterlimit:4;stroke-dasharray:none" />
+    </g>
+    <text
+       xml:space="preserve"
+       style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:3.70416689px;line-height:1.25;font-family:sans-serif;-inkscape-font-specification:'sans-serif, Normal';font-variant-ligatures:normal;font-variant-caps:normal;font-variant-numeric:normal;font-feature-settings:normal;text-align:start;letter-spacing:0px;word-spacing:0px;writing-mode:lr-tb;text-anchor:start;fill:#000000;fill-opacity:1;stroke:none;stroke-width:0.21267372"
+       x="108.31697"
+       y="65.916351"
+       id="text1773-6-6-5-2"
+       transform="scale(0.93214046,1.0727997)"><tspan
+         y="65.916351"
+         x="108.31697"
+         sodipodi:role="line"
+         id="tspan1964-1"
+         style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:3.70416689px;font-family:sans-serif;-inkscape-font-specification:'sans-serif, Normal';font-variant-ligatures:normal;font-variant-caps:normal;font-variant-numeric:normal;font-feature-settings:normal;text-align:start;writing-mode:lr-tb;text-anchor:start;stroke-width:0.21267372">vhost</tspan></text>
+    <path
+       style="fill:none;stroke:#000000;stroke-width:0.24075001;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1;marker-end:url(#marker6489)"
+       d="m 89.14955,80.670765 c 12.09068,14.320689 12.09068,14.320689 12.09068,14.320689"
+       id="path6479"
+       inkscape:connector-curvature="0" />
   </g>
 </svg>
-- 
1.9.1

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

* [spp] [PATCH 10/30] doc: fix figure in overview
  2018-01-15 11:04 ` [spp] Proposal - spp_vf(SR-IOV like feature) addition to SPP Ferruh Yigit
                     ` (8 preceding siblings ...)
  2018-01-16  5:16   ` [spp] [PATCH 09/30] doc: fix " x-fn-spp
@ 2018-01-16  5:16   ` x-fn-spp
  2018-01-16  5:16   ` [spp] [PATCH 11/30] doc: add sample usage x-fn-spp
                     ` (19 subsequent siblings)
  29 siblings, 0 replies; 97+ messages in thread
From: x-fn-spp @ 2018-01-16  5:16 UTC (permalink / raw)
  To: spp

From: Hiroyuki Nakamura <nakamura.hioryuki@po.ntt-tx.co.jp>

Fix the figure in overview section, which is depicted in spp_vf_overview.svg.

Signed-off-by: Tomoyuki Mizuguchi <mizuguchi.tomoyuki@po.ntt-tx.co.jp>
Signed-off-by: Naoki Takada <takada.naoki@lab.ntt.co.jp>
---
 docs/spp_vf/spp_vf_overview.svg | 391 ++++++++++++++++++++++++++--------------
 1 file changed, 259 insertions(+), 132 deletions(-)

diff --git a/docs/spp_vf/spp_vf_overview.svg b/docs/spp_vf/spp_vf_overview.svg
index adfe93e..5ec1709 100644
--- a/docs/spp_vf/spp_vf_overview.svg
+++ b/docs/spp_vf/spp_vf_overview.svg
@@ -15,10 +15,154 @@
    version="1.1"
    id="svg4746"
    inkscape:version="0.92.2 (5c3e80d, 2017-08-06)"
-   sodipodi:docname="spp_vf_overview_r1.svg">
+   sodipodi:docname="spp_vf_overview_1024.svg">
   <defs
      id="defs4740">
     <marker
+       inkscape:isstock="true"
+       style="overflow:visible;"
+       id="marker6296"
+       refX="0.0"
+       refY="0.0"
+       orient="auto"
+       inkscape:stockid="Arrow2Lend">
+      <path
+         transform="scale(1.1) rotate(180) translate(1,0)"
+         d="M 8.7185878,4.0337352 L -2.2072895,0.016013256 L 8.7185884,-4.0017078 C 6.9730900,-1.6296469 6.9831476,1.6157441 8.7185878,4.0337352 z "
+         style="fill-rule:evenodd;stroke-width:0.625;stroke-linejoin:round;stroke:#000000;stroke-opacity:1;fill:#000000;fill-opacity:1"
+         id="path6294" />
+    </marker>
+    <marker
+       inkscape:stockid="Arrow2Lend"
+       orient="auto"
+       refY="0.0"
+       refX="0.0"
+       id="marker1654"
+       style="overflow:visible;"
+       inkscape:isstock="true">
+      <path
+         id="path1652"
+         style="fill-rule:evenodd;stroke-width:0.625;stroke-linejoin:round;stroke:#000000;stroke-opacity:1;fill:#000000;fill-opacity:1"
+         d="M 8.7185878,4.0337352 L -2.2072895,0.016013256 L 8.7185884,-4.0017078 C 6.9730900,-1.6296469 6.9831476,1.6157441 8.7185878,4.0337352 z "
+         transform="scale(1.1) rotate(180) translate(1,0)" />
+    </marker>
+    <marker
+       inkscape:stockid="SquareL"
+       orient="auto"
+       refY="0.0"
+       refX="0.0"
+       id="SquareL"
+       style="overflow:visible"
+       inkscape:isstock="true">
+      <path
+         id="path1432"
+         d="M -5.0,-5.0 L -5.0,5.0 L 5.0,5.0 L 5.0,-5.0 L -5.0,-5.0 z "
+         style="fill-rule:evenodd;stroke:#000000;stroke-width:1pt;stroke-opacity:1;fill:#000000;fill-opacity:1"
+         transform="scale(0.8)" />
+    </marker>
+    <marker
+       inkscape:stockid="Arrow2Lend"
+       orient="auto"
+       refY="0.0"
+       refX="0.0"
+       id="Arrow2Lend"
+       style="overflow:visible;"
+       inkscape:isstock="true"
+       inkscape:collect="always">
+      <path
+         id="path1383"
+         style="fill-rule:evenodd;stroke-width:0.625;stroke-linejoin:round;stroke:#000000;stroke-opacity:1;fill:#000000;fill-opacity:1"
+         d="M 8.7185878,4.0337352 L -2.2072895,0.016013256 L 8.7185884,-4.0017078 C 6.9730900,-1.6296469 6.9831476,1.6157441 8.7185878,4.0337352 z "
+         transform="scale(1.1) rotate(180) translate(1,0)" />
+    </marker>
+    <marker
+       inkscape:stockid="Arrow2Lstart"
+       orient="auto"
+       refY="0.0"
+       refX="0.0"
+       id="marker9343"
+       style="overflow:visible"
+       inkscape:isstock="true">
+      <path
+         id="path9341"
+         style="fill-rule:evenodd;stroke-width:0.625;stroke-linejoin:round;stroke:#000000;stroke-opacity:1;fill:#000000;fill-opacity:1"
+         d="M 8.7185878,4.0337352 L -2.2072895,0.016013256 L 8.7185884,-4.0017078 C 6.9730900,-1.6296469 6.9831476,1.6157441 8.7185878,4.0337352 z "
+         transform="scale(1.1) translate(1,0)" />
+    </marker>
+    <marker
+       inkscape:stockid="Arrow2Lstart"
+       orient="auto"
+       refY="0.0"
+       refX="0.0"
+       id="Arrow2Lstart"
+       style="overflow:visible"
+       inkscape:isstock="true">
+      <path
+         id="path1359"
+         style="fill-rule:evenodd;stroke-width:0.625;stroke-linejoin:round;stroke:#000000;stroke-opacity:1;fill:#000000;fill-opacity:1"
+         d="M 8.7185878,4.0337352 L -2.2072895,0.016013256 L 8.7185884,-4.0017078 C 6.9730900,-1.6296469 6.9831476,1.6157441 8.7185878,4.0337352 z "
+         transform="scale(1.1) translate(1,0)" />
+    </marker>
+    <marker
+       inkscape:isstock="true"
+       style="overflow:visible"
+       id="marker4626"
+       refX="0"
+       refY="0"
+       orient="auto"
+       inkscape:stockid="Arrow2Lend">
+      <path
+         inkscape:connector-curvature="0"
+         transform="matrix(-1.1,0,0,-1.1,-1.1,0)"
+         d="M 8.7185878,4.0337352 -2.2072895,0.01601326 8.7185884,-4.0017078 c -1.7454984,2.3720609 -1.7354408,5.6174519 -6e-7,8.035443 z"
+         style="fill:#000000;fill-opacity:1;fill-rule:evenodd;stroke:#000000;stroke-width:0.625;stroke-linejoin:round;stroke-opacity:1"
+         id="path4624" />
+    </marker>
+    <marker
+       inkscape:isstock="true"
+       style="overflow:visible"
+       id="marker3618"
+       refX="0"
+       refY="0"
+       orient="auto"
+       inkscape:stockid="Arrow2Lend">
+      <path
+         inkscape:connector-curvature="0"
+         transform="matrix(-1.1,0,0,-1.1,-1.1,0)"
+         d="M 8.7185878,4.0337352 -2.2072895,0.01601326 8.7185884,-4.0017078 c -1.7454984,2.3720609 -1.7354408,5.6174519 -6e-7,8.035443 z"
+         style="fill:#000000;fill-opacity:1;fill-rule:evenodd;stroke:#000000;stroke-width:0.625;stroke-linejoin:round;stroke-opacity:1"
+         id="path3616" />
+    </marker>
+    <marker
+       inkscape:isstock="true"
+       style="overflow:visible"
+       id="marker1780"
+       refX="0"
+       refY="0"
+       orient="auto"
+       inkscape:stockid="Arrow2Lend">
+      <path
+         inkscape:connector-curvature="0"
+         transform="matrix(-1.1,0,0,-1.1,-1.1,0)"
+         d="M 8.7185878,4.0337352 -2.2072895,0.01601326 8.7185884,-4.0017078 c -1.7454984,2.3720609 -1.7354408,5.6174519 -6e-7,8.035443 z"
+         style="fill:#000000;fill-opacity:1;fill-rule:evenodd;stroke:#000000;stroke-width:0.625;stroke-linejoin:round;stroke-opacity:1"
+         id="path1778" />
+    </marker>
+    <marker
+       inkscape:stockid="Arrow2Lend"
+       orient="auto"
+       refY="0.0"
+       refX="0.0"
+       id="marker1604"
+       style="overflow:visible;"
+       inkscape:isstock="true">
+      <path
+         id="path1362"
+         style="fill-rule:evenodd;stroke-width:0.625;stroke-linejoin:round;stroke:#000000;stroke-opacity:1;fill:#000000;fill-opacity:1"
+         d="M 8.7185878,4.0337352 L -2.2072895,0.016013256 L 8.7185884,-4.0017078 C 6.9730900,-1.6296469 6.9831476,1.6157441 8.7185878,4.0337352 z "
+         transform="scale(1.1) rotate(180) translate(1,0)" />
+    </marker>
+    <marker
        inkscape:stockid="Arrow2Lend"
        orient="auto"
        refY="0"
@@ -320,21 +464,6 @@
          inkscape:connector-curvature="0" />
     </marker>
     <marker
-       inkscape:stockid="Arrow2Lend"
-       orient="auto"
-       refY="0"
-       refX="0"
-       id="Arrow2Lend"
-       style="overflow:visible"
-       inkscape:isstock="true">
-      <path
-         id="path1305"
-         style="fill:#000000;fill-opacity:1;fill-rule:evenodd;stroke:#000000;stroke-width:0.625;stroke-linejoin:round;stroke-opacity:1"
-         d="M 8.7185878,4.0337352 -2.2072895,0.01601326 8.7185884,-4.0017078 c -1.7454984,2.3720609 -1.7354408,5.6174519 -6e-7,8.035443 z"
-         transform="matrix(-1.1,0,0,-1.1,-1.1,0)"
-         inkscape:connector-curvature="0" />
-    </marker>
-    <marker
        inkscape:isstock="true"
        style="overflow:visible"
        id="marker4611"
@@ -990,15 +1119,15 @@
      inkscape:pageopacity="0.0"
      inkscape:pageshadow="2"
      inkscape:zoom="0.9899495"
-     inkscape:cx="457.38747"
+     inkscape:cx="358.41403"
      inkscape:cy="223.84187"
      inkscape:document-units="mm"
-     inkscape:current-layer="layer1"
+     inkscape:current-layer="layer2"
      showgrid="false"
-     inkscape:window-width="1084"
-     inkscape:window-height="664"
-     inkscape:window-x="148"
-     inkscape:window-y="1047"
+     inkscape:window-width="963"
+     inkscape:window-height="676"
+     inkscape:window-x="291"
+     inkscape:window-y="260"
      inkscape:window-maximized="1"
      fit-margin-top="0"
      fit-margin-left="0"
@@ -1014,7 +1143,7 @@
         <dc:format>image/svg+xml</dc:format>
         <dc:type
            rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
-        <dc:title></dc:title>
+        <dc:title />
       </cc:Work>
     </rdf:RDF>
   </metadata>
@@ -1259,6 +1388,21 @@
      inkscape:label="spp_vf_threads"
      style="display:inline;opacity:0.98999999"
      transform="translate(22.342263,-42.641668)">
+    <path
+       style="fill:none;stroke:#000000;stroke-width:0.241;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;marker-end:url(#marker6296);stroke-miterlimit:4;stroke-dasharray:none"
+       d="M 100.80696,76.449807 C 92.088084,96.087573 92.088084,96.087573 92.088084,96.087573"
+       id="path6286"
+       inkscape:connector-curvature="0" />
+    <path
+       style="fill:none;stroke:#000000;stroke-width:0.241;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1;marker-end:url(#Arrow2Lend)"
+       d="m 89.320737,76.353127 c 9.452951,19.668818 9.452951,19.668818 9.452951,19.668818"
+       id="path6138"
+       inkscape:connector-curvature="0" />
+    <path
+       style="fill:none;stroke:#000000;stroke-width:0.241;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1;marker-end:url(#marker1780)"
+       d="m 25.766181,78.300049 5.164281,-5.567772"
+       id="path4812"
+       inkscape:connector-curvature="0" />
     <text
        xml:space="preserve"
        style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:3.70416689px;line-height:1.25;font-family:sans-serif;-inkscape-font-specification:'sans-serif, Normal';font-variant-ligatures:normal;font-variant-caps:normal;font-variant-numeric:normal;font-feature-settings:normal;text-align:start;letter-spacing:0px;word-spacing:0px;writing-mode:lr-tb;text-anchor:start;fill:#d7f4e3;fill-opacity:1;stroke:none;stroke-width:0.19843748"
@@ -1276,18 +1420,18 @@
        width="21.297846"
        height="5.9898095"
        x="30.552704"
-       y="65.475006"
+       y="67.062508"
        ry="1.3525398" />
     <text
        xml:space="preserve"
        style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:3.70416689px;line-height:1.25;font-family:sans-serif;-inkscape-font-specification:'sans-serif, Normal';font-variant-ligatures:normal;font-variant-caps:normal;font-variant-numeric:normal;font-feature-settings:normal;text-align:start;letter-spacing:0px;word-spacing:0px;writing-mode:lr-tb;text-anchor:start;fill:#000000;fill-opacity:1;stroke:none;stroke-width:0.19843748"
        x="33.065685"
-       y="69.462097"
+       y="71.049599"
        id="text1773"><tspan
          sodipodi:role="line"
          id="tspan1461"
          x="33.065685"
-         y="69.462097"
+         y="71.049599"
          style="stroke-width:0.19843748">classifier</tspan></text>
     <g
        id="g1969-0"
@@ -1315,11 +1459,6 @@
          id="tspan1964-1-7"
          style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:3.70416689px;font-family:sans-serif;-inkscape-font-specification:'sans-serif, Normal';font-variant-ligatures:normal;font-variant-caps:normal;font-variant-numeric:normal;font-feature-settings:normal;text-align:start;writing-mode:lr-tb;text-anchor:start;stroke-width:0.21267372">vhost</tspan></text>
     <path
-       style="fill:none;stroke:#000000;stroke-width:0.24075001;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1;marker-end:url(#marker13092)"
-       d="m 24.862305,78.74278 6.068157,-7.598004"
-       id="path4812"
-       inkscape:connector-curvature="0" />
-    <path
        style="fill:none;stroke:#000000;stroke-width:0.24075001;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1;marker-end:url(#marker14793)"
        d="m 112.38085,66.046195 c 6.21402,0 6.21402,0 6.21402,0"
        id="path14783"
@@ -1355,16 +1494,6 @@
        id="path14783-8-2"
        inkscape:connector-curvature="0" />
     <path
-       style="display:inline;fill:none;stroke:#000000;stroke-width:0.24075001;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1;marker-end:url(#marker1516)"
-       d="M 51.850549,68.289812 71.166691,62.203934"
-       id="path1506"
-       inkscape:connector-curvature="0" />
-    <path
-       style="display:inline;fill:none;stroke:#000000;stroke-width:0.24075001;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1;marker-end:url(#marker1864)"
-       d="m 51.850549,68.25313 c 19.344482,9.601053 19.344482,9.601053 19.344482,9.601053"
-       id="path1854"
-       inkscape:connector-curvature="0" />
-    <path
        style="display:inline;fill:none;stroke:#000000;stroke-width:0.24075001;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1;marker-end:url(#marker2218)"
        d="m 71.365131,98.43499 c -21.806219,6.92139 -21.806219,6.92139 -21.806219,6.92139"
        id="path2208"
@@ -1485,87 +1614,6 @@
            y="30.337786">forwarder</tspan></text>
     </g>
     <g
-       id="g1263"
-       transform="matrix(0.75,0,0,0.75,-8.8329671,-38.024071)">
-      <g
-         id="g2377-5-42"
-         style="display:inline;fill:#eef4d7"
-         transform="translate(-6.7279778,-3.9309553)">
-        <ellipse
-           style="display:inline;fill:#eef4d7;fill-opacity:1;stroke:#000000;stroke-width:0.35376999;stroke-miterlimit:4;stroke-dasharray:none"
-           id="path1780-3-7-12-8"
-           cx="100.0881"
-           cy="141.425"
-           rx="6.5516987"
-           ry="3.1499126"
-           inkscape:transform-center-x="13.229167"
-           inkscape:transform-center-y="-59.720238" />
-        <text
-           xml:space="preserve"
-           style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:4.93888903px;line-height:1.25;font-family:sans-serif;-inkscape-font-specification:'sans-serif, Normal';font-variant-ligatures:normal;font-variant-caps:normal;font-variant-numeric:normal;font-feature-settings:normal;text-align:start;letter-spacing:0px;word-spacing:0px;writing-mode:lr-tb;text-anchor:start;display:inline;fill:#eef4d7;fill-opacity:1;stroke:none;stroke-width:0.28356495"
-           x="102.67519"
-           y="132.96213"
-           id="text1773-6-6-5-2-7-4-3-60"
-           transform="scale(0.93214046,1.0727997)"><tspan
-             sodipodi:role="line"
-             id="tspan2372-8-0"
-             x="102.67519"
-             y="132.96213">ring</tspan></text>
-      </g>
-      <text
-         transform="scale(0.93214046,1.0727997)"
-         id="text1773-6-6-5-2-7-4-4-2"
-         y="129.157"
-         x="95.700722"
-         style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:4.93888903px;line-height:1.25;font-family:sans-serif;-inkscape-font-specification:'sans-serif, Normal';font-variant-ligatures:normal;font-variant-caps:normal;font-variant-numeric:normal;font-feature-settings:normal;text-align:start;letter-spacing:0px;word-spacing:0px;writing-mode:lr-tb;text-anchor:start;display:inline;fill:#000000;fill-opacity:1;stroke:none;stroke-width:0.28356495"
-         xml:space="preserve"><tspan
-           y="129.157"
-           x="95.700722"
-           id="tspan2372-2-3"
-           sodipodi:role="line">ring</tspan></text>
-    </g>
-    <g
-       style="display:inline"
-       id="g1263-5"
-       transform="matrix(0.75,0,0,0.75,-8.5494851,-30.483443)">
-      <g
-         id="g2377-5-42-7"
-         style="display:inline;fill:#eef4d7"
-         transform="translate(-6.7279778,-3.9309553)">
-        <ellipse
-           style="display:inline;fill:#eef4d7;fill-opacity:1;stroke:#000000;stroke-width:0.35376999;stroke-miterlimit:4;stroke-dasharray:none"
-           id="path1780-3-7-12-8-4"
-           cx="100.0881"
-           cy="141.425"
-           rx="6.5516987"
-           ry="3.1499126"
-           inkscape:transform-center-x="13.229167"
-           inkscape:transform-center-y="-59.720238" />
-        <text
-           xml:space="preserve"
-           style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:4.93888903px;line-height:1.25;font-family:sans-serif;-inkscape-font-specification:'sans-serif, Normal';font-variant-ligatures:normal;font-variant-caps:normal;font-variant-numeric:normal;font-feature-settings:normal;text-align:start;letter-spacing:0px;word-spacing:0px;writing-mode:lr-tb;text-anchor:start;display:inline;fill:#eef4d7;fill-opacity:1;stroke:none;stroke-width:0.28356495"
-           x="102.67519"
-           y="132.96213"
-           id="text1773-6-6-5-2-7-4-3-60-1"
-           transform="scale(0.93214046,1.0727997)"><tspan
-             sodipodi:role="line"
-             id="tspan2372-8-0-0"
-             x="102.67519"
-             y="132.96213">ring</tspan></text>
-      </g>
-      <text
-         transform="scale(0.93214046,1.0727997)"
-         id="text1773-6-6-5-2-7-4-4-2-6"
-         y="129.157"
-         x="95.700722"
-         style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:4.93888903px;line-height:1.25;font-family:sans-serif;-inkscape-font-specification:'sans-serif, Normal';font-variant-ligatures:normal;font-variant-caps:normal;font-variant-numeric:normal;font-feature-settings:normal;text-align:start;letter-spacing:0px;word-spacing:0px;writing-mode:lr-tb;text-anchor:start;display:inline;fill:#000000;fill-opacity:1;stroke:none;stroke-width:0.28356495"
-         xml:space="preserve"><tspan
-           y="129.157"
-           x="95.700722"
-           id="tspan2372-2-3-9"
-           sodipodi:role="line">ring</tspan></text>
-    </g>
-    <g
        style="display:inline"
        id="g1263-1"
        transform="matrix(0.75,0,0,0.75,-8.4326281,-1.356976)">
@@ -1737,13 +1785,6 @@
        d="m 129.24802,66.640363 c 6.21402,0 6.21402,0 6.21402,0"
        id="path14783-87-5-1"
        inkscape:connector-curvature="0" />
-    <path
-       style="display:inline;opacity:0.98999999;fill:none;stroke:#000000;stroke-width:0.24075001;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1;marker-end:url(#Arrow2Lend)"
-       d="M 102.20059,79.998337 C 88.91589,95.161133 88.91589,95.161133 88.91589,95.161133"
-       id="path5936"
-       inkscape:connector-curvature="0"
-       inkscape:transform-center-x="1.7108"
-       inkscape:transform-center-y="-0.86607933" />
     <g
        id="g1969"
        transform="matrix(0.74487285,0,0,2.6794736,5.8732829,-268.99875)"
@@ -1770,9 +1811,95 @@
          id="tspan1964-1"
          style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:3.70416689px;font-family:sans-serif;-inkscape-font-specification:'sans-serif, Normal';font-variant-ligatures:normal;font-variant-caps:normal;font-variant-numeric:normal;font-feature-settings:normal;text-align:start;writing-mode:lr-tb;text-anchor:start;stroke-width:0.21267372">vhost</tspan></text>
     <path
-       style="fill:none;stroke:#000000;stroke-width:0.24075001;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1;marker-end:url(#marker6489)"
-       d="m 89.14955,80.670765 c 12.09068,14.320689 12.09068,14.320689 12.09068,14.320689"
-       id="path6479"
+       style="fill:none;stroke:#000000;stroke-width:0.241;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1;marker-end:url(#marker3618)"
+       d="M 51.850549,69.877318 C 71.174813,62.195833 71.174813,62.195833 71.174813,62.195833"
+       id="path3608"
        inkscape:connector-curvature="0" />
+    <path
+       style="fill:none;stroke:#000000;stroke-width:0.241;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1;marker-end:url(#marker4626)"
+       d="m 51.850549,69.708341 c 19.344505,7.616675 19.344505,7.616675 19.344505,7.616675"
+       id="path4616"
+       inkscape:connector-curvature="0" />
+    <g
+       id="g1263"
+       transform="matrix(0.75,0,0,0.75,-8.8329671,-36.965737)">
+      <g
+         id="g2377-5-42"
+         style="display:inline;fill:#eef4d7"
+         transform="translate(-6.7279778,-3.9309553)">
+        <ellipse
+           style="display:inline;fill:#eef4d7;fill-opacity:1;stroke:#000000;stroke-width:0.35376999;stroke-miterlimit:4;stroke-dasharray:none"
+           id="path1780-3-7-12-8"
+           cx="100.0881"
+           cy="141.425"
+           rx="6.5516987"
+           ry="3.1499126"
+           inkscape:transform-center-x="13.229167"
+           inkscape:transform-center-y="-59.720238" />
+        <text
+           xml:space="preserve"
+           style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:4.93888903px;line-height:1.25;font-family:sans-serif;-inkscape-font-specification:'sans-serif, Normal';font-variant-ligatures:normal;font-variant-caps:normal;font-variant-numeric:normal;font-feature-settings:normal;text-align:start;letter-spacing:0px;word-spacing:0px;writing-mode:lr-tb;text-anchor:start;display:inline;fill:#eef4d7;fill-opacity:1;stroke:none;stroke-width:0.28356495"
+           x="102.67519"
+           y="132.96213"
+           id="text1773-6-6-5-2-7-4-3-60"
+           transform="scale(0.93214046,1.0727997)"><tspan
+             sodipodi:role="line"
+             id="tspan2372-8-0"
+             x="102.67519"
+             y="132.96213">ring</tspan></text>
+      </g>
+      <text
+         transform="scale(0.93214046,1.0727997)"
+         id="text1773-6-6-5-2-7-4-4-2"
+         y="129.157"
+         x="95.700722"
+         style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:4.93888903px;line-height:1.25;font-family:sans-serif;-inkscape-font-specification:'sans-serif, Normal';font-variant-ligatures:normal;font-variant-caps:normal;font-variant-numeric:normal;font-feature-settings:normal;text-align:start;letter-spacing:0px;word-spacing:0px;writing-mode:lr-tb;text-anchor:start;display:inline;fill:#000000;fill-opacity:1;stroke:none;stroke-width:0.28356495"
+         xml:space="preserve"><tspan
+           y="129.157"
+           x="95.700722"
+           id="tspan2372-2-3"
+           sodipodi:role="line">ring</tspan></text>
+    </g>
+    <g
+       style="display:inline"
+       id="g1263-5"
+       transform="matrix(0.75,0,0,0.75,-8.5494851,-29.425109)">
+      <g
+         id="g2377-5-42-7"
+         style="display:inline;fill:#eef4d7"
+         transform="translate(-6.7279778,-3.9309553)">
+        <ellipse
+           style="display:inline;fill:#eef4d7;fill-opacity:1;stroke:#000000;stroke-width:0.35376999;stroke-miterlimit:4;stroke-dasharray:none"
+           id="path1780-3-7-12-8-4"
+           cx="100.0881"
+           cy="141.425"
+           rx="6.5516987"
+           ry="3.1499126"
+           inkscape:transform-center-x="13.229167"
+           inkscape:transform-center-y="-59.720238" />
+        <text
+           xml:space="preserve"
+           style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:4.93888903px;line-height:1.25;font-family:sans-serif;-inkscape-font-specification:'sans-serif, Normal';font-variant-ligatures:normal;font-variant-caps:normal;font-variant-numeric:normal;font-feature-settings:normal;text-align:start;letter-spacing:0px;word-spacing:0px;writing-mode:lr-tb;text-anchor:start;display:inline;fill:#eef4d7;fill-opacity:1;stroke:none;stroke-width:0.28356495"
+           x="102.67519"
+           y="132.96213"
+           id="text1773-6-6-5-2-7-4-3-60-1"
+           transform="scale(0.93214046,1.0727997)"><tspan
+             sodipodi:role="line"
+             id="tspan2372-8-0-0"
+             x="102.67519"
+             y="132.96213">ring</tspan></text>
+      </g>
+      <text
+         transform="scale(0.93214046,1.0727997)"
+         id="text1773-6-6-5-2-7-4-4-2-6"
+         y="129.157"
+         x="95.700722"
+         style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:4.93888903px;line-height:1.25;font-family:sans-serif;-inkscape-font-specification:'sans-serif, Normal';font-variant-ligatures:normal;font-variant-caps:normal;font-variant-numeric:normal;font-feature-settings:normal;text-align:start;letter-spacing:0px;word-spacing:0px;writing-mode:lr-tb;text-anchor:start;display:inline;fill:#000000;fill-opacity:1;stroke:none;stroke-width:0.28356495"
+         xml:space="preserve"><tspan
+           y="129.157"
+           x="95.700722"
+           id="tspan2372-2-3-9"
+           sodipodi:role="line">ring</tspan></text>
+    </g>
   </g>
 </svg>
-- 
1.9.1

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

* [spp] [PATCH 11/30] doc: add sample usage
  2018-01-15 11:04 ` [spp] Proposal - spp_vf(SR-IOV like feature) addition to SPP Ferruh Yigit
                     ` (9 preceding siblings ...)
  2018-01-16  5:16   ` [spp] [PATCH 10/30] doc: fix figure in overview x-fn-spp
@ 2018-01-16  5:16   ` x-fn-spp
  2018-01-16  5:16   ` [spp] [PATCH 12/30] doc: revice path descs x-fn-spp
                     ` (18 subsequent siblings)
  29 siblings, 0 replies; 97+ messages in thread
From: x-fn-spp @ 2018-01-16  5:16 UTC (permalink / raw)
  To: spp

From: Hiroyuki Nakamura <nakamura.hioryuki@po.ntt-tx.co.jp>

Signed-off-by: Naoki Takada <takada.naoki@lab.ntt.co.jp>
---
 docs/spp_vf/how_to_use.md   |   2 +-
 docs/spp_vf/sample_usage.md | 212 ++++++++++++++++++++++++++++++++
 docs/spp_vf/setup.md        | 291 --------------------------------------------
 docs/spp_vf/setup_guide.md  | 291 ++++++++++++++++++++++++++++++++++++++++++++
 docs/spp_vf/spp_vf.md       |   6 +-
 5 files changed, 509 insertions(+), 293 deletions(-)
 create mode 100644 docs/spp_vf/sample_usage.md
 delete mode 100644 docs/spp_vf/setup.md
 create mode 100644 docs/spp_vf/setup_guide.md

diff --git a/docs/spp_vf/how_to_use.md b/docs/spp_vf/how_to_use.md
index ca9cf15..6b5019c 100644
--- a/docs/spp_vf/how_to_use.md
+++ b/docs/spp_vf/how_to_use.md
@@ -14,7 +14,7 @@ SPP_VF is a SR-IOV like network functionality for NFV.
 
 ## Launch SPP
 
-Before launching spp, you need to setup described as [setup guide](setup.md).
+Before launching spp, you need to setup described as [setup guide](setup_guide.md).
 
 ### SPP Controller
 
diff --git a/docs/spp_vf/sample_usage.md b/docs/spp_vf/sample_usage.md
new file mode 100644
index 0000000..2157378
--- /dev/null
+++ b/docs/spp_vf/sample_usage.md
@@ -0,0 +1,212 @@
+# SPP_VF Sample Usage
+
+This sample demonstrates an use-case of MAC address classification of
+spp_vf.
+It enables to access to VMs with ssh from a remote node.
+
+Before trying this sample, install SPP by following
+[setup guide](setup_guide.md).
+
+## Testing Steps
+
+In this section, you configure spp_vf and client applications for
+this use-case.
+
+
+### Setup SPP
+
+First, launch spp controller and primary process.
+
+  ```sh
+  $ pwd
+  /path/to/Soft-Patch-Panel
+
+  # SPP controller
+  $ python ./src/spp.py -p 5555 -s 6666
+
+  # SPP primary
+  $ sudo ./src/primary/x86_64-native-linuxapp-gcc/spp_primary \
+  -c 0x02 -n 4 --socket-mem 512,512 --huge-dir=/run/hugepages/kvm \
+  --proc-type=primary \
+  -- \
+  -p 0x03 -n 8 -s 127.0.0.1:5555
+  ```
+
+TODO(yasufum) add description for sec.
+
+  ```sh
+  # start nc for secondary 1
+  $ while true; do nc -l 11111; done
+
+  # start secondary 1
+  $ sudo ./src/vf/x86_64-native-linuxapp-gcc/spp_vf \
+  -c 0x00fd -n 4 --proc-type=secondary \
+  -- \
+  --process-id 1 \
+  --config $SPRINT_REVIEW_HOME/spp_vf1_without_cmtab.json \
+  -s 127.0.0.1:11111
+
+  # start nc for secondary 2
+  $ while true; do nc -l 11112; done
+
+  # start secondary 2
+  $ sudo ./src/vf/x86_64-native-linuxapp-gcc/spp_vf \
+  -c 0x3f01 -n 4 --proc-type=secondary \
+  -- \
+  --process-id 2 \
+  --config $SPRINT_REVIEW_HOME/spp_vf2_without_cmtab.json \
+  -s 127.0.0.1:11112
+  ```
+
+### Setup network configuration for VMs.
+
+Start two VMs.
+
+  ```sh
+  $ virsh start spp-vm1
+  $ virsh start spp-vm2
+  ```
+
+Login to spp-vm1 for network configuration.
+To not ask for unknown keys while login VMs,
+set `-oStrictHostKeyChecking=no` option for ssh.
+
+  ```sh
+  $ ssh -oStrictHostKeyChecking=no ntt@192.168.122.31
+  ```
+
+Up interfaces for vhost and register them to arp table inside spp-vm1.
+In addition, you have to disable TCP offload function, or ssh is faled
+after configuration is done.
+
+  ```sh
+  # up interfaces
+  $ sudo ifconfig ens4 inet 192.168.240.21 netmask 255.255.255.0 up
+  $ sudo ifconfig ens5 inet 192.168.250.22 netmask 255.255.255.0 up
+
+  # register to arp table
+  $ sudo arp -s 192.168.240.11 a0:36:9f:78:86:78 -i ens4
+  $ sudo arp -s 192.168.250.13 a0:36:9f:6c:ed:bc -i ens5
+
+  # diable TCP offload
+  $ sudo ethtool -K ens4 tx off
+  $ sudo ethtool -K ens5 tx off
+  ```
+
+Configurations for spp-vm2 is same as spp-vm1.
+
+  ```sh
+  $ ssh -oStrictHostKeyChecking=no ntt@192.168.122.32
+
+  # up interfaces
+  $ sudo ifconfig ens4 inet 192.168.240.31 netmask 255.255.255.0 up
+  $ sudo ifconfig ens5 inet 192.168.250.32 netmask 255.255.255.0 up
+
+  # register to arp table
+  $ sudo arp -s 192.168.240.11 a0:36:9f:78:86:78 -i ens4
+  $ sudo arp -s 192.168.250.13 a0:36:9f:6c:ed:bc -i ens5
+
+  # diable TCP offload
+  $ sudo ethtool -K ens4 tx off
+  $ sudo ethtool -K ens5 tx off
+  ```
+
+Check the configuration by trying ssh from remote machine that
+connection is accepted but discarded in spp secondary.
+If you do ssh for VM1, you find a messages from spp secondary for
+discarding packets.
+
+## Test Application
+
+TODO(yasufum) json-based steps are deprecated.
+
+### Register MAC address to Classifier
+
+Send a request for getting each of process IDs with nc command.
+TODO(yasufum) for what?
+
+  ```sh
+  {
+    "commands": [
+      {
+        "command": "process"
+      }
+    ]
+  }
+  ```
+
+Register MAC addresses to classifier.
+
+  ```sh
+  {
+    "commands": [
+      {
+        "command": "classifier_table",
+        "type": "mac",
+        "value": "52:54:00:12:34:56",
+        "port": "ring0"
+      },
+      {
+        "command": "classifier_table",
+        "type": "mac",
+        "value": "52:54:00:12:34:58",
+        "port": "ring1"
+      },
+      {
+        "command": "flush"
+      }
+    ]
+  }
+  ```
+
+  ```sh
+  {
+    "commands": [
+      {
+        "command": "classifier_table",
+        "type": "mac",
+        "value": "52:54:00:12:34:57",
+        "port": "ring4"
+      },
+      {
+                    "command": "flush"
+      }
+    ]
+  }
+  ```
+
+### Login to VMs
+
+Now, you can login VMs.
+
+  ```sh
+  # spp-vm1 via NIC0
+  $ ssh ntt@192.168.240.21
+
+  # spp-vm1 via NIC1
+  $ ssh ntt@192.168.250.22
+
+  # spp-vm2 via NIC0
+  $ ssh ntt@192.168.240.31
+
+  # spp-vm2 via NIC1
+  $ ssh ntt@192.168.250.32
+  ```
+
+If you unregister the addresses, send request as following.
+
+  ```sh
+  {
+    "commands": [
+      {
+        "command": "classifier_table",
+        "type": "mac",
+        "value": "52:54:00:12:34:58",
+        "port": "unuse"
+      },
+      {
+        "command": "flush"
+      }
+    ]
+  }
+  ```
diff --git a/docs/spp_vf/setup.md b/docs/spp_vf/setup.md
deleted file mode 100644
index 450e68a..0000000
--- a/docs/spp_vf/setup.md
+++ /dev/null
@@ -1,291 +0,0 @@
-# Setup Guide
-
-## Environment
-
-* Ubuntu 16.04
-* qemu-kvm
-* DPDK v17.05
-
-## Setting
-
-### Host
-
-#### Edit Config
-
-Uncomment user and group in `/etc/libvirt/qemu.conf`.
-
-```sh
-# /etc/libvirt/qemu.conf
-
-user = "root"
-group = "root"
-```
-
-Change `KVM_HUGEPAGES` from 0 to 1 in `/etc/default/qemu-kvm`.
-
-```sh
-# /etc/default/qemu-kvm
-
-KVM_HUGEPAGES=1
-```
-
-Change grub config for hugepages and isolcpus.
-
-```sh
-# /etc/default/grub
-
-GRUB_CMDLINE_LINUX_DEFAULT="isolcpus=2,4,6,8,10,12-18,20,22,24,26-42,44,46 hugepagesz=1G hugepages=36 default_hugepagesz=1G"
-```
-
-You need to run `update-grub` and reboot to activate grub config.
-
-```sh
-$ sudo upadte-grub
-$ sudo reboot
-```
-
-You can check hugepage settings as following.
-
-```sh
-$ cat /proc/meminfo | grep -i huge
-AnonHugePages:      2048 kB
-HugePages_Total:      36		#	/etc/default/grub
-HugePages_Free:       36
-HugePages_Rsvd:        0
-HugePages_Surp:        0
-Hugepagesize:    1048576 kB		#	/etc/default/grub
-
-$ mount | grep -i huge
-cgroup on /sys/fs/cgroup/hugetlb type cgroup (rw,nosuid,nodev,noexec,relatime,hugetlb,release_agent=/run/cgmanager/agents/cgm-release-agent.hugetlb,nsroot=/)
-hugetlbfs on /dev/hugepages type hugetlbfs (rw,relatime)
-hugetlbfs-kvm on /run/hugepages/kvm type hugetlbfs (rw,relatime,mode=775,gid=117)
-hugetlb on /run/lxcfs/controllers/hugetlb type cgroup (rw,relatime,hugetlb,release_agent=/run/cgmanager/agents/cgm-release-agent.hugetlb,nsroot=/)
-```
-
-Finally, you unmount default hugepage.
-
-```sh
-$ sudo unmount /dev/hugepages
-```
-
-#### Install jasson
-
-Network configuration is defined in JSON and `spp_vf` reads config from
-the file while launching.
-[jasson](http://www.digip.org/jansson/) is a JSON library written in C.
-
-It is required to use `json_path` feature of `jasson` for `spp_vf`.
-It has develped under `json_path` branch and you need to checkout and compile
-it manually.
-
-```sh
-$ git clone https://github.com/rogerz/jansson
-$ cd jansson
-$ sudo git checkout json_path
-Branch json_path set up to track remote branch json_path from origin. Switched to a new branch 'json_path'
-```
-
-This setup guide expects that `jasson` is placed as `/opt/jasson`.
-
-```sh
-$ sudo mkdir -p /opt/jansson
-$ sudo mv jansson /opt/jansson
-```
-
-Compile it as following.
-
-```sh
-$ cd /opt/jansson/jansson
-$ sudo autoreconf -i
-$ sudo ./configure
-$ sudo make
-$ sudo make install
-$ sudo ldconfig
-```
-
-Then, confirm that header files of jasson are generated in `/usr/local/include`.
-
-```sh
-$ ls -al /usr/local/include
-total 24
-drwxr-xr-x  2 root root 4096 Jul 28 16:45 .
-drwxr-xr-x 10 root root 4096 May 27 10:23 ..
--rw-r--r--  1 root root 1183 Jul 28 16:45 jansson_config.h
--rw-r--r--  1 root root 9499 Jul 28 16:45 jansson.h
-```
-
-#### Install DPDK
-
-Install DPDK v17.05 in any directory. This is a simple instruction and please refer
-[Getting Started Guide for Linux](http://dpdk.org/doc/guides/linux_gsg/index.html)
-for details.
-
-```sh
-$ cd /path/to/any_dir
-$ git clone http://dpdk.org/git/dpdk
-$ cd dpdk
-$ git checkout v17.05
-$ export RTE_SDK=`pwd`
-$ export RTE_TARGET=x86_64-native-linuxapp-gcc
-$ make T=x86_64-native-linuxapp-gcc install
-```
-
-#### Install SPP
-
-Clone SPP in any directory and compile it.
-
-```sh
-$ cd /path/to/spp_home/
-$ git clone https://github.com/ntt-ns/Soft-Patch-Panel.git
-export SPP_HOME=/path/to/spp_home/Soft-Patch-Panel
-$ cd $SPP_HOME
-$ make
-```
-
-#### Setup for DPDK
-
-Load igb_uio module.
-
-```sh
-$ sudo modprobe uio
-$ sudo insmod $RTE_SDK/x86_64-native-linuxapp-gcc/kmod/igb_uio.ko
-$ lsmod | grep uio
-igb_uio                16384  0  # igb_uio is loaded
-uio                    20480  1 igb_uio
-```
-
-Then, bind it with PCI_Number.
-```sh
-$ $RTE_SDK/usertools/dpdk-devbind.py --status
-# check your device for PCI_Number
-
-$ sudo $RTE_SDK/usertools/dpdk-devbind.py --bind=igb_uio [PCI_Number]
-```
-
-#### virsh setup
-
-Edit VM configuration with virsh.
-
-```sh
-$ virsh edit [VM_NAME]
-```
-
-```xml
-<domain type='kvm' xmlns:qemu='http://libvirt.org/schemas/domain/qemu/1.0'>
-	  <name>spp-vm1</name>
-	  <uuid>d90f5420-861a-4479-8559-62d7a1545cb9</uuid>
-	  <memory unit='KiB'>4194304</memory>
-	  <currentMemory unit='KiB'>4194304</currentMemory>
-	  <memoryBacking>
-	    <hugepages/>
-	  </memoryBacking>
-	  <vcpu placement='static'>4</vcpu>
-	  <os>
-	    <type arch='x86_64' machine='pc-i440fx-2.3'>hvm</type>
-	    <boot dev='hd'/>
-	  </os>
-	  <features>
-	    <acpi/>
-	    <apic/>
-	    <pae/>
-	  </features>
-	  <clock offset='utc'/>
-	  <on_poweroff>destroy</on_poweroff>
-	  <on_reboot>restart</on_reboot>
-	  <on_crash>restart</on_crash>
-	  <devices>
-	    <emulator>/usr/local/bin/qemu-system-x86_64</emulator>
-	    <disk type='file' device='disk'>
-	      <driver name='qemu' type='raw'/>
-	      <source file='/var/lib/libvirt/images/spp-vm1.qcow2'/>
-	      <target dev='hda' bus='ide'/>
-	      <address type='drive' controller='0' bus='0' target='0' unit='0'/>
-	    </disk>
-	    <disk type='block' device='cdrom'>
-	      <driver name='qemu' type='raw'/>
-	      <target dev='hdc' bus='ide'/>
-	      <readonly/>
-	      <address type='drive' controller='0' bus='1' target='0' unit='0'/>
-	    </disk>
-	    <controller type='usb' index='0'>
-	      <address type='pci' domain='0x0000' bus='0x00' slot='0x01' function='0x2'/>
-	    </controller>
-	    <controller type='pci' index='0' model='pci-root'/>
-	    <controller type='ide' index='0'>
-	      <address type='pci' domain='0x0000' bus='0x00' slot='0x01' function='0x1'/>
-	    </controller>
-	    <interface type='network'>
-	      <mac address='52:54:00:99:aa:7f'/>
-	      <source network='default'/>
-	      <model type='rtl8139'/>
-	      <address type='pci' domain='0x0000' bus='0x00' slot='0x02' function='0x0'/>
-	    </interface>
-	    <serial type='pty'>
-	      <target type='isa-serial' port='0'/>
-	    </serial>
-	    <console type='pty'>
-	      <target type='serial' port='0'/>
-	    </console>
-	    <memballoon model='virtio'>
-	      <address type='pci' domain='0x0000' bus='0x00' slot='0x03' function='0x0'/>
-	    </memballoon>
-	  </devices>
-	  <qemu:commandline>
-	    <qemu:arg value='-cpu'/>
-	    <qemu:arg value='host'/>
-	    <qemu:arg value='-object'/>
-	    <qemu:arg value='memory-backend-file,id=mem,size=4096M,mem-path=/run/hugepages/kvm,share=on'/>
-	    <qemu:arg value='-numa'/>
-	    <qemu:arg value='node,memdev=mem'/>
-	    <qemu:arg value='-mem-prealloc'/>
-	    <qemu:arg value='-chardev'/>
-	    <qemu:arg value='socket,id=chr0,path=/tmp/sock0'/>
-	    <qemu:arg value='-device'/>
-	    <qemu:arg value='virtio-net-pci,netdev=vhost-net0'/>
-	    <qemu:arg value='-netdev'/>
-	    <qemu:arg value='vhost-user,id=vhost-net0,chardev=chr0,vhostforce'/>
-	    <qemu:arg value='-chardev'/>
-	    <qemu:arg value='socket,id=chr1,path=/tmp/sock1'/>
-	    <qemu:arg value='-device'/>
-	    <qemu:arg value='virtio-net-pci,netdev=vhost-net1'/>
-	    <qemu:arg value='-netdev'/>
-	    <qemu:arg value='vhost-user,id=vhost-net1,chardev=chr1,vhostforce'/>
-	  </qemu:commandline>
-	</domain>
-```
-
-### Trouble Shooting
-
-You might encounter a permission error for `tmp/sockN` because of appamor.
-In this case, you should try it.
-
-```sh
-$ sudo ln -s /etc/apparmor.d/usr.lib.libvirt.virt-aa-helper /etc/apparmor.d/disable/usr.lib.libvirt.virt-aa-helper
-$ sudo ln -s /etc/apparmor.d/usr.sbin.libvirtd /etc/apparmor.d/disable/usr.sbin.libvirtd
-$ sudo apparmor_parser -R /etc/apparmor.d/usr.lib.libvirt.virt-aa-helper
-$ sudo apparmor_parser -R /etc/apparmor.d/usr.sbin.libvirtd
-$ sudo service apparmor reload
-$ sudo service apparmor restart
-$ sudo service libvirt-bin restart
-```
-
-Or, you remove appamor.
-
-```sh
-$ sudo apt-get remove apparmor
-```
-
-If you use CentOS, not Ubuntu, confirm that SELinux doesn't prevent for permission.
-SELinux should be disabled in this case.
-
-```sh
-# /etc/selinux/config
-SELINUX=disabled
-```
-
-Check your SELinux configuration.
-
-```sh
-$ getenforce
-Disabled
-```
diff --git a/docs/spp_vf/setup_guide.md b/docs/spp_vf/setup_guide.md
new file mode 100644
index 0000000..450e68a
--- /dev/null
+++ b/docs/spp_vf/setup_guide.md
@@ -0,0 +1,291 @@
+# Setup Guide
+
+## Environment
+
+* Ubuntu 16.04
+* qemu-kvm
+* DPDK v17.05
+
+## Setting
+
+### Host
+
+#### Edit Config
+
+Uncomment user and group in `/etc/libvirt/qemu.conf`.
+
+```sh
+# /etc/libvirt/qemu.conf
+
+user = "root"
+group = "root"
+```
+
+Change `KVM_HUGEPAGES` from 0 to 1 in `/etc/default/qemu-kvm`.
+
+```sh
+# /etc/default/qemu-kvm
+
+KVM_HUGEPAGES=1
+```
+
+Change grub config for hugepages and isolcpus.
+
+```sh
+# /etc/default/grub
+
+GRUB_CMDLINE_LINUX_DEFAULT="isolcpus=2,4,6,8,10,12-18,20,22,24,26-42,44,46 hugepagesz=1G hugepages=36 default_hugepagesz=1G"
+```
+
+You need to run `update-grub` and reboot to activate grub config.
+
+```sh
+$ sudo upadte-grub
+$ sudo reboot
+```
+
+You can check hugepage settings as following.
+
+```sh
+$ cat /proc/meminfo | grep -i huge
+AnonHugePages:      2048 kB
+HugePages_Total:      36		#	/etc/default/grub
+HugePages_Free:       36
+HugePages_Rsvd:        0
+HugePages_Surp:        0
+Hugepagesize:    1048576 kB		#	/etc/default/grub
+
+$ mount | grep -i huge
+cgroup on /sys/fs/cgroup/hugetlb type cgroup (rw,nosuid,nodev,noexec,relatime,hugetlb,release_agent=/run/cgmanager/agents/cgm-release-agent.hugetlb,nsroot=/)
+hugetlbfs on /dev/hugepages type hugetlbfs (rw,relatime)
+hugetlbfs-kvm on /run/hugepages/kvm type hugetlbfs (rw,relatime,mode=775,gid=117)
+hugetlb on /run/lxcfs/controllers/hugetlb type cgroup (rw,relatime,hugetlb,release_agent=/run/cgmanager/agents/cgm-release-agent.hugetlb,nsroot=/)
+```
+
+Finally, you unmount default hugepage.
+
+```sh
+$ sudo unmount /dev/hugepages
+```
+
+#### Install jasson
+
+Network configuration is defined in JSON and `spp_vf` reads config from
+the file while launching.
+[jasson](http://www.digip.org/jansson/) is a JSON library written in C.
+
+It is required to use `json_path` feature of `jasson` for `spp_vf`.
+It has develped under `json_path` branch and you need to checkout and compile
+it manually.
+
+```sh
+$ git clone https://github.com/rogerz/jansson
+$ cd jansson
+$ sudo git checkout json_path
+Branch json_path set up to track remote branch json_path from origin. Switched to a new branch 'json_path'
+```
+
+This setup guide expects that `jasson` is placed as `/opt/jasson`.
+
+```sh
+$ sudo mkdir -p /opt/jansson
+$ sudo mv jansson /opt/jansson
+```
+
+Compile it as following.
+
+```sh
+$ cd /opt/jansson/jansson
+$ sudo autoreconf -i
+$ sudo ./configure
+$ sudo make
+$ sudo make install
+$ sudo ldconfig
+```
+
+Then, confirm that header files of jasson are generated in `/usr/local/include`.
+
+```sh
+$ ls -al /usr/local/include
+total 24
+drwxr-xr-x  2 root root 4096 Jul 28 16:45 .
+drwxr-xr-x 10 root root 4096 May 27 10:23 ..
+-rw-r--r--  1 root root 1183 Jul 28 16:45 jansson_config.h
+-rw-r--r--  1 root root 9499 Jul 28 16:45 jansson.h
+```
+
+#### Install DPDK
+
+Install DPDK v17.05 in any directory. This is a simple instruction and please refer
+[Getting Started Guide for Linux](http://dpdk.org/doc/guides/linux_gsg/index.html)
+for details.
+
+```sh
+$ cd /path/to/any_dir
+$ git clone http://dpdk.org/git/dpdk
+$ cd dpdk
+$ git checkout v17.05
+$ export RTE_SDK=`pwd`
+$ export RTE_TARGET=x86_64-native-linuxapp-gcc
+$ make T=x86_64-native-linuxapp-gcc install
+```
+
+#### Install SPP
+
+Clone SPP in any directory and compile it.
+
+```sh
+$ cd /path/to/spp_home/
+$ git clone https://github.com/ntt-ns/Soft-Patch-Panel.git
+export SPP_HOME=/path/to/spp_home/Soft-Patch-Panel
+$ cd $SPP_HOME
+$ make
+```
+
+#### Setup for DPDK
+
+Load igb_uio module.
+
+```sh
+$ sudo modprobe uio
+$ sudo insmod $RTE_SDK/x86_64-native-linuxapp-gcc/kmod/igb_uio.ko
+$ lsmod | grep uio
+igb_uio                16384  0  # igb_uio is loaded
+uio                    20480  1 igb_uio
+```
+
+Then, bind it with PCI_Number.
+```sh
+$ $RTE_SDK/usertools/dpdk-devbind.py --status
+# check your device for PCI_Number
+
+$ sudo $RTE_SDK/usertools/dpdk-devbind.py --bind=igb_uio [PCI_Number]
+```
+
+#### virsh setup
+
+Edit VM configuration with virsh.
+
+```sh
+$ virsh edit [VM_NAME]
+```
+
+```xml
+<domain type='kvm' xmlns:qemu='http://libvirt.org/schemas/domain/qemu/1.0'>
+	  <name>spp-vm1</name>
+	  <uuid>d90f5420-861a-4479-8559-62d7a1545cb9</uuid>
+	  <memory unit='KiB'>4194304</memory>
+	  <currentMemory unit='KiB'>4194304</currentMemory>
+	  <memoryBacking>
+	    <hugepages/>
+	  </memoryBacking>
+	  <vcpu placement='static'>4</vcpu>
+	  <os>
+	    <type arch='x86_64' machine='pc-i440fx-2.3'>hvm</type>
+	    <boot dev='hd'/>
+	  </os>
+	  <features>
+	    <acpi/>
+	    <apic/>
+	    <pae/>
+	  </features>
+	  <clock offset='utc'/>
+	  <on_poweroff>destroy</on_poweroff>
+	  <on_reboot>restart</on_reboot>
+	  <on_crash>restart</on_crash>
+	  <devices>
+	    <emulator>/usr/local/bin/qemu-system-x86_64</emulator>
+	    <disk type='file' device='disk'>
+	      <driver name='qemu' type='raw'/>
+	      <source file='/var/lib/libvirt/images/spp-vm1.qcow2'/>
+	      <target dev='hda' bus='ide'/>
+	      <address type='drive' controller='0' bus='0' target='0' unit='0'/>
+	    </disk>
+	    <disk type='block' device='cdrom'>
+	      <driver name='qemu' type='raw'/>
+	      <target dev='hdc' bus='ide'/>
+	      <readonly/>
+	      <address type='drive' controller='0' bus='1' target='0' unit='0'/>
+	    </disk>
+	    <controller type='usb' index='0'>
+	      <address type='pci' domain='0x0000' bus='0x00' slot='0x01' function='0x2'/>
+	    </controller>
+	    <controller type='pci' index='0' model='pci-root'/>
+	    <controller type='ide' index='0'>
+	      <address type='pci' domain='0x0000' bus='0x00' slot='0x01' function='0x1'/>
+	    </controller>
+	    <interface type='network'>
+	      <mac address='52:54:00:99:aa:7f'/>
+	      <source network='default'/>
+	      <model type='rtl8139'/>
+	      <address type='pci' domain='0x0000' bus='0x00' slot='0x02' function='0x0'/>
+	    </interface>
+	    <serial type='pty'>
+	      <target type='isa-serial' port='0'/>
+	    </serial>
+	    <console type='pty'>
+	      <target type='serial' port='0'/>
+	    </console>
+	    <memballoon model='virtio'>
+	      <address type='pci' domain='0x0000' bus='0x00' slot='0x03' function='0x0'/>
+	    </memballoon>
+	  </devices>
+	  <qemu:commandline>
+	    <qemu:arg value='-cpu'/>
+	    <qemu:arg value='host'/>
+	    <qemu:arg value='-object'/>
+	    <qemu:arg value='memory-backend-file,id=mem,size=4096M,mem-path=/run/hugepages/kvm,share=on'/>
+	    <qemu:arg value='-numa'/>
+	    <qemu:arg value='node,memdev=mem'/>
+	    <qemu:arg value='-mem-prealloc'/>
+	    <qemu:arg value='-chardev'/>
+	    <qemu:arg value='socket,id=chr0,path=/tmp/sock0'/>
+	    <qemu:arg value='-device'/>
+	    <qemu:arg value='virtio-net-pci,netdev=vhost-net0'/>
+	    <qemu:arg value='-netdev'/>
+	    <qemu:arg value='vhost-user,id=vhost-net0,chardev=chr0,vhostforce'/>
+	    <qemu:arg value='-chardev'/>
+	    <qemu:arg value='socket,id=chr1,path=/tmp/sock1'/>
+	    <qemu:arg value='-device'/>
+	    <qemu:arg value='virtio-net-pci,netdev=vhost-net1'/>
+	    <qemu:arg value='-netdev'/>
+	    <qemu:arg value='vhost-user,id=vhost-net1,chardev=chr1,vhostforce'/>
+	  </qemu:commandline>
+	</domain>
+```
+
+### Trouble Shooting
+
+You might encounter a permission error for `tmp/sockN` because of appamor.
+In this case, you should try it.
+
+```sh
+$ sudo ln -s /etc/apparmor.d/usr.lib.libvirt.virt-aa-helper /etc/apparmor.d/disable/usr.lib.libvirt.virt-aa-helper
+$ sudo ln -s /etc/apparmor.d/usr.sbin.libvirtd /etc/apparmor.d/disable/usr.sbin.libvirtd
+$ sudo apparmor_parser -R /etc/apparmor.d/usr.lib.libvirt.virt-aa-helper
+$ sudo apparmor_parser -R /etc/apparmor.d/usr.sbin.libvirtd
+$ sudo service apparmor reload
+$ sudo service apparmor restart
+$ sudo service libvirt-bin restart
+```
+
+Or, you remove appamor.
+
+```sh
+$ sudo apt-get remove apparmor
+```
+
+If you use CentOS, not Ubuntu, confirm that SELinux doesn't prevent for permission.
+SELinux should be disabled in this case.
+
+```sh
+# /etc/selinux/config
+SELINUX=disabled
+```
+
+Check your SELinux configuration.
+
+```sh
+$ getenforce
+Disabled
+```
diff --git a/docs/spp_vf/spp_vf.md b/docs/spp_vf/spp_vf.md
index 786e712..99c914f 100644
--- a/docs/spp_vf/spp_vf.md
+++ b/docs/spp_vf/spp_vf.md
@@ -29,12 +29,16 @@ by looking MAC address in the packet..
 
 ## Build the Application
 
-See [setup guide](setup.md).
+See [setup guide](setup_guide.md).
 
 ## Running the Application
 
 See [how to use](how_to_use.md).
 
+## Sample Usage
+
+See [sample usage](sample_usage.md).
+
 ## Explanation
 
 The following sections provide some explanation of the code.
-- 
1.9.1

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

* [spp] [PATCH 12/30] doc: revice path descs
  2018-01-15 11:04 ` [spp] Proposal - spp_vf(SR-IOV like feature) addition to SPP Ferruh Yigit
                     ` (10 preceding siblings ...)
  2018-01-16  5:16   ` [spp] [PATCH 11/30] doc: add sample usage x-fn-spp
@ 2018-01-16  5:16   ` x-fn-spp
  2018-01-16  5:16   ` [spp] [PATCH 13/30] doc: add network configuration diagram x-fn-spp
                     ` (17 subsequent siblings)
  29 siblings, 0 replies; 97+ messages in thread
From: x-fn-spp @ 2018-01-16  5:16 UTC (permalink / raw)
  To: spp

From: Hiroyuki Nakamura <nakamura.hioryuki@po.ntt-tx.co.jp>

Signed-off-by: Naoki Takada <takada.naoki@lab.ntt.co.jp>
---
 docs/spp_vf/sample_usage.md | 6 +++---
 1 file changed, 3 insertions(+), 3 deletions(-)

diff --git a/docs/spp_vf/sample_usage.md b/docs/spp_vf/sample_usage.md
index 2157378..5f6ece2 100644
--- a/docs/spp_vf/sample_usage.md
+++ b/docs/spp_vf/sample_usage.md
@@ -43,7 +43,7 @@ TODO(yasufum) add description for sec.
   -c 0x00fd -n 4 --proc-type=secondary \
   -- \
   --process-id 1 \
-  --config $SPRINT_REVIEW_HOME/spp_vf1_without_cmtab.json \
+  --config /path/to/spp_vf1_without_cmtab.json \
   -s 127.0.0.1:11111
 
   # start nc for secondary 2
@@ -54,11 +54,11 @@ TODO(yasufum) add description for sec.
   -c 0x3f01 -n 4 --proc-type=secondary \
   -- \
   --process-id 2 \
-  --config $SPRINT_REVIEW_HOME/spp_vf2_without_cmtab.json \
+  --config /path/to/spp_vf2_without_cmtab.json \
   -s 127.0.0.1:11112
   ```
 
-### Setup network configuration for VMs.
+### Setup network configuration for VMs
 
 Start two VMs.
 
-- 
1.9.1

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

* [spp] [PATCH 13/30] doc: add network configuration diagram
  2018-01-15 11:04 ` [spp] Proposal - spp_vf(SR-IOV like feature) addition to SPP Ferruh Yigit
                     ` (11 preceding siblings ...)
  2018-01-16  5:16   ` [spp] [PATCH 12/30] doc: revice path descs x-fn-spp
@ 2018-01-16  5:16   ` x-fn-spp
  2018-01-16  5:16   ` [spp] [PATCH 14/30] doc: update user account x-fn-spp
                     ` (16 subsequent siblings)
  29 siblings, 0 replies; 97+ messages in thread
From: x-fn-spp @ 2018-01-16  5:16 UTC (permalink / raw)
  To: spp

From: Hiroyuki Nakamura <nakamura.hioryuki@po.ntt-tx.co.jp>

Signed-off-by: Naoki Takada <takada.naoki@lab.ntt.co.jp>
---
 docs/spp_vf/sample_usage.md | 2 ++
 1 file changed, 2 insertions(+)

diff --git a/docs/spp_vf/sample_usage.md b/docs/spp_vf/sample_usage.md
index 5f6ece2..bb4d540 100644
--- a/docs/spp_vf/sample_usage.md
+++ b/docs/spp_vf/sample_usage.md
@@ -7,6 +7,8 @@ It enables to access to VMs with ssh from a remote node.
 Before trying this sample, install SPP by following
 [setup guide](setup_guide.md).
 
+![spp_sample_usage](spp_sample_usage.svg)
+
 ## Testing Steps
 
 In this section, you configure spp_vf and client applications for
-- 
1.9.1

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

* [spp] [PATCH 14/30] doc: update user account
  2018-01-15 11:04 ` [spp] Proposal - spp_vf(SR-IOV like feature) addition to SPP Ferruh Yigit
                     ` (12 preceding siblings ...)
  2018-01-16  5:16   ` [spp] [PATCH 13/30] doc: add network configuration diagram x-fn-spp
@ 2018-01-16  5:16   ` x-fn-spp
  2018-01-16  5:16   ` [spp] [PATCH 15/30] doc: update descriptions for todo x-fn-spp
                     ` (15 subsequent siblings)
  29 siblings, 0 replies; 97+ messages in thread
From: x-fn-spp @ 2018-01-16  5:16 UTC (permalink / raw)
  To: spp

From: Hiroyuki Nakamura <nakamura.hioryuki@po.ntt-tx.co.jp>

User account 'ntt' is not appropriate for example of spp's usacase.
Change to 'sppuser'.

Signed-off-by: Naoki Takada <takada.naoki@lab.ntt.co.jp>
---
 docs/spp_vf/sample_usage.md | 41 ++++++++++++++---------------------------
 1 file changed, 14 insertions(+), 27 deletions(-)

diff --git a/docs/spp_vf/sample_usage.md b/docs/spp_vf/sample_usage.md
index bb4d540..00e1631 100644
--- a/docs/spp_vf/sample_usage.md
+++ b/docs/spp_vf/sample_usage.md
@@ -74,7 +74,7 @@ To not ask for unknown keys while login VMs,
 set `-oStrictHostKeyChecking=no` option for ssh.
 
   ```sh
-  $ ssh -oStrictHostKeyChecking=no ntt@192.168.122.31
+  $ ssh -oStrictHostKeyChecking=no sppuser@192.168.122.31
   ```
 
 Up interfaces for vhost and register them to arp table inside spp-vm1.
@@ -83,12 +83,12 @@ after configuration is done.
 
   ```sh
   # up interfaces
-  $ sudo ifconfig ens4 inet 192.168.240.21 netmask 255.255.255.0 up
-  $ sudo ifconfig ens5 inet 192.168.250.22 netmask 255.255.255.0 up
+  $ sudo ifconfig ens4 inet 192.168.140.21 netmask 255.255.255.0 up
+  $ sudo ifconfig ens5 inet 192.168.150.22 netmask 255.255.255.0 up
 
   # register to arp table
-  $ sudo arp -s 192.168.240.11 a0:36:9f:78:86:78 -i ens4
-  $ sudo arp -s 192.168.250.13 a0:36:9f:6c:ed:bc -i ens5
+  $ sudo arp -s 192.168.140.11 a0:36:9f:78:86:78 -i ens4
+  $ sudo arp -s 192.168.150.13 a0:36:9f:6c:ed:bc -i ens5
 
   # diable TCP offload
   $ sudo ethtool -K ens4 tx off
@@ -98,15 +98,15 @@ after configuration is done.
 Configurations for spp-vm2 is same as spp-vm1.
 
   ```sh
-  $ ssh -oStrictHostKeyChecking=no ntt@192.168.122.32
+  $ ssh -oStrictHostKeyChecking=no sppuser@192.168.122.32
 
   # up interfaces
-  $ sudo ifconfig ens4 inet 192.168.240.31 netmask 255.255.255.0 up
-  $ sudo ifconfig ens5 inet 192.168.250.32 netmask 255.255.255.0 up
+  $ sudo ifconfig ens4 inet 192.168.140.31 netmask 255.255.255.0 up
+  $ sudo ifconfig ens5 inet 192.168.150.32 netmask 255.255.255.0 up
 
   # register to arp table
-  $ sudo arp -s 192.168.240.11 a0:36:9f:78:86:78 -i ens4
-  $ sudo arp -s 192.168.250.13 a0:36:9f:6c:ed:bc -i ens5
+  $ sudo arp -s 192.168.140.11 a0:36:9f:78:86:78 -i ens4
+  $ sudo arp -s 192.168.150.13 a0:36:9f:6c:ed:bc -i ens5
 
   # diable TCP offload
   $ sudo ethtool -K ens4 tx off
@@ -124,19 +124,6 @@ TODO(yasufum) json-based steps are deprecated.
 
 ### Register MAC address to Classifier
 
-Send a request for getting each of process IDs with nc command.
-TODO(yasufum) for what?
-
-  ```sh
-  {
-    "commands": [
-      {
-        "command": "process"
-      }
-    ]
-  }
-  ```
-
 Register MAC addresses to classifier.
 
   ```sh
@@ -183,16 +170,16 @@ Now, you can login VMs.
 
   ```sh
   # spp-vm1 via NIC0
-  $ ssh ntt@192.168.240.21
+  $ ssh sppuser@192.168.140.21
 
   # spp-vm1 via NIC1
-  $ ssh ntt@192.168.250.22
+  $ ssh sppuser@192.168.150.22
 
   # spp-vm2 via NIC0
-  $ ssh ntt@192.168.240.31
+  $ ssh sppuser@192.168.140.31
 
   # spp-vm2 via NIC1
-  $ ssh ntt@192.168.250.32
+  $ ssh sppuser@192.168.150.32
   ```
 
 If you unregister the addresses, send request as following.
-- 
1.9.1

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

* [spp] [PATCH 15/30] doc: update descriptions for todo
  2018-01-15 11:04 ` [spp] Proposal - spp_vf(SR-IOV like feature) addition to SPP Ferruh Yigit
                     ` (13 preceding siblings ...)
  2018-01-16  5:16   ` [spp] [PATCH 14/30] doc: update user account x-fn-spp
@ 2018-01-16  5:16   ` x-fn-spp
  2018-01-16  5:16   ` [spp] [PATCH 16/30] doc: add description for explanation section x-fn-spp
                     ` (14 subsequent siblings)
  29 siblings, 0 replies; 97+ messages in thread
From: x-fn-spp @ 2018-01-16  5:16 UTC (permalink / raw)
  To: spp

From: Hiroyuki Nakamura <nakamura.hioryuki@po.ntt-tx.co.jp>

- Add why use nc command and how.
- Change the status of json based steps from 'are deprecated' to
  'will be deprecated'.

Signed-off-by: Naoki Takada <takada.naoki@lab.ntt.co.jp>
---
 docs/spp_vf/sample_usage.md | 14 ++++++++++----
 1 file changed, 10 insertions(+), 4 deletions(-)

diff --git a/docs/spp_vf/sample_usage.md b/docs/spp_vf/sample_usage.md
index 00e1631..ce68867 100644
--- a/docs/spp_vf/sample_usage.md
+++ b/docs/spp_vf/sample_usage.md
@@ -34,10 +34,16 @@ First, launch spp controller and primary process.
   -p 0x03 -n 8 -s 127.0.0.1:5555
   ```
 
-TODO(yasufum) add description for sec.
+After primary process is launched, run nc command for each of
+seconrdary processes and itselves.
+In this sample, commands for secondary are sent from nc because
+`spp.py` does not support commands for spp_vf.
+nc is a network utility and it can open TCP connections, send UDP
+packets, listen on arbitrary TCP and UDP ports, do port scanning,
+and deal with both IPv4 and IPv6.
 
   ```sh
-  # start nc for secondary 1
+  # run nc for secondary 1 with port 11111
   $ while true; do nc -l 11111; done
 
   # start secondary 1
@@ -48,7 +54,7 @@ TODO(yasufum) add description for sec.
   --config /path/to/spp_vf1_without_cmtab.json \
   -s 127.0.0.1:11111
 
-  # start nc for secondary 2
+  # run nc for secondary 2 with port 11112
   $ while true; do nc -l 11112; done
 
   # start secondary 2
@@ -120,7 +126,7 @@ discarding packets.
 
 ## Test Application
 
-TODO(yasufum) json-based steps are deprecated.
+TODO(yasufum) json-based steps will be deprecated.
 
 ### Register MAC address to Classifier
 
-- 
1.9.1

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

* [spp] [PATCH 16/30] doc: add description for explanation section
  2018-01-15 11:04 ` [spp] Proposal - spp_vf(SR-IOV like feature) addition to SPP Ferruh Yigit
                     ` (14 preceding siblings ...)
  2018-01-16  5:16   ` [spp] [PATCH 15/30] doc: update descriptions for todo x-fn-spp
@ 2018-01-16  5:16   ` x-fn-spp
  2018-01-16  5:16   ` [spp] [PATCH 17/30] doc: add spp_sample_usage_svg in docs/spp_vf/ x-fn-spp
                     ` (13 subsequent siblings)
  29 siblings, 0 replies; 97+ messages in thread
From: x-fn-spp @ 2018-01-16  5:16 UTC (permalink / raw)
  To: spp

From: Hiroyuki Nakamura <nakamura.hioryuki@po.ntt-tx.co.jp>

Add details explanation for essential parts of spp_vf for
developers.

Signed-off-by: Naoki Takada <takada.naoki@lab.ntt.co.jp>
---
 docs/spp_vf/spp_vf.md | 221 ++++++++++++++++++++++++++++++++++++++++++++++++--
 1 file changed, 214 insertions(+), 7 deletions(-)

diff --git a/docs/spp_vf/spp_vf.md b/docs/spp_vf/spp_vf.md
index 786e712..19ea403 100644
--- a/docs/spp_vf/spp_vf.md
+++ b/docs/spp_vf/spp_vf.md
@@ -4,8 +4,8 @@ SPP_VF is a SR-IOV like network functionality using DPDK for NFV.
 
 ## Overview
 
-The application distributes incoming packets depends on MAC address
-similar to SR-IOV functionality.
+The application distributes incoming packets referring virtual MAC
+address similar to SR-IOV functionality.
 Network configuration is defined in JSON config file which is imported
 while launching the application.
 The configuration is able to change after initialization by sending
@@ -13,14 +13,14 @@ commnad from spp controller.
 
 SPP_VF is a multi-thread application.
 It consists of manager thread and forwarder threads.
-There are three types of forwarder for 1:1, 1:N and N:1.
+There are three types of forwarder for 1:1, 1:N and N:1 as following.
 
   * forward: 1:1
   * classifier_mac: 1:N (Destination is determined by MAC address)
   * merge: N:1
 
 This is an example of network configration, in which one classifier_mac,
-one merger and four forwarders are runnig in spp_vf process for two
+one merger and four forwarders are runnig in SPP_VF process for two
 destinations of vhost interface.
 Incoming packets from rx on host1 are sent to each of vhosts on guest
 by looking MAC address in the packet..
@@ -95,9 +95,15 @@ file and return json_t object as a result.
 In spp_config_load_file(), configuration of classifier table and
 resource assignment of threads are loaded into config of spp.
 
-After importing config, each of threads are launched.
+### Forwarding
+
+SPP_VF supports three types of forwarding, for 1:1, 1:N and N:1.
+After importing config, each of forwarding threads are launched
+from`rte_eal_remote_launch()`.
 
   ```c
+  /* spp_vf.c */
+
 	/* Start  thread */
 	unsigned int lcore_id = 0;
 	RTE_LCORE_FOREACH_SLAVE(lcore_id) {
@@ -113,9 +119,210 @@ After importing config, each of threads are launched.
 	}
   ```
 
-### Forwarding
+`spp_classifier_mac_do()` is a forwarding function of 1:N defined in
+`classifier_mac.c`.
+Configuration of destination is managed as a table structured info.
+`classifier_mac_info` and `classifier_mac_mng_info` struct are for
+the purpose.
+
+TODO(yasufum) add desc for table structure and it's doubled for
+redundancy.
+
+  ```c
+  /* classifier_mac.c */
+
+  /* classifier information */
+  struct classifier_mac_info {
+  	struct rte_hash *classifier_table;
+  	int num_active_classified;
+  	int active_classifieds[RTE_MAX_ETHPORTS];
+  	int default_classified;
+  };
+
+  /* classifier management information */
+  struct classifier_mac_mng_info {
+  	struct classifier_mac_info info[NUM_CLASSIFIER_MAC_INFO];
+  	volatile int ref_index;
+  	volatile int upd_index;
+  	struct classified_data classified_data[RTE_MAX_ETHPORTS];
+  };
+  ```
+
+In `spp_classifier_mac_do()`, it receives packets from rx port and send them
+to destinations with `classify_packet()`.
+`classifier_info` is an argument of `classify_packet()` and is used to decide
+the destinations.
+
+  ```c
+  /* classifier_mac.c */
+
+	while(likely(core_info->status == SPP_CORE_IDLE) ||
+			likely(core_info->status == SPP_CORE_FORWARD)) {
+
+		while(likely(core_info->status == SPP_CORE_FORWARD)) {
+			/* change index of update side */
+			change_update_index(classifier_mng_info, lcore_id);
+
+			/* decide classifier infomation of the current cycle */
+			classifier_info = classifier_mng_info->info +
+					classifier_mng_info->ref_index;
+
+			/* drain tx packets, if buffer is not filled for interval */
+			cur_tsc = rte_rdtsc();
+			if (unlikely(cur_tsc - prev_tsc > drain_tsc)) {
+				for (i = 0; i < n_classified_data; i++) {
+					if (unlikely(classified_data[i].num_pkt != 0)) {
+						RTE_LOG(DEBUG, SPP_CLASSIFIER_MAC,
+                        					"transimit packets (drain). "
+								"index=%d, "
+								"num_pkt=%hu, "
+								"interval=%lu\n",
+								i,
+								classified_data[i].num_pkt,
+								cur_tsc - prev_tsc);
+						transmit_packet(&classified_data[i]);
+					}
+				}
+				prev_tsc = cur_tsc;
+			}
+
+			/* retrieve packets */
+			n_rx = rte_eth_rx_burst(core_info->rx_ports[0].dpdk_port, 0,
+					rx_pkts, MAX_PKT_BURST);
+			if (unlikely(n_rx == 0))
+				continue;
+
+#ifdef SPP_RINGLATENCYSTATS_ENABLE
+			if (core_info->rx_ports[0].if_type == RING)
+				spp_ringlatencystats_calculate_latency(
+						core_info->rx_ports[0].if_no, rx_pkts, n_rx);
+#endif
+
+			/* classify and transmit (filled) */
+			classify_packet(rx_pkts, n_rx, classifier_info, classified_data);
+		}
+	}
+  ```
+
+On the other hand, `spp_forward` is for 1:1 or N:1 (called as merge)
+forwarding defined in `spp_forward.c`.
+Source and destination ports are decided from `core_info`
+and given to `set_use_interface()` in which first argment is
+destination info and second one is source.
+
+  ```c
+  /* spp_forward.c */
+
+	/* RX/TX Info setting */
+	rxtx_num = core_info->num_rx_port;
+	for (if_cnt = 0; if_cnt < rxtx_num; if_cnt++) {
+		set_use_interface(&patch[if_cnt].rx,
+				&core_info->rx_ports[if_cnt]);
+		if (core_info->type == SPP_CONFIG_FORWARD) {
+			/* FORWARD */
+			set_use_interface(&patch[if_cnt].tx,
+					&core_info->tx_ports[if_cnt]);
+		} else {
+			/* MERGE */
+			set_use_interface(&patch[if_cnt].tx,
+					&core_info->tx_ports[0]);
+		}
+	}
+  ```
+
+  After ports are decided, forwarding is executed.
+
+  ```c
+  /* spp_forward.c */
+
+	int cnt, nb_rx, nb_tx, buf;
+	struct spp_core_port_info *rx;
+	struct spp_core_port_info *tx;
+	struct rte_mbuf *bufs[MAX_PKT_BURST];
+	while (likely(core_info->status == SPP_CORE_IDLE) ||
+			likely(core_info->status == SPP_CORE_FORWARD)) {
+		while (likely(core_info->status == SPP_CORE_FORWARD)) {
+			for (cnt = 0; cnt < rxtx_num; cnt++) {
+				rx = &patch[cnt].rx;
+				tx = &patch[cnt].tx;
+
+				/* Packet receive */
+				nb_rx = rte_eth_rx_burst(rx->dpdk_port, 0, bufs, MAX_PKT_BURST);
+				if (unlikely(nb_rx == 0)) {
+					continue;
+				}
+
+#ifdef SPP_RINGLATENCYSTATS_ENABLE
+				if (rx->if_type == RING) {
+					/* Receive port is RING */
+					spp_ringlatencystats_calculate_latency(rx->if_no,
+							bufs, nb_rx);
+				}
+				if (tx->if_type == RING) {
+					/* Send port is RING */
+					spp_ringlatencystats_add_time_stamp(tx->if_no,
+							bufs, nb_rx);
+				}
+#endif /* SPP_RINGLATENCYSTATS_ENABLE */
+
+				/* Send packet */
+				nb_tx = rte_eth_tx_burst(tx->dpdk_port, 0, bufs, nb_rx);
+
+				/* Free any unsent packets. */
+				if (unlikely(nb_tx < nb_rx)) {
+					for (buf = nb_tx; buf < nb_rx; buf++) {
+						rte_pktmbuf_free(bufs[buf]);
+					}
+				}
+			}
+		}
+	}
+  ```
 
+### L2 Multicast Support
 
-### Packet Cloning
+Multicast for resolving ARP requests is also supported in SPP_VF.
+It is implemented as `handle_l2multicast_packet()` and called from
+`classify_packet()` for incoming multicast packets.
 
+  ```c
+  /* classify_packet() in classifier_mac.c */
+
+  /* L2 multicast(include broadcast) ? */
+  if (unlikely(is_multicast_ether_addr(&eth->d_addr))) {
+  	RTE_LOG(DEBUG, SPP_CLASSIFIER_MAC,
+  			"multicast mac address.\n");
+  	handle_l2multicast_packet(rx_pkts[i],
+  			classifier_info, classified_data);
+  	continue;
+  }
+  ```
+
+For distributing multicast packet, it is cloned with
+`rte_mbuf_refcnt_update()`.
 
+  ```c
+  /* classifier_mac.c */
+
+  /* handle L2 multicast(include broadcast) packet */
+  static inline void
+  handle_l2multicast_packet(struct rte_mbuf *pkt,
+  		struct classifier_mac_info *classifier_info,
+  		struct classified_data *classified_data)
+  {
+  	int i;
+
+  	if (unlikely(classifier_info->num_active_classified == 0)) {
+  		RTE_LOG(ERR, SPP_CLASSIFIER_MAC, "No mac address.(l2multicast packet)\n");
+  		rte_pktmbuf_free(pkt);
+  		return;
+  	}
+
+  	rte_mbuf_refcnt_update(pkt, classifier_info->num_active_classified);
+
+  	for (i= 0; i < classifier_info->num_active_classified; i++) {
+  		push_packet(pkt, classified_data +
+  				(long)classifier_info->active_classifieds[i]);
+  	}
+  }
+  ```
-- 
1.9.1

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

* [spp] [PATCH 17/30] doc: add spp_sample_usage_svg in docs/spp_vf/
  2018-01-15 11:04 ` [spp] Proposal - spp_vf(SR-IOV like feature) addition to SPP Ferruh Yigit
                     ` (15 preceding siblings ...)
  2018-01-16  5:16   ` [spp] [PATCH 16/30] doc: add description for explanation section x-fn-spp
@ 2018-01-16  5:16   ` x-fn-spp
  2018-01-16  5:16   ` [spp] [PATCH 18/30] doc: add explanation for terminating spp app x-fn-spp
                     ` (12 subsequent siblings)
  29 siblings, 0 replies; 97+ messages in thread
From: x-fn-spp @ 2018-01-16  5:16 UTC (permalink / raw)
  To: spp

From: Hiroyuki Nakamura <nakamura.hioryuki@po.ntt-tx.co.jp>

Add spp_sample_usage.svg file in docs/spp_vf, which is removed
from docs/ directory.

Signed-off-by: Tomoyuki Mizuguchi <mizuguchi.tomoyuki@po.ntt-tx.co.jp>
Signed-off-by: Naoki Takada <takada.naoki@lab.ntt.co.jp>
---
 docs/spp_vf/spp_sample_usage.svg | 3144 ++++++++++++++++++++++++++++++++++++++
 1 file changed, 3144 insertions(+)
 create mode 100644 docs/spp_vf/spp_sample_usage.svg

diff --git a/docs/spp_vf/spp_sample_usage.svg b/docs/spp_vf/spp_sample_usage.svg
new file mode 100644
index 0000000..3fdd7df
--- /dev/null
+++ b/docs/spp_vf/spp_sample_usage.svg
@@ -0,0 +1,3144 @@
+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+<!-- Created with Inkscape (http://www.inkscape.org/) -->
+
+<svg
+   xmlns:dc="http://purl.org/dc/elements/1.1/"
+   xmlns:cc="http://creativecommons.org/ns#"
+   xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
+   xmlns:svg="http://www.w3.org/2000/svg"
+   xmlns="http://www.w3.org/2000/svg"
+   xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
+   xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
+   width="172.52679mm"
+   height="120.57605mm"
+   viewBox="0 0 172.52679 120.57605"
+   version="1.1"
+   id="svg4746"
+   inkscape:version="0.92.2 (5c3e80d, 2017-08-06)"
+   sodipodi:docname="spp_sample_usage.svg">
+  <defs
+     id="defs4740">
+    <marker
+       inkscape:stockid="Arrow2Lend"
+       orient="auto"
+       refY="0.0"
+       refX="0.0"
+       id="marker39126"
+       style="overflow:visible;"
+       inkscape:isstock="true">
+      <path
+         id="path39124"
+         style="fill-rule:evenodd;stroke-width:0.625;stroke-linejoin:round;stroke:#000000;stroke-opacity:1;fill:#000000;fill-opacity:1"
+         d="M 8.7185878,4.0337352 L -2.2072895,0.016013256 L 8.7185884,-4.0017078 C 6.9730900,-1.6296469 6.9831476,1.6157441 8.7185878,4.0337352 z "
+         transform="scale(1.1) rotate(180) translate(1,0)" />
+    </marker>
+    <marker
+       inkscape:isstock="true"
+       style="overflow:visible;"
+       id="marker34720"
+       refX="0.0"
+       refY="0.0"
+       orient="auto"
+       inkscape:stockid="Arrow2Lend">
+      <path
+         transform="scale(1.1) rotate(180) translate(1,0)"
+         d="M 8.7185878,4.0337352 L -2.2072895,0.016013256 L 8.7185884,-4.0017078 C 6.9730900,-1.6296469 6.9831476,1.6157441 8.7185878,4.0337352 z "
+         style="fill-rule:evenodd;stroke-width:0.625;stroke-linejoin:round;stroke:#000000;stroke-opacity:1;fill:#000000;fill-opacity:1"
+         id="path34718" />
+    </marker>
+    <marker
+       inkscape:stockid="Arrow2Lend"
+       orient="auto"
+       refY="0.0"
+       refX="0.0"
+       id="marker33826"
+       style="overflow:visible;"
+       inkscape:isstock="true">
+      <path
+         id="path33824"
+         style="fill-rule:evenodd;stroke-width:0.625;stroke-linejoin:round;stroke:#000000;stroke-opacity:1;fill:#000000;fill-opacity:1"
+         d="M 8.7185878,4.0337352 L -2.2072895,0.016013256 L 8.7185884,-4.0017078 C 6.9730900,-1.6296469 6.9831476,1.6157441 8.7185878,4.0337352 z "
+         transform="scale(1.1) rotate(180) translate(1,0)" />
+    </marker>
+    <marker
+       inkscape:isstock="true"
+       style="overflow:visible;"
+       id="marker32792"
+       refX="0.0"
+       refY="0.0"
+       orient="auto"
+       inkscape:stockid="Arrow2Lend">
+      <path
+         transform="scale(1.1) rotate(180) translate(1,0)"
+         d="M 8.7185878,4.0337352 L -2.2072895,0.016013256 L 8.7185884,-4.0017078 C 6.9730900,-1.6296469 6.9831476,1.6157441 8.7185878,4.0337352 z "
+         style="fill-rule:evenodd;stroke-width:0.625;stroke-linejoin:round;stroke:#000000;stroke-opacity:1;fill:#000000;fill-opacity:1"
+         id="path32790" />
+    </marker>
+    <marker
+       inkscape:stockid="Arrow2Lend"
+       orient="auto"
+       refY="0.0"
+       refX="0.0"
+       id="marker16375"
+       style="overflow:visible;"
+       inkscape:isstock="true">
+      <path
+         id="path16373"
+         style="fill-rule:evenodd;stroke-width:0.625;stroke-linejoin:round;stroke:#000000;stroke-opacity:1;fill:#000000;fill-opacity:1"
+         d="M 8.7185878,4.0337352 L -2.2072895,0.016013256 L 8.7185884,-4.0017078 C 6.9730900,-1.6296469 6.9831476,1.6157441 8.7185878,4.0337352 z "
+         transform="scale(1.1) rotate(180) translate(1,0)" />
+    </marker>
+    <marker
+       inkscape:stockid="Arrow2Lend"
+       orient="auto"
+       refY="0.0"
+       refX="0.0"
+       id="marker15633"
+       style="overflow:visible;"
+       inkscape:isstock="true">
+      <path
+         id="path15631"
+         style="fill-rule:evenodd;stroke-width:0.625;stroke-linejoin:round;stroke:#000000;stroke-opacity:1;fill:#000000;fill-opacity:1"
+         d="M 8.7185878,4.0337352 L -2.2072895,0.016013256 L 8.7185884,-4.0017078 C 6.9730900,-1.6296469 6.9831476,1.6157441 8.7185878,4.0337352 z "
+         transform="scale(1.1) rotate(180) translate(1,0)" />
+    </marker>
+    <marker
+       inkscape:stockid="Arrow2Lend"
+       orient="auto"
+       refY="0.0"
+       refX="0.0"
+       id="marker15037"
+       style="overflow:visible;"
+       inkscape:isstock="true">
+      <path
+         id="path15035"
+         style="fill-rule:evenodd;stroke-width:0.625;stroke-linejoin:round;stroke:#000000;stroke-opacity:1;fill:#000000;fill-opacity:1"
+         d="M 8.7185878,4.0337352 L -2.2072895,0.016013256 L 8.7185884,-4.0017078 C 6.9730900,-1.6296469 6.9831476,1.6157441 8.7185878,4.0337352 z "
+         transform="scale(1.1) rotate(180) translate(1,0)" />
+    </marker>
+    <marker
+       inkscape:stockid="Arrow2Lend"
+       orient="auto"
+       refY="0.0"
+       refX="0.0"
+       id="marker14003"
+       style="overflow:visible;"
+       inkscape:isstock="true">
+      <path
+         id="path14001"
+         style="fill-rule:evenodd;stroke-width:0.625;stroke-linejoin:round;stroke:#000000;stroke-opacity:1;fill:#000000;fill-opacity:1"
+         d="M 8.7185878,4.0337352 L -2.2072895,0.016013256 L 8.7185884,-4.0017078 C 6.9730900,-1.6296469 6.9831476,1.6157441 8.7185878,4.0337352 z "
+         transform="scale(1.1) rotate(180) translate(1,0)" />
+    </marker>
+    <marker
+       inkscape:stockid="Arrow2Lend"
+       orient="auto"
+       refY="0.0"
+       refX="0.0"
+       id="marker12239"
+       style="overflow:visible;"
+       inkscape:isstock="true">
+      <path
+         id="path12237"
+         style="fill-rule:evenodd;stroke-width:0.625;stroke-linejoin:round;stroke:#000000;stroke-opacity:1;fill:#000000;fill-opacity:1"
+         d="M 8.7185878,4.0337352 L -2.2072895,0.016013256 L 8.7185884,-4.0017078 C 6.9730900,-1.6296469 6.9831476,1.6157441 8.7185878,4.0337352 z "
+         transform="scale(1.1) rotate(180) translate(1,0)" />
+    </marker>
+    <marker
+       inkscape:stockid="Arrow2Lend"
+       orient="auto"
+       refY="0.0"
+       refX="0.0"
+       id="marker11643"
+       style="overflow:visible;"
+       inkscape:isstock="true">
+      <path
+         id="path11641"
+         style="fill-rule:evenodd;stroke-width:0.625;stroke-linejoin:round;stroke:#000000;stroke-opacity:1;fill:#000000;fill-opacity:1"
+         d="M 8.7185878,4.0337352 L -2.2072895,0.016013256 L 8.7185884,-4.0017078 C 6.9730900,-1.6296469 6.9831476,1.6157441 8.7185878,4.0337352 z "
+         transform="scale(1.1) rotate(180) translate(1,0)" />
+    </marker>
+    <marker
+       inkscape:stockid="Arrow2Lend"
+       orient="auto"
+       refY="0.0"
+       refX="0.0"
+       id="marker11193"
+       style="overflow:visible;"
+       inkscape:isstock="true">
+      <path
+         id="path11191"
+         style="fill-rule:evenodd;stroke-width:0.625;stroke-linejoin:round;stroke:#000000;stroke-opacity:1;fill:#000000;fill-opacity:1"
+         d="M 8.7185878,4.0337352 L -2.2072895,0.016013256 L 8.7185884,-4.0017078 C 6.9730900,-1.6296469 6.9831476,1.6157441 8.7185878,4.0337352 z "
+         transform="scale(1.1) rotate(180) translate(1,0)" />
+    </marker>
+    <marker
+       inkscape:stockid="Arrow2Lend"
+       orient="auto"
+       refY="0.0"
+       refX="0.0"
+       id="marker9721"
+       style="overflow:visible;"
+       inkscape:isstock="true">
+      <path
+         id="path9719"
+         style="fill-rule:evenodd;stroke-width:0.625;stroke-linejoin:round;stroke:#000000;stroke-opacity:1;fill:#000000;fill-opacity:1"
+         d="M 8.7185878,4.0337352 L -2.2072895,0.016013256 L 8.7185884,-4.0017078 C 6.9730900,-1.6296469 6.9831476,1.6157441 8.7185878,4.0337352 z "
+         transform="scale(1.1) rotate(180) translate(1,0)" />
+    </marker>
+    <marker
+       inkscape:stockid="Arrow2Lend"
+       orient="auto"
+       refY="0.0"
+       refX="0.0"
+       id="marker6789"
+       style="overflow:visible;"
+       inkscape:isstock="true">
+      <path
+         id="path6787"
+         style="fill-rule:evenodd;stroke-width:0.625;stroke-linejoin:round;stroke:#000000;stroke-opacity:1;fill:#000000;fill-opacity:1"
+         d="M 8.7185878,4.0337352 L -2.2072895,0.016013256 L 8.7185884,-4.0017078 C 6.9730900,-1.6296469 6.9831476,1.6157441 8.7185878,4.0337352 z "
+         transform="scale(1.1) rotate(180) translate(1,0)" />
+    </marker>
+    <marker
+       inkscape:isstock="true"
+       style="overflow:visible"
+       id="marker26505"
+       refX="0.0"
+       refY="0.0"
+       orient="auto"
+       inkscape:stockid="Arrow2Lstart">
+      <path
+         transform="scale(1.1) translate(1,0)"
+         d="M 8.7185878,4.0337352 L -2.2072895,0.016013256 L 8.7185884,-4.0017078 C 6.9730900,-1.6296469 6.9831476,1.6157441 8.7185878,4.0337352 z "
+         style="fill-rule:evenodd;stroke-width:0.625;stroke-linejoin:round;stroke:#000000;stroke-opacity:1;fill:#000000;fill-opacity:1"
+         id="path26503" />
+    </marker>
+    <marker
+       inkscape:isstock="true"
+       style="overflow:visible"
+       id="marker25907"
+       refX="0.0"
+       refY="0.0"
+       orient="auto"
+       inkscape:stockid="Arrow2Lstart">
+      <path
+         transform="scale(1.1) translate(1,0)"
+         d="M 8.7185878,4.0337352 L -2.2072895,0.016013256 L 8.7185884,-4.0017078 C 6.9730900,-1.6296469 6.9831476,1.6157441 8.7185878,4.0337352 z "
+         style="fill-rule:evenodd;stroke-width:0.625;stroke-linejoin:round;stroke:#000000;stroke-opacity:1;fill:#000000;fill-opacity:1"
+         id="path25905" />
+    </marker>
+    <marker
+       inkscape:isstock="true"
+       style="overflow:visible;"
+       id="marker23218"
+       refX="0.0"
+       refY="0.0"
+       orient="auto"
+       inkscape:stockid="Arrow2Lend">
+      <path
+         transform="scale(1.1) rotate(180) translate(1,0)"
+         d="M 8.7185878,4.0337352 L -2.2072895,0.016013256 L 8.7185884,-4.0017078 C 6.9730900,-1.6296469 6.9831476,1.6157441 8.7185878,4.0337352 z "
+         style="fill-rule:evenodd;stroke-width:0.625;stroke-linejoin:round;stroke:#000000;stroke-opacity:1;fill:#000000;fill-opacity:1"
+         id="path23216" />
+    </marker>
+    <marker
+       inkscape:stockid="Arrow2Lend"
+       orient="auto"
+       refY="0.0"
+       refX="0.0"
+       id="marker19632"
+       style="overflow:visible;"
+       inkscape:isstock="true">
+      <path
+         id="path19630"
+         style="fill-rule:evenodd;stroke-width:0.625;stroke-linejoin:round;stroke:#000000;stroke-opacity:1;fill:#000000;fill-opacity:1"
+         d="M 8.7185878,4.0337352 L -2.2072895,0.016013256 L 8.7185884,-4.0017078 C 6.9730900,-1.6296469 6.9831476,1.6157441 8.7185878,4.0337352 z "
+         transform="scale(1.1) rotate(180) translate(1,0)" />
+    </marker>
+    <marker
+       inkscape:stockid="Arrow2Lend"
+       orient="auto"
+       refY="0.0"
+       refX="0.0"
+       id="marker18406"
+       style="overflow:visible;"
+       inkscape:isstock="true"
+       inkscape:collect="always">
+      <path
+         id="path18404"
+         style="fill-rule:evenodd;stroke-width:0.625;stroke-linejoin:round;stroke:#000000;stroke-opacity:1;fill:#000000;fill-opacity:1"
+         d="M 8.7185878,4.0337352 L -2.2072895,0.016013256 L 8.7185884,-4.0017078 C 6.9730900,-1.6296469 6.9831476,1.6157441 8.7185878,4.0337352 z "
+         transform="scale(1.1) rotate(180) translate(1,0)" />
+    </marker>
+    <marker
+       inkscape:isstock="true"
+       style="overflow:visible;"
+       id="marker17872"
+       refX="0.0"
+       refY="0.0"
+       orient="auto"
+       inkscape:stockid="Arrow2Lend"
+       inkscape:collect="always">
+      <path
+         transform="scale(1.1) rotate(180) translate(1,0)"
+         d="M 8.7185878,4.0337352 L -2.2072895,0.016013256 L 8.7185884,-4.0017078 C 6.9730900,-1.6296469 6.9831476,1.6157441 8.7185878,4.0337352 z "
+         style="fill-rule:evenodd;stroke-width:0.625;stroke-linejoin:round;stroke:#000000;stroke-opacity:1;fill:#000000;fill-opacity:1"
+         id="path17870" />
+    </marker>
+    <marker
+       inkscape:stockid="Arrow2Lend"
+       orient="auto"
+       refY="0.0"
+       refX="0.0"
+       id="marker17252"
+       style="overflow:visible;"
+       inkscape:isstock="true">
+      <path
+         id="path17250"
+         style="fill-rule:evenodd;stroke-width:0.625;stroke-linejoin:round;stroke:#000000;stroke-opacity:1;fill:#000000;fill-opacity:1"
+         d="M 8.7185878,4.0337352 L -2.2072895,0.016013256 L 8.7185884,-4.0017078 C 6.9730900,-1.6296469 6.9831476,1.6157441 8.7185878,4.0337352 z "
+         transform="scale(1.1) rotate(180) translate(1,0)" />
+    </marker>
+    <marker
+       inkscape:stockid="Arrow2Lend"
+       orient="auto"
+       refY="0.0"
+       refX="0.0"
+       id="marker16657"
+       style="overflow:visible;"
+       inkscape:isstock="true"
+       inkscape:collect="always">
+      <path
+         id="path16655"
+         style="fill-rule:evenodd;stroke-width:0.625;stroke-linejoin:round;stroke:#000000;stroke-opacity:1;fill:#000000;fill-opacity:1"
+         d="M 8.7185878,4.0337352 L -2.2072895,0.016013256 L 8.7185884,-4.0017078 C 6.9730900,-1.6296469 6.9831476,1.6157441 8.7185878,4.0337352 z "
+         transform="scale(1.1) rotate(180) translate(1,0)" />
+    </marker>
+    <marker
+       inkscape:isstock="true"
+       style="overflow:visible;"
+       id="marker6296"
+       refX="0.0"
+       refY="0.0"
+       orient="auto"
+       inkscape:stockid="Arrow2Lend"
+       inkscape:collect="always">
+      <path
+         transform="scale(1.1) rotate(180) translate(1,0)"
+         d="M 8.7185878,4.0337352 L -2.2072895,0.016013256 L 8.7185884,-4.0017078 C 6.9730900,-1.6296469 6.9831476,1.6157441 8.7185878,4.0337352 z "
+         style="fill-rule:evenodd;stroke-width:0.625;stroke-linejoin:round;stroke:#000000;stroke-opacity:1;fill:#000000;fill-opacity:1"
+         id="path6294" />
+    </marker>
+    <marker
+       inkscape:stockid="Arrow2Lend"
+       orient="auto"
+       refY="0.0"
+       refX="0.0"
+       id="marker1654"
+       style="overflow:visible;"
+       inkscape:isstock="true"
+       inkscape:collect="always">
+      <path
+         id="path1652"
+         style="fill-rule:evenodd;stroke-width:0.625;stroke-linejoin:round;stroke:#000000;stroke-opacity:1;fill:#000000;fill-opacity:1"
+         d="M 8.7185878,4.0337352 L -2.2072895,0.016013256 L 8.7185884,-4.0017078 C 6.9730900,-1.6296469 6.9831476,1.6157441 8.7185878,4.0337352 z "
+         transform="scale(1.1) rotate(180) translate(1,0)" />
+    </marker>
+    <marker
+       inkscape:stockid="SquareL"
+       orient="auto"
+       refY="0.0"
+       refX="0.0"
+       id="SquareL"
+       style="overflow:visible"
+       inkscape:isstock="true">
+      <path
+         id="path1432"
+         d="M -5.0,-5.0 L -5.0,5.0 L 5.0,5.0 L 5.0,-5.0 L -5.0,-5.0 z "
+         style="fill-rule:evenodd;stroke:#000000;stroke-width:1pt;stroke-opacity:1;fill:#000000;fill-opacity:1"
+         transform="scale(0.8)" />
+    </marker>
+    <marker
+       inkscape:stockid="Arrow2Lstart"
+       orient="auto"
+       refY="0.0"
+       refX="0.0"
+       id="marker9343"
+       style="overflow:visible"
+       inkscape:isstock="true"
+       inkscape:collect="always">
+      <path
+         id="path9341"
+         style="fill-rule:evenodd;stroke-width:0.625;stroke-linejoin:round;stroke:#000000;stroke-opacity:1;fill:#000000;fill-opacity:1"
+         d="M 8.7185878,4.0337352 L -2.2072895,0.016013256 L 8.7185884,-4.0017078 C 6.9730900,-1.6296469 6.9831476,1.6157441 8.7185878,4.0337352 z "
+         transform="scale(1.1) translate(1,0)" />
+    </marker>
+    <marker
+       inkscape:stockid="Arrow2Lstart"
+       orient="auto"
+       refY="0.0"
+       refX="0.0"
+       id="Arrow2Lstart"
+       style="overflow:visible"
+       inkscape:isstock="true">
+      <path
+         id="path1359"
+         style="fill-rule:evenodd;stroke-width:0.625;stroke-linejoin:round;stroke:#000000;stroke-opacity:1;fill:#000000;fill-opacity:1"
+         d="M 8.7185878,4.0337352 L -2.2072895,0.016013256 L 8.7185884,-4.0017078 C 6.9730900,-1.6296469 6.9831476,1.6157441 8.7185878,4.0337352 z "
+         transform="scale(1.1) translate(1,0)" />
+    </marker>
+    <marker
+       inkscape:isstock="true"
+       style="overflow:visible"
+       id="marker4626"
+       refX="0"
+       refY="0"
+       orient="auto"
+       inkscape:stockid="Arrow2Lend">
+      <path
+         inkscape:connector-curvature="0"
+         transform="matrix(-1.1,0,0,-1.1,-1.1,0)"
+         d="M 8.7185878,4.0337352 -2.2072895,0.01601326 8.7185884,-4.0017078 c -1.7454984,2.3720609 -1.7354408,5.6174519 -6e-7,8.035443 z"
+         style="fill:#000000;fill-opacity:1;fill-rule:evenodd;stroke:#000000;stroke-width:0.625;stroke-linejoin:round;stroke-opacity:1"
+         id="path4624" />
+    </marker>
+    <marker
+       inkscape:isstock="true"
+       style="overflow:visible"
+       id="marker3618"
+       refX="0"
+       refY="0"
+       orient="auto"
+       inkscape:stockid="Arrow2Lend">
+      <path
+         inkscape:connector-curvature="0"
+         transform="matrix(-1.1,0,0,-1.1,-1.1,0)"
+         d="M 8.7185878,4.0337352 -2.2072895,0.01601326 8.7185884,-4.0017078 c -1.7454984,2.3720609 -1.7354408,5.6174519 -6e-7,8.035443 z"
+         style="fill:#000000;fill-opacity:1;fill-rule:evenodd;stroke:#000000;stroke-width:0.625;stroke-linejoin:round;stroke-opacity:1"
+         id="path3616" />
+    </marker>
+    <marker
+       inkscape:isstock="true"
+       style="overflow:visible"
+       id="marker1780"
+       refX="0"
+       refY="0"
+       orient="auto"
+       inkscape:stockid="Arrow2Lend">
+      <path
+         inkscape:connector-curvature="0"
+         transform="matrix(-1.1,0,0,-1.1,-1.1,0)"
+         d="M 8.7185878,4.0337352 -2.2072895,0.01601326 8.7185884,-4.0017078 c -1.7454984,2.3720609 -1.7354408,5.6174519 -6e-7,8.035443 z"
+         style="fill:#000000;fill-opacity:1;fill-rule:evenodd;stroke:#000000;stroke-width:0.625;stroke-linejoin:round;stroke-opacity:1"
+         id="path1778" />
+    </marker>
+    <marker
+       inkscape:stockid="Arrow2Lend"
+       orient="auto"
+       refY="0.0"
+       refX="0.0"
+       id="marker1604"
+       style="overflow:visible;"
+       inkscape:isstock="true">
+      <path
+         id="path1362"
+         style="fill-rule:evenodd;stroke-width:0.625;stroke-linejoin:round;stroke:#000000;stroke-opacity:1;fill:#000000;fill-opacity:1"
+         d="M 8.7185878,4.0337352 L -2.2072895,0.016013256 L 8.7185884,-4.0017078 C 6.9730900,-1.6296469 6.9831476,1.6157441 8.7185878,4.0337352 z "
+         transform="scale(1.1) rotate(180) translate(1,0)" />
+    </marker>
+    <marker
+       inkscape:stockid="Arrow2Lend"
+       orient="auto"
+       refY="0"
+       refX="0"
+       id="marker6489"
+       style="overflow:visible"
+       inkscape:isstock="true">
+      <path
+         inkscape:connector-curvature="0"
+         id="path6487"
+         style="fill:#000000;fill-opacity:1;fill-rule:evenodd;stroke:#000000;stroke-width:0.625;stroke-linejoin:round;stroke-opacity:1"
+         d="M 8.7185878,4.0337352 -2.2072895,0.01601326 8.7185884,-4.0017078 c -1.7454984,2.3720609 -1.7354408,5.6174519 -6e-7,8.035443 z"
+         transform="matrix(-1.1,0,0,-1.1,-1.1,0)" />
+    </marker>
+    <marker
+       inkscape:stockid="Arrow2Lend"
+       orient="auto"
+       refY="0"
+       refX="0"
+       id="marker8593"
+       style="overflow:visible"
+       inkscape:isstock="true">
+      <path
+         inkscape:connector-curvature="0"
+         id="path8591"
+         style="fill:#000000;fill-opacity:1;fill-rule:evenodd;stroke:#000000;stroke-width:0.625;stroke-linejoin:round;stroke-opacity:1"
+         d="M 8.7185878,4.0337352 -2.2072895,0.01601326 8.7185884,-4.0017078 c -1.7454984,2.3720609 -1.7354408,5.6174519 -6e-7,8.035443 z"
+         transform="matrix(-1.1,0,0,-1.1,-1.1,0)" />
+    </marker>
+    <marker
+       inkscape:stockid="Arrow2Lend"
+       orient="auto"
+       refY="0"
+       refX="0"
+       id="marker8169"
+       style="overflow:visible"
+       inkscape:isstock="true">
+      <path
+         id="path8167"
+         style="fill:#000000;fill-opacity:1;fill-rule:evenodd;stroke:#000000;stroke-width:0.625;stroke-linejoin:round;stroke-opacity:1"
+         d="M 8.7185878,4.0337352 -2.2072895,0.01601326 8.7185884,-4.0017078 c -1.7454984,2.3720609 -1.7354408,5.6174519 -6e-7,8.035443 z"
+         transform="matrix(-1.1,0,0,-1.1,-1.1,0)"
+         inkscape:connector-curvature="0" />
+    </marker>
+    <marker
+       inkscape:stockid="Arrow1Lend"
+       orient="auto"
+       refY="0"
+       refX="0"
+       id="marker7739"
+       style="overflow:visible"
+       inkscape:isstock="true">
+      <path
+         id="path7737"
+         d="M 0,0 5,-5 -12.5,0 5,5 Z"
+         style="fill:#000000;fill-opacity:1;fill-rule:evenodd;stroke:#000000;stroke-width:1.00000003pt;stroke-opacity:1"
+         transform="matrix(-0.8,0,0,-0.8,-10,0)"
+         inkscape:connector-curvature="0" />
+    </marker>
+    <marker
+       inkscape:stockid="Arrow1Lend"
+       orient="auto"
+       refY="0"
+       refX="0"
+       id="Arrow1Lend"
+       style="overflow:visible"
+       inkscape:isstock="true">
+      <path
+         id="path5589"
+         d="M 0,0 5,-5 -12.5,0 5,5 Z"
+         style="fill:#000000;fill-opacity:1;fill-rule:evenodd;stroke:#000000;stroke-width:1.00000003pt;stroke-opacity:1"
+         transform="matrix(-0.8,0,0,-0.8,-10,0)"
+         inkscape:connector-curvature="0" />
+    </marker>
+    <marker
+       inkscape:isstock="true"
+       style="overflow:visible"
+       id="marker6959"
+       refX="0"
+       refY="0"
+       orient="auto"
+       inkscape:stockid="Arrow2Lend">
+      <path
+         inkscape:connector-curvature="0"
+         transform="matrix(-1.1,0,0,-1.1,-1.1,0)"
+         d="M 8.7185878,4.0337352 -2.2072895,0.01601326 8.7185884,-4.0017078 c -1.7454984,2.3720609 -1.7354408,5.6174519 -6e-7,8.035443 z"
+         style="fill:#000000;fill-opacity:1;fill-rule:evenodd;stroke:#000000;stroke-width:0.625;stroke-linejoin:round;stroke-opacity:1"
+         id="path6957" />
+    </marker>
+    <marker
+       inkscape:isstock="true"
+       style="overflow:visible"
+       id="marker6583"
+       refX="0"
+       refY="0"
+       orient="auto"
+       inkscape:stockid="Arrow2Lend">
+      <path
+         inkscape:connector-curvature="0"
+         transform="matrix(-1.1,0,0,-1.1,-1.1,0)"
+         d="M 8.7185878,4.0337352 -2.2072895,0.01601326 8.7185884,-4.0017078 c -1.7454984,2.3720609 -1.7354408,5.6174519 -6e-7,8.035443 z"
+         style="fill:#000000;fill-opacity:1;fill-rule:evenodd;stroke:#000000;stroke-width:0.625;stroke-linejoin:round;stroke-opacity:1"
+         id="path6581" />
+    </marker>
+    <marker
+       inkscape:isstock="true"
+       style="overflow:visible"
+       id="marker6219"
+       refX="0"
+       refY="0"
+       orient="auto"
+       inkscape:stockid="Arrow2Lend">
+      <path
+         inkscape:connector-curvature="0"
+         transform="matrix(-1.1,0,0,-1.1,-1.1,0)"
+         d="M 8.7185878,4.0337352 -2.2072895,0.01601326 8.7185884,-4.0017078 c -1.7454984,2.3720609 -1.7354408,5.6174519 -6e-7,8.035443 z"
+         style="fill:#000000;fill-opacity:1;fill-rule:evenodd;stroke:#000000;stroke-width:0.625;stroke-linejoin:round;stroke-opacity:1"
+         id="path6217" />
+    </marker>
+    <marker
+       inkscape:stockid="Arrow1Lstart"
+       orient="auto"
+       refY="0"
+       refX="0"
+       id="marker5849"
+       style="overflow:visible"
+       inkscape:isstock="true">
+      <path
+         id="path5586"
+         d="M 0,0 5,-5 -12.5,0 5,5 Z"
+         style="fill:#000000;fill-opacity:1;fill-rule:evenodd;stroke:#000000;stroke-width:1.00000003pt;stroke-opacity:1"
+         transform="matrix(0.8,0,0,0.8,10,0)"
+         inkscape:connector-curvature="0" />
+    </marker>
+    <marker
+       inkscape:stockid="Arrow2Lend"
+       orient="auto"
+       refY="0"
+       refX="0"
+       id="marker2218"
+       style="overflow:visible"
+       inkscape:isstock="true">
+      <path
+         id="path2216"
+         style="fill:#000000;fill-opacity:1;fill-rule:evenodd;stroke:#000000;stroke-width:0.625;stroke-linejoin:round;stroke-opacity:1"
+         d="M 8.7185878,4.0337352 -2.2072895,0.01601326 8.7185884,-4.0017078 c -1.7454984,2.3720609 -1.7354408,5.6174519 -6e-7,8.035443 z"
+         transform="matrix(-1.1,0,0,-1.1,-1.1,0)"
+         inkscape:connector-curvature="0" />
+    </marker>
+    <marker
+       inkscape:stockid="Arrow2Lend"
+       orient="auto"
+       refY="0"
+       refX="0"
+       id="marker1864"
+       style="overflow:visible"
+       inkscape:isstock="true">
+      <path
+         id="path1862"
+         style="fill:#000000;fill-opacity:1;fill-rule:evenodd;stroke:#000000;stroke-width:0.625;stroke-linejoin:round;stroke-opacity:1"
+         d="M 8.7185878,4.0337352 -2.2072895,0.01601326 8.7185884,-4.0017078 c -1.7454984,2.3720609 -1.7354408,5.6174519 -6e-7,8.035443 z"
+         transform="matrix(-1.1,0,0,-1.1,-1.1,0)"
+         inkscape:connector-curvature="0" />
+    </marker>
+    <marker
+       inkscape:stockid="Arrow2Lend"
+       orient="auto"
+       refY="0"
+       refX="0"
+       id="marker1516"
+       style="overflow:visible"
+       inkscape:isstock="true">
+      <path
+         id="path1514"
+         style="fill:#000000;fill-opacity:1;fill-rule:evenodd;stroke:#000000;stroke-width:0.625;stroke-linejoin:round;stroke-opacity:1"
+         d="M 8.7185878,4.0337352 -2.2072895,0.01601326 8.7185884,-4.0017078 c -1.7454984,2.3720609 -1.7354408,5.6174519 -6e-7,8.035443 z"
+         transform="matrix(-1.1,0,0,-1.1,-1.1,0)"
+         inkscape:connector-curvature="0" />
+    </marker>
+    <marker
+       inkscape:stockid="Arrow2Lend"
+       orient="auto"
+       refY="0"
+       refX="0"
+       id="marker1632"
+       style="overflow:visible"
+       inkscape:isstock="true">
+      <path
+         id="path1630"
+         style="fill:#000000;fill-opacity:1;fill-rule:evenodd;stroke:#000000;stroke-width:0.625;stroke-linejoin:round;stroke-opacity:1"
+         d="M 8.7185878,4.0337352 -2.2072895,0.01601326 8.7185884,-4.0017078 c -1.7454984,2.3720609 -1.7354408,5.6174519 -6e-7,8.035443 z"
+         transform="matrix(-1.1,0,0,-1.1,-1.1,0)"
+         inkscape:connector-curvature="0" />
+    </marker>
+    <marker
+       inkscape:stockid="Arrow2Lend"
+       orient="auto"
+       refY="0"
+       refX="0"
+       id="marker1626"
+       style="overflow:visible"
+       inkscape:isstock="true">
+      <path
+         id="path1624"
+         style="fill:#000000;fill-opacity:1;fill-rule:evenodd;stroke:#000000;stroke-width:0.625;stroke-linejoin:round;stroke-opacity:1"
+         d="M 8.7185878,4.0337352 -2.2072895,0.01601326 8.7185884,-4.0017078 c -1.7454984,2.3720609 -1.7354408,5.6174519 -6e-7,8.035443 z"
+         transform="matrix(-1.1,0,0,-1.1,-1.1,0)"
+         inkscape:connector-curvature="0" />
+    </marker>
+    <marker
+       inkscape:stockid="Arrow2Lend"
+       orient="auto"
+       refY="0"
+       refX="0"
+       id="marker1620"
+       style="overflow:visible"
+       inkscape:isstock="true">
+      <path
+         id="path1618"
+         style="fill:#000000;fill-opacity:1;fill-rule:evenodd;stroke:#000000;stroke-width:0.625;stroke-linejoin:round;stroke-opacity:1"
+         d="M 8.7185878,4.0337352 -2.2072895,0.01601326 8.7185884,-4.0017078 c -1.7454984,2.3720609 -1.7354408,5.6174519 -6e-7,8.035443 z"
+         transform="matrix(-1.1,0,0,-1.1,-1.1,0)"
+         inkscape:connector-curvature="0" />
+    </marker>
+    <marker
+       inkscape:stockid="Arrow2Lend"
+       orient="auto"
+       refY="0"
+       refX="0"
+       id="marker1614"
+       style="overflow:visible"
+       inkscape:isstock="true">
+      <path
+         id="path1612"
+         style="fill:#000000;fill-opacity:1;fill-rule:evenodd;stroke:#000000;stroke-width:0.625;stroke-linejoin:round;stroke-opacity:1"
+         d="M 8.7185878,4.0337352 -2.2072895,0.01601326 8.7185884,-4.0017078 c -1.7454984,2.3720609 -1.7354408,5.6174519 -6e-7,8.035443 z"
+         transform="matrix(-1.1,0,0,-1.1,-1.1,0)"
+         inkscape:connector-curvature="0" />
+    </marker>
+    <marker
+       inkscape:stockid="Arrow2Lend"
+       orient="auto"
+       refY="0"
+       refX="0"
+       id="marker1608"
+       style="overflow:visible"
+       inkscape:isstock="true">
+      <path
+         id="path1606"
+         style="fill:#000000;fill-opacity:1;fill-rule:evenodd;stroke:#000000;stroke-width:0.625;stroke-linejoin:round;stroke-opacity:1"
+         d="M 8.7185878,4.0337352 -2.2072895,0.01601326 8.7185884,-4.0017078 c -1.7454984,2.3720609 -1.7354408,5.6174519 -6e-7,8.035443 z"
+         transform="matrix(-1.1,0,0,-1.1,-1.1,0)"
+         inkscape:connector-curvature="0" />
+    </marker>
+    <marker
+       inkscape:stockid="Arrow2Lend"
+       orient="auto"
+       refY="0"
+       refX="0"
+       id="marker1560"
+       style="overflow:visible"
+       inkscape:isstock="true">
+      <path
+         id="path1558"
+         style="fill:#000000;fill-opacity:1;fill-rule:evenodd;stroke:#000000;stroke-width:0.625;stroke-linejoin:round;stroke-opacity:1"
+         d="M 8.7185878,4.0337352 -2.2072895,0.01601326 8.7185884,-4.0017078 c -1.7454984,2.3720609 -1.7354408,5.6174519 -6e-7,8.035443 z"
+         transform="matrix(-1.1,0,0,-1.1,-1.1,0)"
+         inkscape:connector-curvature="0" />
+    </marker>
+    <marker
+       inkscape:stockid="Arrow2Lend"
+       orient="auto"
+       refY="0"
+       refX="0"
+       id="marker1552"
+       style="overflow:visible"
+       inkscape:isstock="true">
+      <path
+         id="path1550"
+         style="fill:#000000;fill-opacity:1;fill-rule:evenodd;stroke:#000000;stroke-width:0.625;stroke-linejoin:round;stroke-opacity:1"
+         d="M 8.7185878,4.0337352 -2.2072895,0.01601326 8.7185884,-4.0017078 c -1.7454984,2.3720609 -1.7354408,5.6174519 -6e-7,8.035443 z"
+         transform="matrix(-1.1,0,0,-1.1,-1.1,0)"
+         inkscape:connector-curvature="0" />
+    </marker>
+    <marker
+       inkscape:isstock="true"
+       style="overflow:visible"
+       id="marker4611"
+       refX="0"
+       refY="0"
+       orient="auto"
+       inkscape:stockid="Arrow2Lend">
+      <path
+         transform="matrix(-1.1,0,0,-1.1,-1.1,0)"
+         d="M 8.7185878,4.0337352 -2.2072895,0.01601326 8.7185884,-4.0017078 c -1.7454984,2.3720609 -1.7354408,5.6174519 -6e-7,8.035443 z"
+         style="fill:#000000;fill-opacity:1;fill-rule:evenodd;stroke:#000000;stroke-width:0.625;stroke-linejoin:round;stroke-opacity:1"
+         id="path4609"
+         inkscape:connector-curvature="0" />
+    </marker>
+    <marker
+       inkscape:isstock="true"
+       style="overflow:visible"
+       id="marker24654"
+       refX="0"
+       refY="0"
+       orient="auto"
+       inkscape:stockid="Arrow2Lstart">
+      <path
+         transform="matrix(1.1,0,0,1.1,1.1,0)"
+         d="M 8.7185878,4.0337352 -2.2072895,0.01601326 8.7185884,-4.0017078 c -1.7454984,2.3720609 -1.7354408,5.6174519 -6e-7,8.035443 z"
+         style="fill:#000000;fill-opacity:1;fill-rule:evenodd;stroke:#000000;stroke-width:0.625;stroke-linejoin:round;stroke-opacity:1"
+         id="path24652"
+         inkscape:connector-curvature="0" />
+    </marker>
+    <marker
+       inkscape:isstock="true"
+       style="overflow:visible"
+       id="marker23978"
+       refX="0"
+       refY="0"
+       orient="auto"
+       inkscape:stockid="Arrow2Lend">
+      <path
+         transform="matrix(-1.1,0,0,-1.1,-1.1,0)"
+         d="M 8.7185878,4.0337352 -2.2072895,0.01601326 8.7185884,-4.0017078 c -1.7454984,2.3720609 -1.7354408,5.6174519 -6e-7,8.035443 z"
+         style="fill:#000000;fill-opacity:1;fill-rule:evenodd;stroke:#000000;stroke-width:0.625;stroke-linejoin:round;stroke-opacity:1"
+         id="path23976"
+         inkscape:connector-curvature="0" />
+    </marker>
+    <marker
+       inkscape:isstock="true"
+       style="overflow:visible"
+       id="marker23136"
+       refX="0"
+       refY="0"
+       orient="auto"
+       inkscape:stockid="Arrow2Lend">
+      <path
+         transform="matrix(-1.1,0,0,-1.1,-1.1,0)"
+         d="M 8.7185878,4.0337352 -2.2072895,0.01601326 8.7185884,-4.0017078 c -1.7454984,2.3720609 -1.7354408,5.6174519 -6e-7,8.035443 z"
+         style="fill:#000000;fill-opacity:1;fill-rule:evenodd;stroke:#000000;stroke-width:0.625;stroke-linejoin:round;stroke-opacity:1"
+         id="path23134"
+         inkscape:connector-curvature="0" />
+    </marker>
+    <marker
+       inkscape:isstock="true"
+       style="overflow:visible"
+       id="marker22960"
+       refX="0"
+       refY="0"
+       orient="auto"
+       inkscape:stockid="Arrow2Lstart">
+      <path
+         transform="matrix(1.1,0,0,1.1,1.1,0)"
+         d="M 8.7185878,4.0337352 -2.2072895,0.01601326 8.7185884,-4.0017078 c -1.7454984,2.3720609 -1.7354408,5.6174519 -6e-7,8.035443 z"
+         style="fill:#000000;fill-opacity:1;fill-rule:evenodd;stroke:#000000;stroke-width:0.625;stroke-linejoin:round;stroke-opacity:1"
+         id="path22958"
+         inkscape:connector-curvature="0" />
+    </marker>
+    <marker
+       inkscape:isstock="true"
+       style="overflow:visible"
+       id="marker14793"
+       refX="0"
+       refY="0"
+       orient="auto"
+       inkscape:stockid="Arrow2Lend">
+      <path
+         transform="matrix(-1.1,0,0,-1.1,-1.1,0)"
+         d="M 8.7185878,4.0337352 -2.2072895,0.01601326 8.7185884,-4.0017078 c -1.7454984,2.3720609 -1.7354408,5.6174519 -6e-7,8.035443 z"
+         style="fill:#000000;fill-opacity:1;fill-rule:evenodd;stroke:#000000;stroke-width:0.625;stroke-linejoin:round;stroke-opacity:1"
+         id="path14791"
+         inkscape:connector-curvature="0" />
+    </marker>
+    <marker
+       inkscape:isstock="true"
+       style="overflow:visible"
+       id="marker13092"
+       refX="0"
+       refY="0"
+       orient="auto"
+       inkscape:stockid="Arrow2Lend">
+      <path
+         transform="matrix(-1.1,0,0,-1.1,-1.1,0)"
+         d="M 8.7185878,4.0337352 -2.2072895,0.01601326 8.7185884,-4.0017078 c -1.7454984,2.3720609 -1.7354408,5.6174519 -6e-7,8.035443 z"
+         style="fill:#000000;fill-opacity:1;fill-rule:evenodd;stroke:#000000;stroke-width:0.625;stroke-linejoin:round;stroke-opacity:1"
+         id="path13090"
+         inkscape:connector-curvature="0" />
+    </marker>
+    <marker
+       inkscape:isstock="true"
+       style="overflow:visible"
+       id="marker12910"
+       refX="0"
+       refY="0"
+       orient="auto"
+       inkscape:stockid="Arrow2Lend">
+      <path
+         transform="matrix(-1.1,0,0,-1.1,-1.1,0)"
+         d="M 8.7185878,4.0337352 -2.2072895,0.01601326 8.7185884,-4.0017078 c -1.7454984,2.3720609 -1.7354408,5.6174519 -6e-7,8.035443 z"
+         style="fill:#000000;fill-opacity:1;fill-rule:evenodd;stroke:#000000;stroke-width:0.625;stroke-linejoin:round;stroke-opacity:1"
+         id="path12908"
+         inkscape:connector-curvature="0" />
+    </marker>
+    <marker
+       inkscape:isstock="true"
+       style="overflow:visible"
+       id="marker12568"
+       refX="0"
+       refY="0"
+       orient="auto"
+       inkscape:stockid="Arrow2Lend">
+      <path
+         transform="matrix(-1.1,0,0,-1.1,-1.1,0)"
+         d="M 8.7185878,4.0337352 -2.2072895,0.01601326 8.7185884,-4.0017078 c -1.7454984,2.3720609 -1.7354408,5.6174519 -6e-7,8.035443 z"
+         style="fill:#000000;fill-opacity:1;fill-rule:evenodd;stroke:#000000;stroke-width:0.625;stroke-linejoin:round;stroke-opacity:1"
+         id="path12566"
+         inkscape:connector-curvature="0" />
+    </marker>
+    <marker
+       inkscape:isstock="true"
+       style="overflow:visible"
+       id="marker5180"
+       refX="0"
+       refY="0"
+       orient="auto"
+       inkscape:stockid="Arrow1Lend">
+      <path
+         transform="matrix(-0.8,0,0,-0.8,-10,0)"
+         style="fill:#000000;fill-opacity:1;fill-rule:evenodd;stroke:#000000;stroke-width:1.00000003pt;stroke-opacity:1"
+         d="M 0,0 5,-5 -12.5,0 5,5 Z"
+         id="path5178"
+         inkscape:connector-curvature="0" />
+    </marker>
+    <marker
+       inkscape:stockid="Arrow1Lend"
+       orient="auto"
+       refY="0"
+       refX="0"
+       id="marker4816"
+       style="overflow:visible"
+       inkscape:isstock="true">
+      <path
+         id="path4814"
+         d="M 0,0 5,-5 -12.5,0 5,5 Z"
+         style="fill:#000000;fill-opacity:1;fill-rule:evenodd;stroke:#000000;stroke-width:1.00000003pt;stroke-opacity:1"
+         transform="matrix(-0.8,0,0,-0.8,-10,0)"
+         inkscape:connector-curvature="0" />
+    </marker>
+    <marker
+       inkscape:stockid="Arrow2Lend"
+       orient="auto"
+       refY="0"
+       refX="0"
+       id="marker4059"
+       style="overflow:visible"
+       inkscape:isstock="true">
+      <path
+         id="path4057"
+         style="fill:#000000;fill-opacity:1;fill-rule:evenodd;stroke:#000000;stroke-width:0.625;stroke-linejoin:round;stroke-opacity:1"
+         d="M 8.7185878,4.0337352 -2.2072895,0.01601326 8.7185884,-4.0017078 c -1.7454984,2.3720609 -1.7354408,5.6174519 -6e-7,8.035443 z"
+         transform="matrix(-1.1,0,0,-1.1,-1.1,0)"
+         inkscape:connector-curvature="0" />
+    </marker>
+    <marker
+       inkscape:stockid="Arrow1Lstart"
+       orient="auto"
+       refY="0"
+       refX="0"
+       id="Arrow1Lstart"
+       style="overflow:visible"
+       inkscape:isstock="true">
+      <path
+         id="path5293"
+         d="M 0,0 5,-5 -12.5,0 5,5 Z"
+         style="fill-rule:evenodd;stroke:#000000;stroke-width:1.00000003pt"
+         transform="matrix(0.8,0,0,0.8,10,0)"
+         inkscape:connector-curvature="0" />
+    </marker>
+    <marker
+       inkscape:stockid="Arrow2Lend"
+       orient="auto"
+       refY="0"
+       refX="0"
+       id="Arrow2Lend-4"
+       style="overflow:visible"
+       inkscape:isstock="true">
+      <path
+         inkscape:connector-curvature="0"
+         id="path2284-4"
+         style="fill:#000000;fill-opacity:1;fill-rule:evenodd;stroke:#000000;stroke-width:0.625;stroke-linejoin:round;stroke-opacity:1"
+         d="M 8.7185878,4.0337352 -2.2072895,0.01601326 8.7185884,-4.0017078 c -1.7454984,2.3720609 -1.7354408,5.6174519 -6e-7,8.035443 z"
+         transform="matrix(-1.1,0,0,-1.1,-1.1,0)" />
+    </marker>
+    <marker
+       inkscape:stockid="Arrow2Lend"
+       orient="auto"
+       refY="0"
+       refX="0"
+       id="marker4059-8"
+       style="overflow:visible"
+       inkscape:isstock="true">
+      <path
+         inkscape:connector-curvature="0"
+         id="path4057-0"
+         style="fill:#000000;fill-opacity:1;fill-rule:evenodd;stroke:#000000;stroke-width:0.625;stroke-linejoin:round;stroke-opacity:1"
+         d="M 8.7185878,4.0337352 -2.2072895,0.01601326 8.7185884,-4.0017078 c -1.7454984,2.3720609 -1.7354408,5.6174519 -6e-7,8.035443 z"
+         transform="matrix(-1.1,0,0,-1.1,-1.1,0)" />
+    </marker>
+    <marker
+       inkscape:stockid="Arrow2Lend"
+       orient="auto"
+       refY="0"
+       refX="0"
+       id="Arrow2Lend-2"
+       style="overflow:visible"
+       inkscape:isstock="true">
+      <path
+         inkscape:connector-curvature="0"
+         id="path2284-6"
+         style="fill:#000000;fill-opacity:1;fill-rule:evenodd;stroke:#000000;stroke-width:0.625;stroke-linejoin:round;stroke-opacity:1"
+         d="M 8.7185878,4.0337352 -2.2072895,0.01601326 8.7185884,-4.0017078 c -1.7454984,2.3720609 -1.7354408,5.6174519 -6e-7,8.035443 z"
+         transform="matrix(-1.1,0,0,-1.1,-1.1,0)" />
+    </marker>
+    <marker
+       inkscape:stockid="Arrow2Lend"
+       orient="auto"
+       refY="0"
+       refX="0"
+       id="Arrow2Lend-2-4"
+       style="overflow:visible"
+       inkscape:isstock="true">
+      <path
+         inkscape:connector-curvature="0"
+         id="path2284-6-0"
+         style="fill:#000000;fill-opacity:1;fill-rule:evenodd;stroke:#000000;stroke-width:0.625;stroke-linejoin:round;stroke-opacity:1"
+         d="M 8.7185878,4.0337352 -2.2072895,0.01601326 8.7185884,-4.0017078 c -1.7454984,2.3720609 -1.7354408,5.6174519 -6e-7,8.035443 z"
+         transform="matrix(-1.1,0,0,-1.1,-1.1,0)" />
+    </marker>
+    <marker
+       inkscape:stockid="Arrow2Lend"
+       orient="auto"
+       refY="0"
+       refX="0"
+       id="Arrow2Lend-2-2"
+       style="overflow:visible"
+       inkscape:isstock="true">
+      <path
+         inkscape:connector-curvature="0"
+         id="path2284-6-6"
+         style="fill:#000000;fill-opacity:1;fill-rule:evenodd;stroke:#000000;stroke-width:0.625;stroke-linejoin:round;stroke-opacity:1"
+         d="M 8.7185878,4.0337352 -2.2072895,0.01601326 8.7185884,-4.0017078 c -1.7454984,2.3720609 -1.7354408,5.6174519 -6e-7,8.035443 z"
+         transform="matrix(-1.1,0,0,-1.1,-1.1,0)" />
+    </marker>
+    <marker
+       inkscape:stockid="Arrow2Lend"
+       orient="auto"
+       refY="0"
+       refX="0"
+       id="Arrow2Lend-2-6"
+       style="overflow:visible"
+       inkscape:isstock="true">
+      <path
+         inkscape:connector-curvature="0"
+         id="path2284-6-3"
+         style="fill:#000000;fill-opacity:1;fill-rule:evenodd;stroke:#000000;stroke-width:0.625;stroke-linejoin:round;stroke-opacity:1"
+         d="M 8.7185878,4.0337352 -2.2072895,0.01601326 8.7185884,-4.0017078 c -1.7454984,2.3720609 -1.7354408,5.6174519 -6e-7,8.035443 z"
+         transform="matrix(-1.1,0,0,-1.1,-1.1,0)" />
+    </marker>
+    <marker
+       inkscape:stockid="Arrow2Lend"
+       orient="auto"
+       refY="0"
+       refX="0"
+       id="Arrow2Lend-2-6-2"
+       style="overflow:visible"
+       inkscape:isstock="true">
+      <path
+         inkscape:connector-curvature="0"
+         id="path2284-6-3-4"
+         style="fill:#000000;fill-opacity:1;fill-rule:evenodd;stroke:#000000;stroke-width:0.625;stroke-linejoin:round;stroke-opacity:1"
+         d="M 8.7185878,4.0337352 -2.2072895,0.01601326 8.7185884,-4.0017078 c -1.7454984,2.3720609 -1.7354408,5.6174519 -6e-7,8.035443 z"
+         transform="matrix(-1.1,0,0,-1.1,-1.1,0)" />
+    </marker>
+    <marker
+       inkscape:stockid="Arrow2Lend"
+       orient="auto"
+       refY="0"
+       refX="0"
+       id="Arrow2Lend-5"
+       style="overflow:visible"
+       inkscape:isstock="true">
+      <path
+         inkscape:connector-curvature="0"
+         id="path2284-8"
+         style="fill:#000000;fill-opacity:1;fill-rule:evenodd;stroke:#000000;stroke-width:0.625;stroke-linejoin:round;stroke-opacity:1"
+         d="M 8.7185878,4.0337352 -2.2072895,0.01601326 8.7185884,-4.0017078 c -1.7454984,2.3720609 -1.7354408,5.6174519 -6e-7,8.035443 z"
+         transform="matrix(-1.1,0,0,-1.1,-1.1,0)" />
+    </marker>
+    <marker
+       inkscape:stockid="Arrow2Lend"
+       orient="auto"
+       refY="0"
+       refX="0"
+       id="marker4059-8-1"
+       style="overflow:visible"
+       inkscape:isstock="true">
+      <path
+         inkscape:connector-curvature="0"
+         id="path4057-0-9"
+         style="fill:#000000;fill-opacity:1;fill-rule:evenodd;stroke:#000000;stroke-width:0.625;stroke-linejoin:round;stroke-opacity:1"
+         d="M 8.7185878,4.0337352 -2.2072895,0.01601326 8.7185884,-4.0017078 c -1.7454984,2.3720609 -1.7354408,5.6174519 -6e-7,8.035443 z"
+         transform="matrix(-1.1,0,0,-1.1,-1.1,0)" />
+    </marker>
+    <marker
+       inkscape:stockid="Arrow2Lend"
+       orient="auto"
+       refY="0"
+       refX="0"
+       id="marker4059-8-1-6"
+       style="overflow:visible"
+       inkscape:isstock="true">
+      <path
+         inkscape:connector-curvature="0"
+         id="path4057-0-9-1"
+         style="fill:#000000;fill-opacity:1;fill-rule:evenodd;stroke:#000000;stroke-width:0.625;stroke-linejoin:round;stroke-opacity:1"
+         d="M 8.7185878,4.0337352 -2.2072895,0.01601326 8.7185884,-4.0017078 c -1.7454984,2.3720609 -1.7354408,5.6174519 -6e-7,8.035443 z"
+         transform="matrix(-1.1,0,0,-1.1,-1.1,0)" />
+    </marker>
+    <marker
+       inkscape:stockid="Arrow2Lend"
+       orient="auto"
+       refY="0"
+       refX="0"
+       id="Arrow2Lend-2-4-1"
+       style="overflow:visible"
+       inkscape:isstock="true">
+      <path
+         inkscape:connector-curvature="0"
+         id="path2284-6-0-0"
+         style="fill:#000000;fill-opacity:1;fill-rule:evenodd;stroke:#000000;stroke-width:0.625;stroke-linejoin:round;stroke-opacity:1"
+         d="M 8.7185878,4.0337352 -2.2072895,0.01601326 8.7185884,-4.0017078 c -1.7454984,2.3720609 -1.7354408,5.6174519 -6e-7,8.035443 z"
+         transform="matrix(-1.1,0,0,-1.1,-1.1,0)" />
+    </marker>
+    <marker
+       inkscape:stockid="Arrow2Lend"
+       orient="auto"
+       refY="0"
+       refX="0"
+       id="Arrow2Lend-2-4-1-9"
+       style="overflow:visible"
+       inkscape:isstock="true">
+      <path
+         inkscape:connector-curvature="0"
+         id="path2284-6-0-0-3"
+         style="fill:#000000;fill-opacity:1;fill-rule:evenodd;stroke:#000000;stroke-width:0.625;stroke-linejoin:round;stroke-opacity:1"
+         d="M 8.7185878,4.0337352 -2.2072895,0.01601326 8.7185884,-4.0017078 c -1.7454984,2.3720609 -1.7354408,5.6174519 -6e-7,8.035443 z"
+         transform="matrix(-1.1,0,0,-1.1,-1.1,0)" />
+    </marker>
+    <marker
+       inkscape:stockid="Arrow2Lend"
+       orient="auto"
+       refY="0"
+       refX="0"
+       id="Arrow2Lend-2-4-1-7"
+       style="overflow:visible"
+       inkscape:isstock="true">
+      <path
+         inkscape:connector-curvature="0"
+         id="path2284-6-0-0-0"
+         style="fill:#000000;fill-opacity:1;fill-rule:evenodd;stroke:#000000;stroke-width:0.625;stroke-linejoin:round;stroke-opacity:1"
+         d="M 8.7185878,4.0337352 -2.2072895,0.01601326 8.7185884,-4.0017078 c -1.7454984,2.3720609 -1.7354408,5.6174519 -6e-7,8.035443 z"
+         transform="matrix(-1.1,0,0,-1.1,-1.1,0)" />
+    </marker>
+    <marker
+       inkscape:stockid="Arrow2Lend"
+       orient="auto"
+       refY="0"
+       refX="0"
+       id="Arrow2Lend-2-4-1-7-7"
+       style="overflow:visible"
+       inkscape:isstock="true">
+      <path
+         inkscape:connector-curvature="0"
+         id="path2284-6-0-0-0-8"
+         style="fill:#000000;fill-opacity:1;fill-rule:evenodd;stroke:#000000;stroke-width:0.625;stroke-linejoin:round;stroke-opacity:1"
+         d="M 8.7185878,4.0337352 -2.2072895,0.01601326 8.7185884,-4.0017078 c -1.7454984,2.3720609 -1.7354408,5.6174519 -6e-7,8.035443 z"
+         transform="matrix(-1.1,0,0,-1.1,-1.1,0)" />
+    </marker>
+    <marker
+       inkscape:isstock="true"
+       style="overflow:visible"
+       id="marker5180-9"
+       refX="0"
+       refY="0"
+       orient="auto"
+       inkscape:stockid="Arrow1Lend">
+      <path
+         inkscape:connector-curvature="0"
+         transform="matrix(-0.8,0,0,-0.8,-10,0)"
+         style="fill:#000000;fill-opacity:1;fill-rule:evenodd;stroke:#000000;stroke-width:1.00000003pt;stroke-opacity:1"
+         d="M 0,0 5,-5 -12.5,0 5,5 Z"
+         id="path5178-1" />
+    </marker>
+    <marker
+       inkscape:isstock="true"
+       style="overflow:visible"
+       id="marker5180-9-9"
+       refX="0"
+       refY="0"
+       orient="auto"
+       inkscape:stockid="Arrow1Lend">
+      <path
+         inkscape:connector-curvature="0"
+         transform="matrix(-0.8,0,0,-0.8,-10,0)"
+         style="fill:#000000;fill-opacity:1;fill-rule:evenodd;stroke:#000000;stroke-width:1.00000003pt;stroke-opacity:1"
+         d="M 0,0 5,-5 -12.5,0 5,5 Z"
+         id="path5178-1-4" />
+    </marker>
+    <marker
+       inkscape:stockid="Arrow2Lstart"
+       orient="auto"
+       refY="0"
+       refX="0"
+       id="Arrow2Lstart-6"
+       style="overflow:visible"
+       inkscape:isstock="true">
+      <path
+         inkscape:connector-curvature="0"
+         id="path1110-1"
+         style="fill:#000000;fill-opacity:1;fill-rule:evenodd;stroke:#000000;stroke-width:0.625;stroke-linejoin:round;stroke-opacity:1"
+         d="M 8.7185878,4.0337352 -2.2072895,0.01601326 8.7185884,-4.0017078 c -1.7454984,2.3720609 -1.7354408,5.6174519 -6e-7,8.035443 z"
+         transform="matrix(1.1,0,0,1.1,1.1,0)" />
+    </marker>
+    <marker
+       inkscape:isstock="true"
+       style="overflow:visible"
+       id="marker14793-9"
+       refX="0"
+       refY="0"
+       orient="auto"
+       inkscape:stockid="Arrow2Lend">
+      <path
+         inkscape:connector-curvature="0"
+         transform="matrix(-1.1,0,0,-1.1,-1.1,0)"
+         d="M 8.7185878,4.0337352 -2.2072895,0.01601326 8.7185884,-4.0017078 c -1.7454984,2.3720609 -1.7354408,5.6174519 -6e-7,8.035443 z"
+         style="fill:#000000;fill-opacity:1;fill-rule:evenodd;stroke:#000000;stroke-width:0.625;stroke-linejoin:round;stroke-opacity:1"
+         id="path14791-9" />
+    </marker>
+    <marker
+       inkscape:isstock="true"
+       style="overflow:visible"
+       id="marker14793-5"
+       refX="0"
+       refY="0"
+       orient="auto"
+       inkscape:stockid="Arrow2Lend">
+      <path
+         inkscape:connector-curvature="0"
+         transform="matrix(-1.1,0,0,-1.1,-1.1,0)"
+         d="M 8.7185878,4.0337352 -2.2072895,0.01601326 8.7185884,-4.0017078 c -1.7454984,2.3720609 -1.7354408,5.6174519 -6e-7,8.035443 z"
+         style="fill:#000000;fill-opacity:1;fill-rule:evenodd;stroke:#000000;stroke-width:0.625;stroke-linejoin:round;stroke-opacity:1"
+         id="path14791-0" />
+    </marker>
+    <marker
+       inkscape:isstock="true"
+       style="overflow:visible"
+       id="marker14793-1"
+       refX="0"
+       refY="0"
+       orient="auto"
+       inkscape:stockid="Arrow2Lend">
+      <path
+         inkscape:connector-curvature="0"
+         transform="matrix(-1.1,0,0,-1.1,-1.1,0)"
+         d="M 8.7185878,4.0337352 -2.2072895,0.01601326 8.7185884,-4.0017078 c -1.7454984,2.3720609 -1.7354408,5.6174519 -6e-7,8.035443 z"
+         style="fill:#000000;fill-opacity:1;fill-rule:evenodd;stroke:#000000;stroke-width:0.625;stroke-linejoin:round;stroke-opacity:1"
+         id="path14791-4" />
+    </marker>
+    <marker
+       inkscape:isstock="true"
+       style="overflow:visible"
+       id="marker22960-5"
+       refX="0"
+       refY="0"
+       orient="auto"
+       inkscape:stockid="Arrow2Lstart">
+      <path
+         inkscape:connector-curvature="0"
+         transform="matrix(1.1,0,0,1.1,1.1,0)"
+         d="M 8.7185878,4.0337352 -2.2072895,0.01601326 8.7185884,-4.0017078 c -1.7454984,2.3720609 -1.7354408,5.6174519 -6e-7,8.035443 z"
+         style="fill:#000000;fill-opacity:1;fill-rule:evenodd;stroke:#000000;stroke-width:0.625;stroke-linejoin:round;stroke-opacity:1"
+         id="path22958-6" />
+    </marker>
+    <marker
+       inkscape:stockid="Arrow2Lend"
+       orient="auto"
+       refY="0"
+       refX="0"
+       id="marker1560-3"
+       style="overflow:visible"
+       inkscape:isstock="true">
+      <path
+         inkscape:connector-curvature="0"
+         id="path1558-3"
+         style="fill:#000000;fill-opacity:1;fill-rule:evenodd;stroke:#000000;stroke-width:0.625;stroke-linejoin:round;stroke-opacity:1"
+         d="M 8.7185878,4.0337352 -2.2072895,0.01601326 8.7185884,-4.0017078 c -1.7454984,2.3720609 -1.7354408,5.6174519 -6e-7,8.035443 z"
+         transform="matrix(-1.1,0,0,-1.1,-1.1,0)" />
+    </marker>
+    <marker
+       inkscape:isstock="true"
+       style="overflow:visible"
+       id="marker22960-7"
+       refX="0"
+       refY="0"
+       orient="auto"
+       inkscape:stockid="Arrow2Lstart">
+      <path
+         inkscape:connector-curvature="0"
+         transform="matrix(1.1,0,0,1.1,1.1,0)"
+         d="M 8.7185878,4.0337352 -2.2072895,0.01601326 8.7185884,-4.0017078 c -1.7454984,2.3720609 -1.7354408,5.6174519 -6e-7,8.035443 z"
+         style="fill:#000000;fill-opacity:1;fill-rule:evenodd;stroke:#000000;stroke-width:0.625;stroke-linejoin:round;stroke-opacity:1"
+         id="path22958-61" />
+    </marker>
+    <marker
+       inkscape:isstock="true"
+       style="overflow:visible"
+       id="marker22960-5-6"
+       refX="0"
+       refY="0"
+       orient="auto"
+       inkscape:stockid="Arrow2Lstart">
+      <path
+         inkscape:connector-curvature="0"
+         transform="matrix(1.1,0,0,1.1,1.1,0)"
+         d="M 8.7185878,4.0337352 -2.2072895,0.01601326 8.7185884,-4.0017078 c -1.7454984,2.3720609 -1.7354408,5.6174519 -6e-7,8.035443 z"
+         style="fill:#000000;fill-opacity:1;fill-rule:evenodd;stroke:#000000;stroke-width:0.625;stroke-linejoin:round;stroke-opacity:1"
+         id="path22958-6-8" />
+    </marker>
+    <marker
+       inkscape:isstock="true"
+       style="overflow:visible"
+       id="marker14793-1-4"
+       refX="0"
+       refY="0"
+       orient="auto"
+       inkscape:stockid="Arrow2Lend">
+      <path
+         inkscape:connector-curvature="0"
+         transform="matrix(-1.1,0,0,-1.1,-1.1,0)"
+         d="M 8.7185878,4.0337352 -2.2072895,0.01601326 8.7185884,-4.0017078 c -1.7454984,2.3720609 -1.7354408,5.6174519 -6e-7,8.035443 z"
+         style="fill:#000000;fill-opacity:1;fill-rule:evenodd;stroke:#000000;stroke-width:0.625;stroke-linejoin:round;stroke-opacity:1"
+         id="path14791-4-5" />
+    </marker>
+    <marker
+       inkscape:isstock="true"
+       style="overflow:visible"
+       id="marker22960-9"
+       refX="0"
+       refY="0"
+       orient="auto"
+       inkscape:stockid="Arrow2Lstart">
+      <path
+         inkscape:connector-curvature="0"
+         transform="matrix(1.1,0,0,1.1,1.1,0)"
+         d="M 8.7185878,4.0337352 -2.2072895,0.01601326 8.7185884,-4.0017078 c -1.7454984,2.3720609 -1.7354408,5.6174519 -6e-7,8.035443 z"
+         style="fill:#000000;fill-opacity:1;fill-rule:evenodd;stroke:#000000;stroke-width:0.625;stroke-linejoin:round;stroke-opacity:1"
+         id="path22958-60" />
+    </marker>
+    <marker
+       inkscape:isstock="true"
+       style="overflow:visible"
+       id="marker14793-1-9-6"
+       refX="0"
+       refY="0"
+       orient="auto"
+       inkscape:stockid="Arrow2Lend">
+      <path
+         inkscape:connector-curvature="0"
+         transform="matrix(-1.1,0,0,-1.1,-1.1,0)"
+         d="M 8.7185878,4.0337352 -2.2072895,0.01601326 8.7185884,-4.0017078 c -1.7454984,2.3720609 -1.7354408,5.6174519 -6e-7,8.035443 z"
+         style="fill:#000000;fill-opacity:1;fill-rule:evenodd;stroke:#000000;stroke-width:0.625;stroke-linejoin:round;stroke-opacity:1"
+         id="path14791-4-1-5" />
+    </marker>
+    <marker
+       inkscape:isstock="true"
+       style="overflow:visible"
+       id="marker22960-9-7"
+       refX="0"
+       refY="0"
+       orient="auto"
+       inkscape:stockid="Arrow2Lstart">
+      <path
+         inkscape:connector-curvature="0"
+         transform="matrix(1.1,0,0,1.1,1.1,0)"
+         d="M 8.7185878,4.0337352 -2.2072895,0.01601326 8.7185884,-4.0017078 c -1.7454984,2.3720609 -1.7354408,5.6174519 -6e-7,8.035443 z"
+         style="fill:#000000;fill-opacity:1;fill-rule:evenodd;stroke:#000000;stroke-width:0.625;stroke-linejoin:round;stroke-opacity:1"
+         id="path22958-60-6" />
+    </marker>
+    <marker
+       inkscape:stockid="Arrow2Lend"
+       orient="auto"
+       refY="0"
+       refX="0"
+       id="marker1560-1"
+       style="overflow:visible"
+       inkscape:isstock="true">
+      <path
+         id="path1558-8"
+         style="fill:#000000;fill-opacity:1;fill-rule:evenodd;stroke:#000000;stroke-width:0.625;stroke-linejoin:round;stroke-opacity:1"
+         d="M 8.7185878,4.0337352 -2.2072895,0.01601326 8.7185884,-4.0017078 c -1.7454984,2.3720609 -1.7354408,5.6174519 -6e-7,8.035443 z"
+         transform="matrix(-1.1,0,0,-1.1,-1.1,0)"
+         inkscape:connector-curvature="0" />
+    </marker>
+    <marker
+       inkscape:stockid="Arrow2Lend"
+       orient="auto"
+       refY="0"
+       refX="0"
+       id="marker1560-8"
+       style="overflow:visible"
+       inkscape:isstock="true">
+      <path
+         id="path1558-1"
+         style="fill:#000000;fill-opacity:1;fill-rule:evenodd;stroke:#000000;stroke-width:0.625;stroke-linejoin:round;stroke-opacity:1"
+         d="M 8.7185878,4.0337352 -2.2072895,0.01601326 8.7185884,-4.0017078 c -1.7454984,2.3720609 -1.7354408,5.6174519 -6e-7,8.035443 z"
+         transform="matrix(-1.1,0,0,-1.1,-1.1,0)"
+         inkscape:connector-curvature="0" />
+    </marker>
+    <marker
+       inkscape:stockid="Arrow2Lend"
+       orient="auto"
+       refY="0"
+       refX="0"
+       id="marker1560-1-3"
+       style="overflow:visible"
+       inkscape:isstock="true">
+      <path
+         id="path1558-8-4"
+         style="fill:#000000;fill-opacity:1;fill-rule:evenodd;stroke:#000000;stroke-width:0.625;stroke-linejoin:round;stroke-opacity:1"
+         d="M 8.7185878,4.0337352 -2.2072895,0.01601326 8.7185884,-4.0017078 c -1.7454984,2.3720609 -1.7354408,5.6174519 -6e-7,8.035443 z"
+         transform="matrix(-1.1,0,0,-1.1,-1.1,0)"
+         inkscape:connector-curvature="0" />
+    </marker>
+    <marker
+       inkscape:isstock="true"
+       style="overflow:visible"
+       id="marker14793-1-5"
+       refX="0"
+       refY="0"
+       orient="auto"
+       inkscape:stockid="Arrow2Lend">
+      <path
+         inkscape:connector-curvature="0"
+         transform="matrix(-1.1,0,0,-1.1,-1.1,0)"
+         d="M 8.7185878,4.0337352 -2.2072895,0.01601326 8.7185884,-4.0017078 c -1.7454984,2.3720609 -1.7354408,5.6174519 -6e-7,8.035443 z"
+         style="fill:#000000;fill-opacity:1;fill-rule:evenodd;stroke:#000000;stroke-width:0.625;stroke-linejoin:round;stroke-opacity:1"
+         id="path14791-4-6" />
+    </marker>
+    <marker
+       inkscape:isstock="true"
+       style="overflow:visible"
+       id="marker22960-97"
+       refX="0"
+       refY="0"
+       orient="auto"
+       inkscape:stockid="Arrow2Lstart">
+      <path
+         transform="matrix(1.1,0,0,1.1,1.1,0)"
+         d="M 8.7185878,4.0337352 -2.2072895,0.01601326 8.7185884,-4.0017078 c -1.7454984,2.3720609 -1.7354408,5.6174519 -6e-7,8.035443 z"
+         style="fill:#000000;fill-opacity:1;fill-rule:evenodd;stroke:#000000;stroke-width:0.625;stroke-linejoin:round;stroke-opacity:1"
+         id="path22958-7"
+         inkscape:connector-curvature="0" />
+    </marker>
+    <marker
+       inkscape:stockid="Arrow2Lend"
+       orient="auto"
+       refY="0"
+       refX="0"
+       id="marker1654-6"
+       style="overflow:visible"
+       inkscape:isstock="true">
+      <path
+         inkscape:connector-curvature="0"
+         id="path1652-8"
+         style="fill:#000000;fill-opacity:1;fill-rule:evenodd;stroke:#000000;stroke-width:0.625;stroke-linejoin:round;stroke-opacity:1"
+         d="M 8.7185878,4.0337352 -2.2072895,0.01601326 8.7185884,-4.0017078 c -1.7454984,2.3720609 -1.7354408,5.6174519 -6e-7,8.035443 z"
+         transform="matrix(-1.1,0,0,-1.1,-1.1,0)" />
+    </marker>
+    <marker
+       inkscape:isstock="true"
+       style="overflow:visible"
+       id="marker22960-5-7"
+       refX="0"
+       refY="0"
+       orient="auto"
+       inkscape:stockid="Arrow2Lstart">
+      <path
+         inkscape:connector-curvature="0"
+         transform="matrix(1.1,0,0,1.1,1.1,0)"
+         d="M 8.7185878,4.0337352 -2.2072895,0.01601326 8.7185884,-4.0017078 c -1.7454984,2.3720609 -1.7354408,5.6174519 -6e-7,8.035443 z"
+         style="fill:#000000;fill-opacity:1;fill-rule:evenodd;stroke:#000000;stroke-width:0.625;stroke-linejoin:round;stroke-opacity:1"
+         id="path22958-6-0" />
+    </marker>
+    <marker
+       inkscape:isstock="true"
+       style="overflow:visible"
+       id="marker14793-2"
+       refX="0"
+       refY="0"
+       orient="auto"
+       inkscape:stockid="Arrow2Lend">
+      <path
+         transform="matrix(-1.1,0,0,-1.1,-1.1,0)"
+         d="M 8.7185878,4.0337352 -2.2072895,0.01601326 8.7185884,-4.0017078 c -1.7454984,2.3720609 -1.7354408,5.6174519 -6e-7,8.035443 z"
+         style="fill:#000000;fill-opacity:1;fill-rule:evenodd;stroke:#000000;stroke-width:0.625;stroke-linejoin:round;stroke-opacity:1"
+         id="path14791-6"
+         inkscape:connector-curvature="0" />
+    </marker>
+    <marker
+       inkscape:stockid="Arrow2Lend"
+       orient="auto"
+       refY="0"
+       refX="0"
+       id="marker19632-9"
+       style="overflow:visible"
+       inkscape:isstock="true">
+      <path
+         inkscape:connector-curvature="0"
+         id="path19630-0"
+         style="fill:#000000;fill-opacity:1;fill-rule:evenodd;stroke:#000000;stroke-width:0.625;stroke-linejoin:round;stroke-opacity:1"
+         d="M 8.7185878,4.0337352 -2.2072895,0.01601326 8.7185884,-4.0017078 c -1.7454984,2.3720609 -1.7354408,5.6174519 -6e-7,8.035443 z"
+         transform="matrix(-1.1,0,0,-1.1,-1.1,0)" />
+    </marker>
+    <marker
+       inkscape:stockid="Arrow2Lend"
+       orient="auto"
+       refY="0"
+       refX="0"
+       id="marker20184-3"
+       style="overflow:visible"
+       inkscape:isstock="true">
+      <path
+         inkscape:connector-curvature="0"
+         id="path20182-4"
+         style="fill:#000000;fill-opacity:1;fill-rule:evenodd;stroke:#000000;stroke-width:0.625;stroke-linejoin:round;stroke-opacity:1"
+         d="M 8.7185878,4.0337352 -2.2072895,0.01601326 8.7185884,-4.0017078 c -1.7454984,2.3720609 -1.7354408,5.6174519 -6e-7,8.035443 z"
+         transform="matrix(-1.1,0,0,-1.1,-1.1,0)" />
+    </marker>
+    <marker
+       inkscape:stockid="Arrow2Lend"
+       orient="auto"
+       refY="0"
+       refX="0"
+       id="marker18406-4"
+       style="overflow:visible"
+       inkscape:isstock="true"
+       inkscape:collect="always">
+      <path
+         inkscape:connector-curvature="0"
+         id="path18404-3"
+         style="fill:#000000;fill-opacity:1;fill-rule:evenodd;stroke:#000000;stroke-width:0.625;stroke-linejoin:round;stroke-opacity:1"
+         d="M 8.7185878,4.0337352 -2.2072895,0.01601326 8.7185884,-4.0017078 c -1.7454984,2.3720609 -1.7354408,5.6174519 -6e-7,8.035443 z"
+         transform="matrix(-1.1,0,0,-1.1,-1.1,0)" />
+    </marker>
+    <marker
+       inkscape:isstock="true"
+       style="overflow:visible"
+       id="marker6296-4"
+       refX="0"
+       refY="0"
+       orient="auto"
+       inkscape:stockid="Arrow2Lend"
+       inkscape:collect="always">
+      <path
+         inkscape:connector-curvature="0"
+         transform="matrix(-1.1,0,0,-1.1,-1.1,0)"
+         d="M 8.7185878,4.0337352 -2.2072895,0.01601326 8.7185884,-4.0017078 c -1.7454984,2.3720609 -1.7354408,5.6174519 -6e-7,8.035443 z"
+         style="fill:#000000;fill-opacity:1;fill-rule:evenodd;stroke:#000000;stroke-width:0.625;stroke-linejoin:round;stroke-opacity:1"
+         id="path6294-8" />
+    </marker>
+    <marker
+       inkscape:isstock="true"
+       style="overflow:visible"
+       id="marker17872-8"
+       refX="0"
+       refY="0"
+       orient="auto"
+       inkscape:stockid="Arrow2Lend"
+       inkscape:collect="always">
+      <path
+         inkscape:connector-curvature="0"
+         transform="matrix(-1.1,0,0,-1.1,-1.1,0)"
+         d="M 8.7185878,4.0337352 -2.2072895,0.01601326 8.7185884,-4.0017078 c -1.7454984,2.3720609 -1.7354408,5.6174519 -6e-7,8.035443 z"
+         style="fill:#000000;fill-opacity:1;fill-rule:evenodd;stroke:#000000;stroke-width:0.625;stroke-linejoin:round;stroke-opacity:1"
+         id="path17870-5" />
+    </marker>
+    <marker
+       inkscape:stockid="Arrow2Lstart"
+       orient="auto"
+       refY="0"
+       refX="0"
+       id="marker9343-4"
+       style="overflow:visible"
+       inkscape:isstock="true">
+      <path
+         inkscape:connector-curvature="0"
+         id="path9341-4"
+         style="fill:#000000;fill-opacity:1;fill-rule:evenodd;stroke:#000000;stroke-width:0.625;stroke-linejoin:round;stroke-opacity:1"
+         d="M 8.7185878,4.0337352 -2.2072895,0.01601326 8.7185884,-4.0017078 c -1.7454984,2.3720609 -1.7354408,5.6174519 -6e-7,8.035443 z"
+         transform="matrix(1.1,0,0,1.1,1.1,0)" />
+    </marker>
+    <marker
+       inkscape:stockid="Arrow2Lend"
+       orient="auto"
+       refY="0"
+       refX="0"
+       id="marker16657-7"
+       style="overflow:visible"
+       inkscape:isstock="true"
+       inkscape:collect="always">
+      <path
+         inkscape:connector-curvature="0"
+         id="path16655-1"
+         style="fill:#000000;fill-opacity:1;fill-rule:evenodd;stroke:#000000;stroke-width:0.625;stroke-linejoin:round;stroke-opacity:1"
+         d="M 8.7185878,4.0337352 -2.2072895,0.01601326 8.7185884,-4.0017078 c -1.7454984,2.3720609 -1.7354408,5.6174519 -6e-7,8.035443 z"
+         transform="matrix(-1.1,0,0,-1.1,-1.1,0)" />
+    </marker>
+    <marker
+       inkscape:stockid="Arrow2Lend"
+       orient="auto"
+       refY="0"
+       refX="0"
+       id="marker17252-3"
+       style="overflow:visible"
+       inkscape:isstock="true">
+      <path
+         inkscape:connector-curvature="0"
+         id="path17250-5"
+         style="fill:#000000;fill-opacity:1;fill-rule:evenodd;stroke:#000000;stroke-width:0.625;stroke-linejoin:round;stroke-opacity:1"
+         d="M 8.7185878,4.0337352 -2.2072895,0.01601326 8.7185884,-4.0017078 c -1.7454984,2.3720609 -1.7354408,5.6174519 -6e-7,8.035443 z"
+         transform="matrix(-1.1,0,0,-1.1,-1.1,0)" />
+    </marker>
+    <marker
+       inkscape:isstock="true"
+       style="overflow:visible"
+       id="marker23218-3"
+       refX="0"
+       refY="0"
+       orient="auto"
+       inkscape:stockid="Arrow2Lend">
+      <path
+         inkscape:connector-curvature="0"
+         transform="matrix(-1.1,0,0,-1.1,-1.1,0)"
+         d="M 8.7185878,4.0337352 -2.2072895,0.01601326 8.7185884,-4.0017078 c -1.7454984,2.3720609 -1.7354408,5.6174519 -6e-7,8.035443 z"
+         style="fill:#000000;fill-opacity:1;fill-rule:evenodd;stroke:#000000;stroke-width:0.625;stroke-linejoin:round;stroke-opacity:1"
+         id="path23216-8" />
+    </marker>
+    <marker
+       inkscape:isstock="true"
+       style="overflow:visible"
+       id="marker23218-7"
+       refX="0"
+       refY="0"
+       orient="auto"
+       inkscape:stockid="Arrow2Lend">
+      <path
+         inkscape:connector-curvature="0"
+         transform="matrix(-1.1,0,0,-1.1,-1.1,0)"
+         d="M 8.7185878,4.0337352 -2.2072895,0.01601326 8.7185884,-4.0017078 c -1.7454984,2.3720609 -1.7354408,5.6174519 -6e-7,8.035443 z"
+         style="fill:#000000;fill-opacity:1;fill-rule:evenodd;stroke:#000000;stroke-width:0.625;stroke-linejoin:round;stroke-opacity:1"
+         id="path23216-89" />
+    </marker>
+    <marker
+       inkscape:isstock="true"
+       style="overflow:visible"
+       id="marker23218-3-7"
+       refX="0"
+       refY="0"
+       orient="auto"
+       inkscape:stockid="Arrow2Lend">
+      <path
+         inkscape:connector-curvature="0"
+         transform="matrix(-1.1,0,0,-1.1,-1.1,0)"
+         d="M 8.7185878,4.0337352 -2.2072895,0.01601326 8.7185884,-4.0017078 c -1.7454984,2.3720609 -1.7354408,5.6174519 -6e-7,8.035443 z"
+         style="fill:#000000;fill-opacity:1;fill-rule:evenodd;stroke:#000000;stroke-width:0.625;stroke-linejoin:round;stroke-opacity:1"
+         id="path23216-8-2" />
+    </marker>
+    <marker
+       inkscape:isstock="true"
+       style="overflow:visible"
+       id="marker22960-97-3"
+       refX="0"
+       refY="0"
+       orient="auto"
+       inkscape:stockid="Arrow2Lstart">
+      <path
+         transform="matrix(1.1,0,0,1.1,1.1,0)"
+         d="M 8.7185878,4.0337352 -2.2072895,0.01601326 8.7185884,-4.0017078 c -1.7454984,2.3720609 -1.7354408,5.6174519 -6e-7,8.035443 z"
+         style="fill:#000000;fill-opacity:1;fill-rule:evenodd;stroke:#000000;stroke-width:0.625;stroke-linejoin:round;stroke-opacity:1"
+         id="path22958-7-6"
+         inkscape:connector-curvature="0" />
+    </marker>
+    <marker
+       inkscape:isstock="true"
+       style="overflow:visible"
+       id="marker14793-1-5-9"
+       refX="0"
+       refY="0"
+       orient="auto"
+       inkscape:stockid="Arrow2Lend">
+      <path
+         inkscape:connector-curvature="0"
+         transform="matrix(-1.1,0,0,-1.1,-1.1,0)"
+         d="M 8.7185878,4.0337352 -2.2072895,0.01601326 8.7185884,-4.0017078 c -1.7454984,2.3720609 -1.7354408,5.6174519 -6e-7,8.035443 z"
+         style="fill:#000000;fill-opacity:1;fill-rule:evenodd;stroke:#000000;stroke-width:0.625;stroke-linejoin:round;stroke-opacity:1"
+         id="path14791-4-6-0" />
+    </marker>
+    <marker
+       inkscape:isstock="true"
+       style="overflow:visible"
+       id="marker22960-56"
+       refX="0"
+       refY="0"
+       orient="auto"
+       inkscape:stockid="Arrow2Lstart">
+      <path
+         transform="matrix(1.1,0,0,1.1,1.1,0)"
+         d="M 8.7185878,4.0337352 -2.2072895,0.01601326 8.7185884,-4.0017078 c -1.7454984,2.3720609 -1.7354408,5.6174519 -6e-7,8.035443 z"
+         style="fill:#000000;fill-opacity:1;fill-rule:evenodd;stroke:#000000;stroke-width:0.625;stroke-linejoin:round;stroke-opacity:1"
+         id="path22958-4"
+         inkscape:connector-curvature="0" />
+    </marker>
+    <marker
+       inkscape:isstock="true"
+       style="overflow:visible"
+       id="marker22960-5-7-8"
+       refX="0"
+       refY="0"
+       orient="auto"
+       inkscape:stockid="Arrow2Lstart">
+      <path
+         inkscape:connector-curvature="0"
+         transform="matrix(1.1,0,0,1.1,1.1,0)"
+         d="M 8.7185878,4.0337352 -2.2072895,0.01601326 8.7185884,-4.0017078 c -1.7454984,2.3720609 -1.7354408,5.6174519 -6e-7,8.035443 z"
+         style="fill:#000000;fill-opacity:1;fill-rule:evenodd;stroke:#000000;stroke-width:0.625;stroke-linejoin:round;stroke-opacity:1"
+         id="path22958-6-0-0" />
+    </marker>
+    <marker
+       inkscape:isstock="true"
+       style="overflow:visible"
+       id="marker14793-2-1"
+       refX="0"
+       refY="0"
+       orient="auto"
+       inkscape:stockid="Arrow2Lend">
+      <path
+         transform="matrix(-1.1,0,0,-1.1,-1.1,0)"
+         d="M 8.7185878,4.0337352 -2.2072895,0.01601326 8.7185884,-4.0017078 c -1.7454984,2.3720609 -1.7354408,5.6174519 -6e-7,8.035443 z"
+         style="fill:#000000;fill-opacity:1;fill-rule:evenodd;stroke:#000000;stroke-width:0.625;stroke-linejoin:round;stroke-opacity:1"
+         id="path14791-6-0"
+         inkscape:connector-curvature="0" />
+    </marker>
+    <marker
+       inkscape:isstock="true"
+       style="overflow:visible"
+       id="marker14793-1-58"
+       refX="0"
+       refY="0"
+       orient="auto"
+       inkscape:stockid="Arrow2Lend">
+      <path
+         inkscape:connector-curvature="0"
+         transform="matrix(-1.1,0,0,-1.1,-1.1,0)"
+         d="M 8.7185878,4.0337352 -2.2072895,0.01601326 8.7185884,-4.0017078 c -1.7454984,2.3720609 -1.7354408,5.6174519 -6e-7,8.035443 z"
+         style="fill:#000000;fill-opacity:1;fill-rule:evenodd;stroke:#000000;stroke-width:0.625;stroke-linejoin:round;stroke-opacity:1"
+         id="path14791-4-2" />
+    </marker>
+    <marker
+       inkscape:isstock="true"
+       style="overflow:visible"
+       id="marker22960-5-3"
+       refX="0"
+       refY="0"
+       orient="auto"
+       inkscape:stockid="Arrow2Lstart">
+      <path
+         inkscape:connector-curvature="0"
+         transform="matrix(1.1,0,0,1.1,1.1,0)"
+         d="M 8.7185878,4.0337352 -2.2072895,0.01601326 8.7185884,-4.0017078 c -1.7454984,2.3720609 -1.7354408,5.6174519 -6e-7,8.035443 z"
+         style="fill:#000000;fill-opacity:1;fill-rule:evenodd;stroke:#000000;stroke-width:0.625;stroke-linejoin:round;stroke-opacity:1"
+         id="path22958-6-4" />
+    </marker>
+    <marker
+       inkscape:isstock="true"
+       style="overflow:visible"
+       id="marker14793-8"
+       refX="0"
+       refY="0"
+       orient="auto"
+       inkscape:stockid="Arrow2Lend">
+      <path
+         transform="matrix(-1.1,0,0,-1.1,-1.1,0)"
+         d="M 8.7185878,4.0337352 -2.2072895,0.01601326 8.7185884,-4.0017078 c -1.7454984,2.3720609 -1.7354408,5.6174519 -6e-7,8.035443 z"
+         style="fill:#000000;fill-opacity:1;fill-rule:evenodd;stroke:#000000;stroke-width:0.625;stroke-linejoin:round;stroke-opacity:1"
+         id="path14791-5"
+         inkscape:connector-curvature="0" />
+    </marker>
+    <marker
+       inkscape:isstock="true"
+       style="overflow:visible"
+       id="marker22960-97-3-5"
+       refX="0"
+       refY="0"
+       orient="auto"
+       inkscape:stockid="Arrow2Lstart">
+      <path
+         transform="matrix(1.1,0,0,1.1,1.1,0)"
+         d="M 8.7185878,4.0337352 -2.2072895,0.01601326 8.7185884,-4.0017078 c -1.7454984,2.3720609 -1.7354408,5.6174519 -6e-7,8.035443 z"
+         style="fill:#000000;fill-opacity:1;fill-rule:evenodd;stroke:#000000;stroke-width:0.625;stroke-linejoin:round;stroke-opacity:1"
+         id="path22958-7-6-2"
+         inkscape:connector-curvature="0" />
+    </marker>
+    <marker
+       inkscape:isstock="true"
+       style="overflow:visible"
+       id="marker14793-1-5-9-1"
+       refX="0"
+       refY="0"
+       orient="auto"
+       inkscape:stockid="Arrow2Lend">
+      <path
+         inkscape:connector-curvature="0"
+         transform="matrix(-1.1,0,0,-1.1,-1.1,0)"
+         d="M 8.7185878,4.0337352 -2.2072895,0.01601326 8.7185884,-4.0017078 c -1.7454984,2.3720609 -1.7354408,5.6174519 -6e-7,8.035443 z"
+         style="fill:#000000;fill-opacity:1;fill-rule:evenodd;stroke:#000000;stroke-width:0.625;stroke-linejoin:round;stroke-opacity:1"
+         id="path14791-4-6-0-4" />
+    </marker>
+    <marker
+       inkscape:isstock="true"
+       style="overflow:visible"
+       id="marker22960-56-0"
+       refX="0"
+       refY="0"
+       orient="auto"
+       inkscape:stockid="Arrow2Lstart">
+      <path
+         transform="matrix(1.1,0,0,1.1,1.1,0)"
+         d="M 8.7185878,4.0337352 -2.2072895,0.01601326 8.7185884,-4.0017078 c -1.7454984,2.3720609 -1.7354408,5.6174519 -6e-7,8.035443 z"
+         style="fill:#000000;fill-opacity:1;fill-rule:evenodd;stroke:#000000;stroke-width:0.625;stroke-linejoin:round;stroke-opacity:1"
+         id="path22958-4-2"
+         inkscape:connector-curvature="0" />
+    </marker>
+    <marker
+       inkscape:isstock="true"
+       style="overflow:visible"
+       id="marker14793-1-58-1"
+       refX="0"
+       refY="0"
+       orient="auto"
+       inkscape:stockid="Arrow2Lend">
+      <path
+         inkscape:connector-curvature="0"
+         transform="matrix(-1.1,0,0,-1.1,-1.1,0)"
+         d="M 8.7185878,4.0337352 -2.2072895,0.01601326 8.7185884,-4.0017078 c -1.7454984,2.3720609 -1.7354408,5.6174519 -6e-7,8.035443 z"
+         style="fill:#000000;fill-opacity:1;fill-rule:evenodd;stroke:#000000;stroke-width:0.625;stroke-linejoin:round;stroke-opacity:1"
+         id="path14791-4-2-7" />
+    </marker>
+  </defs>
+  <sodipodi:namedview
+     id="base"
+     pagecolor="#ffffff"
+     bordercolor="#666666"
+     borderopacity="1.0"
+     inkscape:pageopacity="0.0"
+     inkscape:pageshadow="2"
+     inkscape:zoom="0.9899495"
+     inkscape:cx="-70.466635"
+     inkscape:cy="186.07323"
+     inkscape:document-units="mm"
+     inkscape:current-layer="layer4"
+     showgrid="false"
+     inkscape:window-width="1366"
+     inkscape:window-height="664"
+     inkscape:window-x="-8"
+     inkscape:window-y="1016"
+     inkscape:window-maximized="1"
+     fit-margin-top="0"
+     fit-margin-left="0"
+     fit-margin-right="0"
+     fit-margin-bottom="0"
+     viewbox-x="0"
+     scale-x="1" />
+  <metadata
+     id="metadata4743">
+    <rdf:RDF>
+      <cc:Work
+         rdf:about="">
+        <dc:format>image/svg+xml</dc:format>
+        <dc:type
+           rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
+        <dc:title />
+      </cc:Work>
+    </rdf:RDF>
+  </metadata>
+  <g
+     inkscape:label="host"
+     inkscape:groupmode="layer"
+     id="layer1"
+     style="display:inline;opacity:0.98999999"
+     transform="translate(22.342263,-42.641668)">
+    <rect
+       style="fill:#ffffff;fill-opacity:1;stroke:#000000;stroke-width:0.36492524;stroke-miterlimit:4;stroke-dasharray:none"
+       id="rect5291"
+       width="133.45515"
+       height="117.74038"
+       x="16.725571"
+       y="43.951878"
+       ry="0" />
+    <text
+       xml:space="preserve"
+       style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:4.76249981px;line-height:1.25;font-family:sans-serif;-inkscape-font-specification:'sans-serif, Normal';font-variant-ligatures:normal;font-variant-caps:normal;font-variant-numeric:normal;font-feature-settings:normal;text-align:start;letter-spacing:0px;word-spacing:0px;writing-mode:lr-tb;text-anchor:start;fill:#000000;fill-opacity:1;stroke:none;stroke-width:0.19843748"
+       x="17.927746"
+       y="48.597805"
+       id="text5577"><tspan
+         sodipodi:role="line"
+         id="tspan5575"
+         x="17.927746"
+         y="48.597805"
+         style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:4.76249981px;font-family:sans-serif;-inkscape-font-specification:'sans-serif, Normal';font-variant-ligatures:normal;font-variant-caps:normal;font-variant-numeric:normal;font-feature-settings:normal;text-align:start;writing-mode:lr-tb;text-anchor:start;stroke-width:0.19843748">host1</tspan></text>
+    <flowRoot
+       xml:space="preserve"
+       id="flowRoot5610"
+       style="font-style:normal;font-weight:normal;font-size:40px;line-height:1.25;font-family:sans-serif;letter-spacing:0px;word-spacing:0px;fill:#000000;fill-opacity:1;stroke:none"
+       transform="scale(0.26458333)"><flowRegion
+         id="flowRegion5612"><rect
+           id="rect5614"
+           width="12.857142"
+           height="94.285713"
+           x="147.14285"
+           y="89.662544" /></flowRegion><flowPara
+         id="flowPara5616" /></flowRoot>    <rect
+       style="opacity:1;fill:#ffff00;fill-opacity:1;stroke:#000000;stroke-width:0.11811945;stroke-miterlimit:4;stroke-dasharray:none"
+       id="rect1139-1-3"
+       width="9.2134848"
+       height="16.567875"
+       x="16.552696"
+       y="70.891708" />
+    <text
+       xml:space="preserve"
+       style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:3.70416665px;line-height:1.25;font-family:sans-serif;-inkscape-font-specification:'sans-serif, Normal';font-variant-ligatures:normal;font-variant-caps:normal;font-variant-numeric:normal;font-feature-settings:normal;text-align:start;letter-spacing:0px;word-spacing:0px;writing-mode:lr-tb;text-anchor:start;fill:#000000;fill-opacity:1;stroke:none;stroke-width:0.19843748"
+       x="16.618973"
+       y="74.613152"
+       id="text2024-9-4-2"><tspan
+         sodipodi:role="line"
+         id="tspan14621"
+         x="16.618973"
+         y="74.613152">NIC0</tspan></text>
+    <rect
+       style="display:inline;opacity:0.98999999;fill:#ffffff;fill-opacity:1;stroke:#000000;stroke-width:0.36500001;stroke-miterlimit:4;stroke-dasharray:none"
+       id="rect5291-0"
+       width="27.28093"
+       height="119.00851"
+       x="-21.550173"
+       y="43.577824"
+       ry="0" />
+    <rect
+       style="display:inline;opacity:1;fill:#ffff00;fill-opacity:1;stroke:#000000;stroke-width:0.11811945;stroke-miterlimit:4;stroke-dasharray:none"
+       id="rect1139-1-3-3"
+       width="9.2134848"
+       height="16.567875"
+       x="16.552696"
+       y="123.30804" />
+    <text
+       xml:space="preserve"
+       style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:3.70416665px;line-height:1.25;font-family:sans-serif;-inkscape-font-specification:'sans-serif, Normal';font-variant-ligatures:normal;font-variant-caps:normal;font-variant-numeric:normal;font-feature-settings:normal;text-align:start;letter-spacing:0px;word-spacing:0px;writing-mode:lr-tb;text-anchor:start;display:inline;opacity:0.98999999;fill:#000000;fill-opacity:1;stroke:none;stroke-width:0.19843748"
+       x="17.14814"
+       y="127.02951"
+       id="text2024-9-4-2-0"><tspan
+         sodipodi:role="line"
+         id="tspan14623"
+         x="17.14814"
+         y="127.02951">NIC1</tspan></text>
+    <text
+       xml:space="preserve"
+       style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:4.76249981px;line-height:1.25;font-family:sans-serif;-inkscape-font-specification:'sans-serif, Normal';font-variant-ligatures:normal;font-variant-caps:normal;font-variant-numeric:normal;font-feature-settings:normal;text-align:start;letter-spacing:0px;word-spacing:0px;writing-mode:lr-tb;text-anchor:start;display:inline;opacity:0.98999999;fill:#000000;fill-opacity:1;stroke:none;stroke-width:0.19843748"
+       x="-20.979584"
+       y="47.929138"
+       id="text5577-5"><tspan
+         sodipodi:role="line"
+         id="tspan1631"
+         x="-20.979584"
+         y="47.929138">host2</tspan></text>
+    <rect
+       style="display:inline;opacity:1;fill:#ffff00;fill-opacity:1;stroke:#000000;stroke-width:0.11811945;stroke-miterlimit:4;stroke-dasharray:none"
+       id="rect1139-1-3-2"
+       width="9.2134848"
+       height="16.567875"
+       x="-3.440033"
+       y="70.738869" />
+    <text
+       xml:space="preserve"
+       style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:3.70416665px;line-height:1.25;font-family:sans-serif;-inkscape-font-specification:'sans-serif, Normal';font-variant-ligatures:normal;font-variant-caps:normal;font-variant-numeric:normal;font-feature-settings:normal;text-align:start;letter-spacing:0px;word-spacing:0px;writing-mode:lr-tb;text-anchor:start;display:inline;opacity:0.98999999;fill:#000000;fill-opacity:1;stroke:none;stroke-width:0.19843748"
+       x="-3.3737564"
+       y="74.460312"
+       id="text2024-9-4-2-4"><tspan
+         sodipodi:role="line"
+         id="tspan1637"
+         x="-3.3737564"
+         y="74.460312">NIC2</tspan></text>
+    <rect
+       style="display:inline;opacity:1;fill:#ffff00;fill-opacity:1;stroke:#000000;stroke-width:0.11811945;stroke-miterlimit:4;stroke-dasharray:none"
+       id="rect1139-1-3-3-5"
+       width="9.2134848"
+       height="16.567875"
+       x="-3.440033"
+       y="123.15519" />
+    <text
+       xml:space="preserve"
+       style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:3.70416665px;line-height:1.25;font-family:sans-serif;-inkscape-font-specification:'sans-serif, Normal';font-variant-ligatures:normal;font-variant-caps:normal;font-variant-numeric:normal;font-feature-settings:normal;text-align:start;letter-spacing:0px;word-spacing:0px;writing-mode:lr-tb;text-anchor:start;display:inline;opacity:0.98999999;fill:#000000;fill-opacity:1;stroke:none;stroke-width:0.19843748"
+       x="-2.8445892"
+       y="126.87669"
+       id="text2024-9-4-2-0-7"><tspan
+         sodipodi:role="line"
+         id="tspan1639"
+         x="-2.8445892"
+         y="126.87669">NIC3</tspan></text>
+    <path
+       style="fill:none;stroke:#000000;stroke-width:0.241;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1;marker-end:url(#marker23218)"
+       d="M 5.7734517,74.443035 C 16.552696,74.595877 16.552696,74.595877 16.552696,74.595877"
+       id="path23208"
+       inkscape:connector-curvature="0" />
+    <path
+       style="display:inline;opacity:0.98999999;fill:none;stroke:#000000;stroke-width:0.241;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1;marker-end:url(#marker23218-3)"
+       d="m 5.7734518,126.85937 c 10.7792452,0.15284 10.7792452,0.15284 10.7792452,0.15284"
+       id="path23208-4"
+       inkscape:connector-curvature="0" />
+    <path
+       style="display:inline;opacity:0.98999999;fill:none;stroke:#000000;stroke-width:0.241;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1;marker-start:url(#marker26505)"
+       d="M 5.6749747,83.522821 C 16.454217,83.675663 16.454217,83.675663 16.454217,83.675663"
+       id="path23208-9"
+       inkscape:connector-curvature="0" />
+    <path
+       style="display:inline;opacity:0.98999999;fill:none;stroke:#000000;stroke-width:0.241;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1;marker-start:url(#marker25907)"
+       d="m 5.6749757,135.93924 c 10.7792423,0.15285 10.7792423,0.15285 10.7792423,0.15285"
+       id="path23208-4-9"
+       inkscape:connector-curvature="0" />
+    <path
+       style="fill:none;stroke:#000000;stroke-width:0.241;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;stroke-miterlimit:4;stroke-dasharray:none;marker-end:url(#marker39126)"
+       d="m -3.6681555,136.09531 c 0,0 -10.1562395,-0.68662 -11.4925875,-13.73235"
+       id="path39116"
+       inkscape:connector-curvature="0" />
+  </g>
+  <g
+     inkscape:groupmode="layer"
+     id="layer3"
+     inkscape:label="spp_vf_process"
+     style="display:none"
+     transform="translate(22.342263,-42.641668)">
+    <rect
+       style="fill:#ffccaa;fill-opacity:1;stroke:#000000;stroke-width:0.16642947;stroke-miterlimit:4;stroke-dasharray:none"
+       id="rect1763"
+       width="59.980141"
+       height="46.595516"
+       x="28.250807"
+       y="56.22039"
+       ry="2.4291499" />
+    <text
+       xml:space="preserve"
+       style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:3.70416665px;line-height:1.25;font-family:sans-serif;-inkscape-font-specification:'sans-serif, Normal';font-variant-ligatures:normal;font-variant-caps:normal;font-variant-numeric:normal;font-feature-settings:normal;text-align:start;letter-spacing:0px;word-spacing:0px;writing-mode:lr-tb;text-anchor:start;fill:#000000;fill-opacity:1;stroke:none;stroke-width:0.19843748"
+       x="31.005722"
+       y="61.07103"
+       id="text1767"><tspan
+         sodipodi:role="line"
+         id="tspan10724"
+         x="31.005722"
+         y="61.07103">spp_vf1</tspan></text>
+    <rect
+       style="display:inline;opacity:0.98999999;fill:#ffccaa;fill-opacity:1;stroke:#000000;stroke-width:0.16642947;stroke-miterlimit:4;stroke-dasharray:none"
+       id="rect1763-1"
+       width="59.980141"
+       height="46.595516"
+       x="28.250807"
+       y="108.63673"
+       ry="2.4291499" />
+    <text
+       xml:space="preserve"
+       style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:3.70416665px;line-height:1.25;font-family:sans-serif;-inkscape-font-specification:'sans-serif, Normal';font-variant-ligatures:normal;font-variant-caps:normal;font-variant-numeric:normal;font-feature-settings:normal;text-align:start;letter-spacing:0px;word-spacing:0px;writing-mode:lr-tb;text-anchor:start;display:inline;opacity:0.98999999;fill:#000000;fill-opacity:1;stroke:none;stroke-width:0.19843748"
+       x="31.005724"
+       y="113.48738"
+       id="text1767-1"><tspan
+         sodipodi:role="line"
+         id="tspan14625"
+         x="31.005724"
+         y="113.48738">spp_vf2</tspan></text>
+  </g>
+  <g
+     inkscape:groupmode="layer"
+     id="layer4"
+     inkscape:label="guests"
+     style="display:inline"
+     transform="translate(22.342263,-42.641668)">
+    <path
+       style="fill:none;stroke:#000000;stroke-width:0.241;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1;marker-end:url(#marker34720)"
+       d="m -10.45306,119.21565 c -0.07257,7.78267 6.0943783,7.4034 6.0943783,7.4034"
+       id="path34710"
+       inkscape:connector-curvature="0" />
+    <rect
+       style="display:inline;fill:#d7eef4;stroke:#000000;stroke-width:0.28149092;stroke-miterlimit:4;stroke-dasharray:none"
+       id="rect13971-3"
+       width="32.50581"
+       height="53.967125"
+       x="113.9224"
+       y="104.36536"
+       ry="1.690876" />
+    <rect
+       style="display:inline;fill:#ffd5d5;stroke:#000000;stroke-width:0.12;stroke-miterlimit:4;stroke-dasharray:none"
+       id="rect4404-9"
+       width="13.307772"
+       height="40.352818"
+       x="131.26602"
+       y="111.62362"
+       ry="2.7388608" />
+    <text
+       xml:space="preserve"
+       style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:3.70416665px;line-height:1.25;font-family:sans-serif;-inkscape-font-specification:'sans-serif, Normal';font-variant-ligatures:normal;font-variant-caps:normal;font-variant-numeric:normal;font-feature-settings:normal;text-align:center;letter-spacing:0px;word-spacing:0px;writing-mode:lr-tb;text-anchor:middle;display:inline;opacity:0.98999999;fill:#000000;fill-opacity:1;stroke:none;stroke-width:0.21267372"
+       x="147.38239"
+       y="121.55878"
+       id="text1773-6-6-5-2-58-9"
+       transform="scale(0.93214045,1.0727997)"><tspan
+         style="stroke-width:0.21267372"
+         sodipodi:role="line"
+         id="tspan4393-3"
+         x="147.38239"
+         y="121.55878">ssh</tspan><tspan
+         style="stroke-width:0.21267372"
+         sodipodi:role="line"
+         id="tspan4395-1"
+         x="147.38239"
+         y="126.18899">server</tspan></text>
+    <rect
+       style="fill:#d7eef4;stroke:#000000;stroke-width:0.28033611;stroke-miterlimit:4;stroke-dasharray:none"
+       id="rect13971"
+       width="32.239651"
+       height="53.967121"
+       x="114.18855"
+       y="47.752419"
+       ry="1.6908759" />
+    <text
+       xml:space="preserve"
+       style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:3.70416665px;line-height:1.25;font-family:sans-serif;-inkscape-font-specification:'sans-serif, Normal';font-variant-ligatures:normal;font-variant-caps:normal;font-variant-numeric:normal;font-feature-settings:normal;text-align:start;letter-spacing:0px;word-spacing:0px;writing-mode:lr-tb;text-anchor:start;fill:#000000;fill-opacity:1;stroke:none;stroke-width:0.19843748"
+       x="114.9353"
+       y="51.130241"
+       id="text2024"><tspan
+         sodipodi:role="line"
+         id="tspan4579"
+         x="114.9353"
+         y="51.130241">guest vm1</tspan></text>
+    <text
+       xml:space="preserve"
+       style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:3.70416665px;line-height:1.25;font-family:sans-serif;-inkscape-font-specification:'sans-serif, Normal';font-variant-ligatures:normal;font-variant-caps:normal;font-variant-numeric:normal;font-feature-settings:normal;text-align:start;letter-spacing:0px;word-spacing:0px;writing-mode:lr-tb;text-anchor:start;fill:#000000;fill-opacity:1;stroke:none;stroke-width:0.19843748"
+       x="114.67667"
+       y="107.6647"
+       id="text2024-5"><tspan
+         sodipodi:role="line"
+         id="tspan4581"
+         x="114.67667"
+         y="107.6647">guest vm2</tspan></text>
+    <rect
+       style="fill:#ffd5d5;stroke:#000000;stroke-width:0.12;stroke-miterlimit:4;stroke-dasharray:none"
+       id="rect4404"
+       width="13.307771"
+       height="40.352818"
+       x="131.26602"
+       y="58.185673"
+       ry="2.7388606" />
+    <text
+       xml:space="preserve"
+       style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:3.70416665px;line-height:1.25;font-family:sans-serif;-inkscape-font-specification:'sans-serif, Normal';font-variant-ligatures:normal;font-variant-caps:normal;font-variant-numeric:normal;font-feature-settings:normal;text-align:center;letter-spacing:0px;word-spacing:0px;writing-mode:lr-tb;text-anchor:middle;display:inline;opacity:0.98999999;fill:#000000;fill-opacity:1;stroke:none;stroke-width:0.21267372"
+       x="147.3824"
+       y="69.774078"
+       id="text1773-6-6-5-2-58"
+       transform="scale(0.93214045,1.0727997)"><tspan
+         sodipodi:role="line"
+         id="tspan4393"
+         x="147.3824"
+         y="69.774078">ssh</tspan><tspan
+         sodipodi:role="line"
+         id="tspan4395"
+         x="147.3824"
+         y="74.404289">server</tspan></text>
+    <path
+       style="display:inline;opacity:0.98999999;fill:none;stroke:#000000;stroke-width:0.241;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1;marker-start:url(#marker22960-56)"
+       d="m 126.21074,94.634296 c 4.95896,0 4.95896,0 4.95896,0"
+       id="path14783-8-29"
+       inkscape:connector-curvature="0" />
+    <path
+       style="display:inline;opacity:0.98999999;fill:none;stroke:#000000;stroke-width:0.241;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1;marker-end:url(#marker14793-1-58)"
+       d="m 124.88059,88.334466 c 6.21402,0 6.21402,0 6.21402,0"
+       id="path14783-87-4"
+       inkscape:connector-curvature="0" />
+    <path
+       style="display:inline;opacity:0.98999999;fill:none;stroke:#000000;stroke-width:0.241;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1;marker-start:url(#marker22960-97-3)"
+       d="m 125.86595,147.37137 c 4.95896,0 4.95896,0 4.95896,0"
+       id="path14783-8-2-5"
+       inkscape:connector-curvature="0" />
+    <path
+       style="display:inline;opacity:0.98999999;fill:none;stroke:#000000;stroke-width:0.241;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1;marker-end:url(#marker14793-1-5-9)"
+       d="m 124.5358,141.07155 c 6.21402,0 6.21402,0 6.21402,0"
+       id="path14783-87-0-5"
+       inkscape:connector-curvature="0" />
+    <rect
+       style="display:inline;opacity:1;fill:#ffff00;fill-opacity:1;stroke:#000000;stroke-width:0.11848791;stroke-miterlimit:4;stroke-dasharray:none"
+       id="rect1139-7"
+       width="11.678429"
+       height="13.152599"
+       x="114.16298"
+       y="84.577766" />
+    <text
+       xml:space="preserve"
+       style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:3.70416665px;line-height:1.25;font-family:sans-serif;-inkscape-font-specification:'sans-serif, Normal';font-variant-ligatures:normal;font-variant-caps:normal;font-variant-numeric:normal;font-feature-settings:normal;text-align:start;letter-spacing:0px;word-spacing:0px;writing-mode:lr-tb;text-anchor:start;display:inline;fill:#000000;fill-opacity:1;stroke:none;stroke-width:0.19843748"
+       x="114.97461"
+       y="88.269478"
+       id="text2024-9-0"><tspan
+         sodipodi:role="line"
+         id="tspan1641"
+         x="114.97461"
+         y="88.269478">vNIC1</tspan></text>
+    <rect
+       style="display:inline;opacity:1;fill:#ffff00;fill-opacity:1;stroke:#000000;stroke-width:0.12118802;stroke-miterlimit:4;stroke-dasharray:none"
+       id="rect1139-1-6"
+       width="11.9492"
+       height="13.44709"
+       x="113.9498"
+       y="137.55743" />
+    <text
+       xml:space="preserve"
+       style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:3.70416665px;line-height:1.25;font-family:sans-serif;-inkscape-font-specification:'sans-serif, Normal';font-variant-ligatures:normal;font-variant-caps:normal;font-variant-numeric:normal;font-feature-settings:normal;text-align:start;letter-spacing:0px;word-spacing:0px;writing-mode:lr-tb;text-anchor:start;display:inline;opacity:0.98999999;fill:#000000;fill-opacity:1;stroke:none;stroke-width:0.19843748"
+       x="114.03404"
+       y="141.20172"
+       id="text2024-9-4-29"><tspan
+         sodipodi:role="line"
+         id="tspan1647"
+         x="114.03404"
+         y="141.20172">vNIC3</tspan></text>
+    <path
+       style="display:inline;opacity:0.98999999;fill:none;stroke:#000000;stroke-width:0.241;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1;marker-start:url(#marker22960-56-0)"
+       d="m 126.28635,68.674988 c 4.95896,0 4.95896,0 4.95896,0"
+       id="path14783-8-29-4"
+       inkscape:connector-curvature="0" />
+    <path
+       style="display:inline;opacity:0.98999999;fill:none;stroke:#000000;stroke-width:0.241;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1;marker-end:url(#marker14793-1-58-1)"
+       d="m 124.9562,62.375158 c 6.21402,0 6.21402,0 6.21402,0"
+       id="path14783-87-4-3"
+       inkscape:connector-curvature="0" />
+    <path
+       style="display:inline;opacity:0.98999999;fill:none;stroke:#000000;stroke-width:0.241;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1;marker-start:url(#marker22960-97-3-5)"
+       d="m 125.94156,121.41205 c 4.95896,0 4.95896,0 4.95896,0"
+       id="path14783-8-2-5-7"
+       inkscape:connector-curvature="0" />
+    <path
+       style="display:inline;opacity:0.98999999;fill:none;stroke:#000000;stroke-width:0.241;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1;marker-end:url(#marker14793-1-5-9-1)"
+       d="m 124.61141,115.11223 c 6.21402,0 6.21402,0 6.21402,0"
+       id="path14783-87-0-5-1"
+       inkscape:connector-curvature="0" />
+    <rect
+       style="opacity:1;fill:#ffff00;fill-opacity:1;stroke:#000000;stroke-width:0.1198233;stroke-miterlimit:4;stroke-dasharray:none"
+       id="rect1139"
+       width="11.944364"
+       height="13.151264"
+       x="114.19665"
+       y="59.255657" />
+    <text
+       xml:space="preserve"
+       style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:3.70416665px;line-height:1.25;font-family:sans-serif;-inkscape-font-specification:'sans-serif, Normal';font-variant-ligatures:normal;font-variant-caps:normal;font-variant-numeric:normal;font-feature-settings:normal;text-align:start;letter-spacing:0px;word-spacing:0px;writing-mode:lr-tb;text-anchor:start;fill:#000000;fill-opacity:1;stroke:none;stroke-width:0.19843748"
+       x="114.70798"
+       y="62.946693"
+       id="text2024-9"><tspan
+         sodipodi:role="line"
+         id="tspan1643"
+         x="114.70798"
+         y="62.946693">vNIC0</tspan></text>
+    <rect
+       style="display:inline;opacity:1;fill:#ffff00;fill-opacity:1;stroke:#000000;stroke-width:0.11983798;stroke-miterlimit:4;stroke-dasharray:none"
+       id="rect1139-1-6-8"
+       width="11.683282"
+       height="13.448441"
+       x="114.04266"
+       y="111.84875" />
+    <text
+       xml:space="preserve"
+       style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:3.70416665px;line-height:1.25;font-family:sans-serif;-inkscape-font-specification:'sans-serif, Normal';font-variant-ligatures:normal;font-variant-caps:normal;font-variant-numeric:normal;font-feature-settings:normal;text-align:start;letter-spacing:0px;word-spacing:0px;writing-mode:lr-tb;text-anchor:start;display:inline;opacity:0.98999999;fill:#000000;fill-opacity:1;stroke:none;stroke-width:0.19843748"
+       x="114.48937"
+       y="115.23184"
+       id="text2024-9-4-29-8"><tspan
+         sodipodi:role="line"
+         id="tspan1645"
+         x="114.48937"
+         y="115.23184">vNIC2</tspan></text>
+    <rect
+       style="display:inline;fill:#ffd5d5;stroke:#000000;stroke-width:0.120654;stroke-miterlimit:4;stroke-dasharray:none"
+       id="rect4404-9-5"
+       width="16.770006"
+       height="32.371811"
+       x="-20.445839"
+       y="89.455406"
+       ry="2.1971672" />
+    <text
+       xml:space="preserve"
+       style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:3.70416668px;line-height:1.25;font-family:sans-serif;-inkscape-font-specification:'sans-serif, Normal';font-variant-ligatures:normal;font-variant-caps:normal;font-variant-numeric:normal;font-feature-settings:normal;text-align:center;letter-spacing:0px;word-spacing:0px;writing-mode:lr;text-anchor:middle;display:inline;opacity:0.98999999;fill:#000000;fill-opacity:1;stroke:none;stroke-width:0.21267372;"
+       x="-13.677567"
+       y="97.412262"
+       id="text1773-6-6-5-2-58-9-7"
+       transform="scale(0.93214045,1.0727997)"><tspan
+         sodipodi:role="line"
+         id="tspan1763">ssh </tspan><tspan
+         sodipodi:role="line"
+         id="tspan1765">client</tspan></text>
+    <path
+       style="fill:none;stroke:#000000;stroke-width:0.241;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1;marker-end:url(#marker1654)"
+       d="M -15.835612,89.669972 C -12.488463,79.248516 -3.440033,74.972204 -3.440033,74.972204"
+       id="path32594"
+       inkscape:connector-curvature="0" />
+    <path
+       style="fill:none;stroke:#000000;stroke-width:0.241;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1;marker-end:url(#marker32792)"
+       d="m -3.440033,83.602577 c 0,0 -5.87993,0.801807 -6.147199,5.879927"
+       id="path32782"
+       inkscape:connector-curvature="0" />
+  </g>
+  <g
+     inkscape:groupmode="layer"
+     id="layer2"
+     inkscape:label="spp_vf_threads"
+     style="display:inline;opacity:0.98999999"
+     transform="translate(22.342263,-42.641668)">
+    <path
+       style="fill:none;stroke:#000000;stroke-width:0.241;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1;marker-end:url(#marker16375)"
+       d="m 99.555055,147.04032 c -12.85119,0 -12.85119,0 -12.85119,0"
+       id="path16365"
+       inkscape:connector-curvature="0" />
+    <path
+       style="fill:none;stroke:#000000;stroke-width:0.241;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1;marker-end:url(#marker9721)"
+       d="M 100.21858,69.679628 C 86.806132,84.847397 86.806132,84.847397 86.806132,84.847397"
+       id="path9711"
+       inkscape:connector-curvature="0" />
+    <path
+       style="fill:none;stroke:#000000;stroke-width:0.241;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1;marker-end:url(#marker6789)"
+       d="M 85.793887,62.025084 C 99.160248,61.917299 99.160248,61.917299 99.160248,61.917299"
+       id="path6779"
+       inkscape:connector-curvature="0" />
+    <path
+       style="display:inline;opacity:0.98999999;fill:none;stroke:#000000;stroke-width:0.241;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1;marker-end:url(#marker16657-7)"
+       d="m 51.850553,120.88419 c 13.503428,-6.62315 13.503428,-6.62315 13.503428,-6.62315"
+       id="path16647-0"
+       inkscape:connector-curvature="0" />
+    <path
+       style="display:inline;opacity:0.98999999;fill:none;stroke:#000000;stroke-width:0.241;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1;marker-end:url(#marker17252-3)"
+       d="m 51.850553,121.94252 c 13.523669,4.97261 13.523669,4.97261 13.523669,4.97261"
+       id="path17242-1"
+       inkscape:connector-curvature="0" />
+    <path
+       style="display:inline;opacity:0.98999999;fill:none;stroke:#000000;stroke-width:0.241;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1;marker-start:url(#marker9343-4)"
+       d="m 49.558914,142.12156 c 15.9854,-4.67979 15.9854,-4.67979 15.9854,-4.67979 v 0"
+       id="path17770-7"
+       inkscape:connector-curvature="0" />
+    <path
+       style="display:inline;opacity:0.98999999;fill:none;stroke:#000000;stroke-width:0.241;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1;marker-end:url(#marker17872-8)"
+       d="m 65.827792,148.15468 c -16.268878,-5.1529 -16.268878,-5.1529 -16.268878,-5.1529"
+       id="path17862-4"
+       inkscape:connector-curvature="0" />
+    <path
+       style="display:inline;fill:none;stroke:#000000;stroke-width:0.241;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1;marker-end:url(#marker16657)"
+       d="M 51.850549,68.289813 C 65.353977,61.666664 65.353977,61.666664 65.353977,61.666664"
+       id="path16647"
+       inkscape:connector-curvature="0" />
+    <path
+       style="display:inline;fill:none;stroke:#000000;stroke-width:0.241;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1;marker-start:url(#marker22960)"
+       d="m 109.21487,94.404527 c 4.95896,0 4.95896,0 4.95896,0"
+       id="path14783-8"
+       inkscape:connector-curvature="0" />
+    <rect
+       style="fill:#ffe6d5;fill-opacity:1;stroke:#000000;stroke-width:0.13431512;stroke-miterlimit:4;stroke-dasharray:none"
+       id="rect1769"
+       width="21.297846"
+       height="5.9898095"
+       x="30.552704"
+       y="66.004173"
+       ry="1.3525398" />
+    <text
+       xml:space="preserve"
+       style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:3.70416689px;line-height:1.25;font-family:sans-serif;-inkscape-font-specification:'sans-serif, Normal';font-variant-ligatures:normal;font-variant-caps:normal;font-variant-numeric:normal;font-feature-settings:normal;text-align:start;letter-spacing:0px;word-spacing:0px;writing-mode:lr-tb;text-anchor:start;fill:#000000;fill-opacity:1;stroke:none;stroke-width:0.19843748"
+       x="33.065685"
+       y="69.991264"
+       id="text1773"><tspan
+         sodipodi:role="line"
+         id="tspan1461"
+         x="33.065685"
+         y="69.991264"
+         style="stroke-width:0.19843748">classifier</tspan></text>
+    <path
+       style="fill:none;stroke:#000000;stroke-width:0.241;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1;marker-end:url(#marker14793)"
+       d="m 109.2058,62.342026 c 4.20592,0 4.20592,0 4.20592,0"
+       id="path14783"
+       inkscape:connector-curvature="0" />
+    <path
+       style="display:inline;fill:none;stroke:#000000;stroke-width:0.241;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1;marker-end:url(#marker14793-1)"
+       d="m 107.88472,88.1047 c 6.21402,0 6.21402,0 6.21402,0"
+       id="path14783-87"
+       inkscape:connector-curvature="0" />
+    <path
+       style="display:inline;fill:none;stroke:#000000;stroke-width:0.241;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1;marker-start:url(#marker22960-5)"
+       d="m 109.42079,68.64875 c 4.20592,0 4.20592,0 4.20592,0"
+       id="path14783-8-7"
+       inkscape:connector-curvature="0" />
+    <path
+       style="fill:none;stroke:#000000;stroke-width:0.24075001;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1;marker-end:url(#marker1560)"
+       d="m 100.74232,62.375041 c 6.66184,0 6.66184,0 6.66184,0"
+       id="path1556"
+       inkscape:connector-curvature="0" />
+    <rect
+       style="fill:#ffe6d5;fill-opacity:1;stroke:#000000;stroke-width:0.12518337;stroke-miterlimit:4;stroke-dasharray:none"
+       id="rect1769-3"
+       width="18.472155"
+       height="5.9989409"
+       x="31.086758"
+       y="86.703247"
+       ry="1.3546017" />
+    <text
+       xml:space="preserve"
+       style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:3.70416689px;line-height:1.25;font-family:sans-serif;-inkscape-font-specification:'sans-serif, Normal';font-variant-ligatures:normal;font-variant-caps:normal;font-variant-numeric:normal;font-feature-settings:normal;text-align:start;letter-spacing:0px;word-spacing:0px;writing-mode:lr-tb;text-anchor:start;fill:#000000;fill-opacity:1;stroke:none;stroke-width:0.19843748"
+       x="33.207432"
+       y="90.827194"
+       id="text1773-6"><tspan
+         sodipodi:role="line"
+         id="tspan1463"
+         x="33.207432"
+         y="90.827194"
+         style="stroke-width:0.19843748">merger</tspan></text>
+    <g
+       id="g2295"
+       transform="matrix(0.75,0,0,0.75,-14.653803,40.613879)">
+      <rect
+         ry="1.8039205"
+         y="25.020494"
+         x="106.67704"
+         height="7.9887786"
+         width="27.643539"
+         id="rect1769-3-2"
+         style="fill:#ffe6d5;fill-opacity:1;stroke:#000000;stroke-width:0.17672074;stroke-miterlimit:4;stroke-dasharray:none" />
+      <text
+         id="text1773-6-6"
+         y="30.337786"
+         x="107.9122"
+         style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:4.93888903px;line-height:1.25;font-family:sans-serif;-inkscape-font-specification:'sans-serif, Normal';font-variant-ligatures:normal;font-variant-caps:normal;font-variant-numeric:normal;font-feature-settings:normal;text-align:start;letter-spacing:0px;word-spacing:0px;writing-mode:lr-tb;text-anchor:start;fill:#000000;fill-opacity:1;stroke:none;stroke-width:0.26458332"
+         xml:space="preserve"><tspan
+           id="tspan3024"
+           sodipodi:role="line"
+           x="107.9122"
+           y="30.337786">forwarder</tspan></text>
+    </g>
+    <g
+       transform="matrix(0.75,0,0,0.75,-14.463468,63.265443)"
+       style="display:inline"
+       id="g2295-3">
+      <rect
+         ry="1.8039205"
+         y="25.020494"
+         x="106.67704"
+         height="7.9887786"
+         width="27.643539"
+         id="rect1769-3-2-4"
+         style="fill:#ffe6d5;fill-opacity:1;stroke:#000000;stroke-width:0.17672074;stroke-miterlimit:4;stroke-dasharray:none" />
+      <text
+         id="text1773-6-6-0"
+         y="30.337786"
+         x="107.9122"
+         style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:4.93888903px;line-height:1.25;font-family:sans-serif;-inkscape-font-specification:'sans-serif, Normal';font-variant-ligatures:normal;font-variant-caps:normal;font-variant-numeric:normal;font-feature-settings:normal;text-align:start;letter-spacing:0px;word-spacing:0px;writing-mode:lr-tb;text-anchor:start;fill:#000000;fill-opacity:1;stroke:none;stroke-width:0.26458332"
+         xml:space="preserve"><tspan
+           id="tspan3024-5"
+           sodipodi:role="line"
+           x="107.9122"
+           y="30.337786">forwarder</tspan></text>
+    </g>
+    <g
+       transform="matrix(0.75,0,0,0.75,-14.633561,52.209642)"
+       style="display:inline"
+       id="g2295-5">
+      <rect
+         ry="1.8039205"
+         y="25.020494"
+         x="106.67704"
+         height="7.9887786"
+         width="27.643539"
+         id="rect1769-3-2-2"
+         style="fill:#ffe6d5;fill-opacity:1;stroke:#000000;stroke-width:0.17672074;stroke-miterlimit:4;stroke-dasharray:none" />
+      <text
+         id="text1773-6-6-6"
+         y="30.337786"
+         x="107.9122"
+         style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:4.93888903px;line-height:1.25;font-family:sans-serif;-inkscape-font-specification:'sans-serif, Normal';font-variant-ligatures:normal;font-variant-caps:normal;font-variant-numeric:normal;font-feature-settings:normal;text-align:start;letter-spacing:0px;word-spacing:0px;writing-mode:lr-tb;text-anchor:start;fill:#000000;fill-opacity:1;stroke:none;stroke-width:0.26458332"
+         xml:space="preserve"><tspan
+           id="tspan3024-9"
+           sodipodi:role="line"
+           x="107.9122"
+           y="30.337786">forwarder</tspan></text>
+    </g>
+    <g
+       transform="matrix(0.75,0,0,0.75,-14.179991,73.090775)"
+       style="display:inline"
+       id="g2295-0">
+      <rect
+         ry="1.8039205"
+         y="25.020494"
+         x="106.67704"
+         height="7.9887786"
+         width="27.643539"
+         id="rect1769-3-2-8"
+         style="fill:#ffe6d5;fill-opacity:1;stroke:#000000;stroke-width:0.17672074;stroke-miterlimit:4;stroke-dasharray:none" />
+      <text
+         id="text1773-6-6-8"
+         y="30.337786"
+         x="107.9122"
+         style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:4.93888903px;line-height:1.25;font-family:sans-serif;-inkscape-font-specification:'sans-serif, Normal';font-variant-ligatures:normal;font-variant-caps:normal;font-variant-numeric:normal;font-feature-settings:normal;text-align:start;letter-spacing:0px;word-spacing:0px;writing-mode:lr-tb;text-anchor:start;fill:#000000;fill-opacity:1;stroke:none;stroke-width:0.26458332"
+         xml:space="preserve"><tspan
+           id="tspan3024-96"
+           sodipodi:role="line"
+           x="107.9122"
+           y="30.337786">forwarder</tspan></text>
+    </g>
+    <g
+       id="g1969"
+       transform="matrix(0.52050337,0,0,1.6939167,34.865777,-148.27289)"
+       style="fill:#eef4d7">
+      <rect
+         ry="1.8106976"
+         y="122.52335"
+         x="124.54029"
+         height="8.0187912"
+         width="18.980101"
+         id="rect1769-3-2-7"
+         style="fill:#eef4d7;stroke:#000000;stroke-width:0.14670815;stroke-miterlimit:4;stroke-dasharray:none" />
+    </g>
+    <text
+       xml:space="preserve"
+       style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:3.70416689px;line-height:1.25;font-family:sans-serif;-inkscape-font-specification:'sans-serif, Normal';font-variant-ligatures:normal;font-variant-caps:normal;font-variant-numeric:normal;font-feature-settings:normal;text-align:start;letter-spacing:0px;word-spacing:0px;writing-mode:lr-tb;text-anchor:start;fill:#000000;fill-opacity:1;stroke:none;stroke-width:0.21267372"
+       x="106.97886"
+       y="62.639709"
+       id="text1773-6-6-5-2"
+       transform="scale(0.93214046,1.0727997)"><tspan
+         y="62.639709"
+         x="106.97886"
+         sodipodi:role="line"
+         id="tspan1964-1"
+         style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:3.70416689px;font-family:sans-serif;-inkscape-font-specification:'sans-serif, Normal';font-variant-ligatures:normal;font-variant-caps:normal;font-variant-numeric:normal;font-feature-settings:normal;text-align:start;writing-mode:lr-tb;text-anchor:start;stroke-width:0.21267372">vhost</tspan></text>
+    <g
+       id="g1263"
+       transform="matrix(0.75,0,0,0.75,-12.18121,-38.666051)">
+      <g
+         id="g2377-5-42"
+         style="display:inline;fill:#eef4d7"
+         transform="translate(-6.7279778,-3.9309553)">
+        <ellipse
+           style="display:inline;fill:#eef4d7;fill-opacity:1;stroke:#000000;stroke-width:0.35376999;stroke-miterlimit:4;stroke-dasharray:none"
+           id="path1780-3-7-12-8"
+           cx="100.0881"
+           cy="141.425"
+           rx="6.5516987"
+           ry="3.1499126"
+           inkscape:transform-center-x="13.229167"
+           inkscape:transform-center-y="-59.720238" />
+        <text
+           xml:space="preserve"
+           style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:4.93888903px;line-height:1.25;font-family:sans-serif;-inkscape-font-specification:'sans-serif, Normal';font-variant-ligatures:normal;font-variant-caps:normal;font-variant-numeric:normal;font-feature-settings:normal;text-align:start;letter-spacing:0px;word-spacing:0px;writing-mode:lr-tb;text-anchor:start;display:inline;fill:#eef4d7;fill-opacity:1;stroke:none;stroke-width:0.28356495"
+           x="102.67519"
+           y="132.96213"
+           id="text1773-6-6-5-2-7-4-3-60"
+           transform="scale(0.93214046,1.0727997)"><tspan
+             sodipodi:role="line"
+             id="tspan2372-8-0"
+             x="102.67519"
+             y="132.96213">ring</tspan></text>
+      </g>
+      <text
+         transform="scale(0.93214046,1.0727997)"
+         id="text1773-6-6-5-2-7-4-4-2"
+         y="129.157"
+         x="95.700722"
+         style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:4.93888903px;line-height:1.25;font-family:sans-serif;-inkscape-font-specification:'sans-serif, Normal';font-variant-ligatures:normal;font-variant-caps:normal;font-variant-numeric:normal;font-feature-settings:normal;text-align:start;letter-spacing:0px;word-spacing:0px;writing-mode:lr-tb;text-anchor:start;display:inline;fill:#000000;fill-opacity:1;stroke:none;stroke-width:0.28356495"
+         xml:space="preserve"><tspan
+           y="129.157"
+           x="95.700722"
+           id="tspan2372-2-3"
+           sodipodi:role="line">ring</tspan></text>
+    </g>
+    <path
+       style="display:inline;opacity:0.98999999;fill:none;stroke:#000000;stroke-width:0.24075003;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1;marker-end:url(#marker1560-1)"
+       d="m 100.69372,88.1047 c 6.66183,0 6.66183,0 6.66183,0"
+       id="path1556-4"
+       inkscape:connector-curvature="0" />
+    <g
+       id="g1969-8"
+       transform="matrix(0.52050336,0,0,1.6939167,34.817293,-122.54325)"
+       style="display:inline;opacity:0.98999999;fill:#eef4d7">
+      <rect
+         ry="1.8106976"
+         y="122.52335"
+         x="124.54029"
+         height="8.0187912"
+         width="18.980101"
+         id="rect1769-3-2-7-8"
+         style="fill:#eef4d7;stroke:#000000;stroke-width:0.14670815;stroke-miterlimit:4;stroke-dasharray:none" />
+    </g>
+    <text
+       xml:space="preserve"
+       style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:3.70416689px;line-height:1.25;font-family:sans-serif;-inkscape-font-specification:'sans-serif, Normal';font-variant-ligatures:normal;font-variant-caps:normal;font-variant-numeric:normal;font-feature-settings:normal;text-align:start;letter-spacing:0px;word-spacing:0px;writing-mode:lr-tb;text-anchor:start;display:inline;opacity:0.98999999;fill:#000000;fill-opacity:1;stroke:none;stroke-width:0.21267372"
+       x="107.12971"
+       y="86.447212"
+       id="text1773-6-6-5-2-3"
+       transform="scale(0.93214045,1.0727997)"><tspan
+         y="86.447212"
+         x="107.12971"
+         sodipodi:role="line"
+         id="tspan1964-1-9"
+         style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:3.70416689px;font-family:sans-serif;-inkscape-font-specification:'sans-serif, Normal';font-variant-ligatures:normal;font-variant-caps:normal;font-variant-numeric:normal;font-feature-settings:normal;text-align:start;writing-mode:lr-tb;text-anchor:start;stroke-width:0.21267372">vhost</tspan></text>
+    <path
+       style="display:inline;opacity:0.98999999;fill:none;stroke:#000000;stroke-width:0.241;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1;marker-start:url(#marker22960-97)"
+       d="m 108.87008,147.14161 c 4.95896,0 4.95896,0 4.95896,0"
+       id="path14783-8-2"
+       inkscape:connector-curvature="0" />
+    <path
+       style="display:inline;opacity:0.98999999;fill:none;stroke:#000000;stroke-width:0.241;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1;marker-end:url(#marker14793-1-5)"
+       d="m 107.53993,140.84179 c 6.21402,0 6.21402,0 6.21402,0"
+       id="path14783-87-0"
+       inkscape:connector-curvature="0" />
+    <path
+       style="display:inline;opacity:0.98999999;fill:none;stroke:#000000;stroke-width:0.24075004;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1;marker-end:url(#marker1560-1-3)"
+       d="m 100.34893,140.84179 c 6.66183,0 6.66183,0 6.66183,0"
+       id="path1556-4-6"
+       inkscape:connector-curvature="0" />
+    <g
+       id="g1969-8-0"
+       transform="matrix(0.52050336,0,0,1.6939167,34.472523,-69.806185)"
+       style="display:inline;opacity:0.98999999;fill:#eef4d7">
+      <rect
+         ry="1.8106976"
+         y="122.52335"
+         x="124.54029"
+         height="8.0187912"
+         width="18.980101"
+         id="rect1769-3-2-7-8-0"
+         style="fill:#eef4d7;stroke:#000000;stroke-width:0.14670815;stroke-miterlimit:4;stroke-dasharray:none" />
+    </g>
+    <text
+       xml:space="preserve"
+       style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:3.70416689px;line-height:1.25;font-family:sans-serif;-inkscape-font-specification:'sans-serif, Normal';font-variant-ligatures:normal;font-variant-caps:normal;font-variant-numeric:normal;font-feature-settings:normal;text-align:start;letter-spacing:0px;word-spacing:0px;writing-mode:lr-tb;text-anchor:start;display:inline;opacity:0.98999999;fill:#000000;fill-opacity:1;stroke:none;stroke-width:0.21267372"
+       x="106.75986"
+       y="135.60555"
+       id="text1773-6-6-5-2-3-0"
+       transform="scale(0.93214045,1.0727997)"><tspan
+         y="135.60555"
+         x="106.75986"
+         sodipodi:role="line"
+         id="tspan1964-1-9-1"
+         style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:3.70416689px;font-family:sans-serif;-inkscape-font-specification:'sans-serif, Normal';font-variant-ligatures:normal;font-variant-caps:normal;font-variant-numeric:normal;font-feature-settings:normal;text-align:start;writing-mode:lr-tb;text-anchor:start;stroke-width:0.21267372">vhost</tspan></text>
+    <path
+       style="fill:none;stroke:#000000;stroke-width:0.241;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1;marker-end:url(#marker6296)"
+       d="m 25.76618,74.06671 c 4.786522,-4.887536 4.786522,-4.887536 4.786522,-4.887536"
+       id="path16400"
+       inkscape:connector-curvature="0" />
+    <text
+       xml:space="preserve"
+       style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:3.70416689px;line-height:1.25;font-family:sans-serif;-inkscape-font-specification:'sans-serif, Normal';font-variant-ligatures:normal;font-variant-caps:normal;font-variant-numeric:normal;font-feature-settings:normal;text-align:start;letter-spacing:0px;word-spacing:0px;writing-mode:lr-tb;text-anchor:start;display:inline;opacity:0.98999999;fill:#d7f4e3;fill-opacity:1;stroke:none;stroke-width:0.19843748"
+       x="53.738861"
+       y="118.88161"
+       id="text16968-7"><tspan
+         sodipodi:role="line"
+         id="tspan16966-9"
+         x="53.738861"
+         y="118.88161"
+         style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:3.70416689px;font-family:sans-serif;-inkscape-font-specification:'sans-serif, Normal';font-variant-ligatures:normal;font-variant-caps:normal;font-variant-numeric:normal;font-feature-settings:normal;text-align:start;writing-mode:lr-tb;text-anchor:start;fill:#d7f4e3;stroke-width:0.19843748">ring</tspan></text>
+    <rect
+       style="display:inline;opacity:0.98999999;fill:#ffe6d5;fill-opacity:1;stroke:#000000;stroke-width:0.13431512;stroke-miterlimit:4;stroke-dasharray:none"
+       id="rect1769-1"
+       width="21.297846"
+       height="5.9898095"
+       x="30.552706"
+       y="118.42049"
+       ry="1.3525398" />
+    <text
+       xml:space="preserve"
+       style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:3.70416689px;line-height:1.25;font-family:sans-serif;-inkscape-font-specification:'sans-serif, Normal';font-variant-ligatures:normal;font-variant-caps:normal;font-variant-numeric:normal;font-feature-settings:normal;text-align:start;letter-spacing:0px;word-spacing:0px;writing-mode:lr-tb;text-anchor:start;display:inline;opacity:0.98999999;fill:#000000;fill-opacity:1;stroke:none;stroke-width:0.19843748"
+       x="33.065689"
+       y="122.40759"
+       id="text1773-3"><tspan
+         sodipodi:role="line"
+         id="tspan1461-7"
+         x="33.065689"
+         y="122.40759"
+         style="stroke-width:0.19843748">classifier</tspan></text>
+    <path
+       style="display:inline;opacity:0.98999999;fill:none;stroke:#000000;stroke-width:0.24075003;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1;marker-end:url(#marker1560-8)"
+       d="m 100.74232,114.79142 c 6.66185,0 6.66185,0 6.66185,0"
+       id="path1556-5"
+       inkscape:connector-curvature="0" />
+    <rect
+       style="display:inline;opacity:0.98999999;fill:#ffe6d5;fill-opacity:1;stroke:#000000;stroke-width:0.12518337;stroke-miterlimit:4;stroke-dasharray:none"
+       id="rect1769-3-9"
+       width="18.472155"
+       height="5.9989409"
+       x="31.08676"
+       y="139.11952"
+       ry="1.3546017" />
+    <text
+       xml:space="preserve"
+       style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:3.70416689px;line-height:1.25;font-family:sans-serif;-inkscape-font-specification:'sans-serif, Normal';font-variant-ligatures:normal;font-variant-caps:normal;font-variant-numeric:normal;font-feature-settings:normal;text-align:start;letter-spacing:0px;word-spacing:0px;writing-mode:lr-tb;text-anchor:start;display:inline;opacity:0.98999999;fill:#000000;fill-opacity:1;stroke:none;stroke-width:0.19843748"
+       x="33.207436"
+       y="143.24347"
+       id="text1773-6-66"><tspan
+         sodipodi:role="line"
+         id="tspan1463-8"
+         x="33.207436"
+         y="143.24347"
+         style="stroke-width:0.19843748">merger</tspan></text>
+    <g
+       style="display:inline;opacity:0.98999999"
+       id="g2295-4"
+       transform="matrix(0.75000001,0,0,0.75000001,-14.653804,93.030228)">
+      <rect
+         ry="1.8039205"
+         y="25.020494"
+         x="106.67704"
+         height="7.9887786"
+         width="27.643539"
+         id="rect1769-3-2-9"
+         style="fill:#ffe6d5;fill-opacity:1;stroke:#000000;stroke-width:0.17672074;stroke-miterlimit:4;stroke-dasharray:none" />
+      <text
+         id="text1773-6-6-89"
+         y="30.337786"
+         x="107.9122"
+         style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:4.93888903px;line-height:1.25;font-family:sans-serif;-inkscape-font-specification:'sans-serif, Normal';font-variant-ligatures:normal;font-variant-caps:normal;font-variant-numeric:normal;font-feature-settings:normal;text-align:start;letter-spacing:0px;word-spacing:0px;writing-mode:lr-tb;text-anchor:start;fill:#000000;fill-opacity:1;stroke:none;stroke-width:0.26458332"
+         xml:space="preserve"><tspan
+           id="tspan3024-2"
+           sodipodi:role="line"
+           x="107.9122"
+           y="30.337786">forwarder</tspan></text>
+    </g>
+    <g
+       transform="matrix(0.75000001,0,0,0.75000001,-14.463468,115.68183)"
+       style="display:inline;opacity:0.98999999"
+       id="g2295-3-9">
+      <rect
+         ry="1.8039205"
+         y="25.020494"
+         x="106.67704"
+         height="7.9887786"
+         width="27.643539"
+         id="rect1769-3-2-4-8"
+         style="fill:#ffe6d5;fill-opacity:1;stroke:#000000;stroke-width:0.17672074;stroke-miterlimit:4;stroke-dasharray:none" />
+      <text
+         id="text1773-6-6-0-6"
+         y="30.337786"
+         x="107.9122"
+         style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:4.93888903px;line-height:1.25;font-family:sans-serif;-inkscape-font-specification:'sans-serif, Normal';font-variant-ligatures:normal;font-variant-caps:normal;font-variant-numeric:normal;font-feature-settings:normal;text-align:start;letter-spacing:0px;word-spacing:0px;writing-mode:lr-tb;text-anchor:start;fill:#000000;fill-opacity:1;stroke:none;stroke-width:0.26458332"
+         xml:space="preserve"><tspan
+           id="tspan3024-5-0"
+           sodipodi:role="line"
+           x="107.9122"
+           y="30.337786">forwarder</tspan></text>
+    </g>
+    <g
+       transform="matrix(0.75000001,0,0,0.75000001,-14.63356,104.62602)"
+       style="display:inline;opacity:0.98999999"
+       id="g2295-5-8">
+      <rect
+         ry="1.8039205"
+         y="25.020494"
+         x="106.67704"
+         height="7.9887786"
+         width="27.643539"
+         id="rect1769-3-2-2-0"
+         style="fill:#ffe6d5;fill-opacity:1;stroke:#000000;stroke-width:0.17672074;stroke-miterlimit:4;stroke-dasharray:none" />
+      <text
+         id="text1773-6-6-6-0"
+         y="30.337786"
+         x="107.9122"
+         style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:4.93888903px;line-height:1.25;font-family:sans-serif;-inkscape-font-specification:'sans-serif, Normal';font-variant-ligatures:normal;font-variant-caps:normal;font-variant-numeric:normal;font-feature-settings:normal;text-align:start;letter-spacing:0px;word-spacing:0px;writing-mode:lr-tb;text-anchor:start;fill:#000000;fill-opacity:1;stroke:none;stroke-width:0.26458332"
+         xml:space="preserve"><tspan
+           id="tspan3024-9-2"
+           sodipodi:role="line"
+           x="107.9122"
+           y="30.337786">forwarder</tspan></text>
+    </g>
+    <g
+       transform="matrix(0.75000001,0,0,0.75000001,-14.17999,125.50716)"
+       style="display:inline;opacity:0.98999999"
+       id="g2295-0-8">
+      <rect
+         ry="1.8039205"
+         y="25.020494"
+         x="106.67704"
+         height="7.9887786"
+         width="27.643539"
+         id="rect1769-3-2-8-6"
+         style="fill:#ffe6d5;fill-opacity:1;stroke:#000000;stroke-width:0.17672074;stroke-miterlimit:4;stroke-dasharray:none" />
+      <text
+         id="text1773-6-6-8-7"
+         y="30.337786"
+         x="107.9122"
+         style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:4.93888903px;line-height:1.25;font-family:sans-serif;-inkscape-font-specification:'sans-serif, Normal';font-variant-ligatures:normal;font-variant-caps:normal;font-variant-numeric:normal;font-feature-settings:normal;text-align:start;letter-spacing:0px;word-spacing:0px;writing-mode:lr-tb;text-anchor:start;fill:#000000;fill-opacity:1;stroke:none;stroke-width:0.26458332"
+         xml:space="preserve"><tspan
+           id="tspan3024-96-7"
+           sodipodi:role="line"
+           x="107.9122"
+           y="30.337786">forwarder</tspan></text>
+    </g>
+    <g
+       style="display:inline;opacity:0.98999999"
+       id="g1263-1-6"
+       transform="matrix(0.75000001,0,0,0.75000001,-12.136796,36.242705)">
+      <g
+         id="g2377-5-42-1-1"
+         style="display:inline;fill:#eef4d7"
+         transform="translate(-6.7279778,-3.9309553)">
+        <ellipse
+           style="display:inline;fill:#eef4d7;fill-opacity:1;stroke:#000000;stroke-width:0.35376999;stroke-miterlimit:4;stroke-dasharray:none"
+           id="path1780-3-7-12-8-5-3"
+           cx="100.0881"
+           cy="141.425"
+           rx="6.5516987"
+           ry="3.1499126"
+           inkscape:transform-center-x="13.229167"
+           inkscape:transform-center-y="-59.720238" />
+        <text
+           xml:space="preserve"
+           style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:4.93888903px;line-height:1.25;font-family:sans-serif;-inkscape-font-specification:'sans-serif, Normal';font-variant-ligatures:normal;font-variant-caps:normal;font-variant-numeric:normal;font-feature-settings:normal;text-align:start;letter-spacing:0px;word-spacing:0px;writing-mode:lr-tb;text-anchor:start;display:inline;fill:#eef4d7;fill-opacity:1;stroke:none;stroke-width:0.28356495"
+           x="102.67519"
+           y="132.96213"
+           id="text1773-6-6-5-2-7-4-3-60-6-7"
+           transform="scale(0.93214046,1.0727997)"><tspan
+             sodipodi:role="line"
+             id="tspan2372-8-0-1-9"
+             x="102.67519"
+             y="132.96213">ring</tspan></text>
+      </g>
+      <text
+         transform="scale(0.93214046,1.0727997)"
+         id="text1773-6-6-5-2-7-4-4-2-8-0"
+         y="129.157"
+         x="95.700722"
+         style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:4.93888903px;line-height:1.25;font-family:sans-serif;-inkscape-font-specification:'sans-serif, Normal';font-variant-ligatures:normal;font-variant-caps:normal;font-variant-numeric:normal;font-feature-settings:normal;text-align:start;letter-spacing:0px;word-spacing:0px;writing-mode:lr-tb;text-anchor:start;display:inline;fill:#000000;fill-opacity:1;stroke:none;stroke-width:0.28356495"
+         xml:space="preserve"><tspan
+           y="129.157"
+           x="95.700722"
+           id="tspan2372-2-3-6-5"
+           sodipodi:role="line">ring</tspan></text>
+    </g>
+    <g
+       style="display:inline;opacity:0.98999999"
+       id="g1263-52-2"
+       transform="matrix(0.75000001,0,0,0.75000001,-12.136796,42.743899)">
+      <g
+         id="g2377-5-42-19-1"
+         style="display:inline;fill:#eef4d7"
+         transform="translate(-6.7279778,-3.9309553)">
+        <ellipse
+           style="display:inline;fill:#eef4d7;fill-opacity:1;stroke:#000000;stroke-width:0.35376999;stroke-miterlimit:4;stroke-dasharray:none"
+           id="path1780-3-7-12-8-0-7"
+           cx="100.0881"
+           cy="141.425"
+           rx="6.5516987"
+           ry="3.1499126"
+           inkscape:transform-center-x="13.229167"
+           inkscape:transform-center-y="-59.720238" />
+        <text
+           xml:space="preserve"
+           style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:4.93888903px;line-height:1.25;font-family:sans-serif;-inkscape-font-specification:'sans-serif, Normal';font-variant-ligatures:normal;font-variant-caps:normal;font-variant-numeric:normal;font-feature-settings:normal;text-align:start;letter-spacing:0px;word-spacing:0px;writing-mode:lr-tb;text-anchor:start;display:inline;fill:#eef4d7;fill-opacity:1;stroke:none;stroke-width:0.28356495"
+           x="102.67519"
+           y="132.96213"
+           id="text1773-6-6-5-2-7-4-3-60-0-1"
+           transform="scale(0.93214046,1.0727997)"><tspan
+             sodipodi:role="line"
+             id="tspan2372-8-0-3-1"
+             x="102.67519"
+             y="132.96213">ring</tspan></text>
+      </g>
+      <text
+         transform="scale(0.93214046,1.0727997)"
+         id="text1773-6-6-5-2-7-4-4-2-0-9"
+         y="129.157"
+         x="95.700722"
+         style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:4.93888903px;line-height:1.25;font-family:sans-serif;-inkscape-font-specification:'sans-serif, Normal';font-variant-ligatures:normal;font-variant-caps:normal;font-variant-numeric:normal;font-feature-settings:normal;text-align:start;letter-spacing:0px;word-spacing:0px;writing-mode:lr-tb;text-anchor:start;display:inline;fill:#000000;fill-opacity:1;stroke:none;stroke-width:0.28356495"
+         xml:space="preserve"><tspan
+           y="129.157"
+           x="95.700722"
+           id="tspan2372-2-3-8-3"
+           sodipodi:role="line">ring</tspan></text>
+    </g>
+    <g
+       id="g1969-2"
+       transform="matrix(0.52050336,0,0,1.6939167,34.865776,-95.856534)"
+       style="display:inline;opacity:0.98999999;fill:#eef4d7">
+      <rect
+         ry="1.8106976"
+         y="122.52335"
+         x="124.54029"
+         height="8.0187912"
+         width="18.980101"
+         id="rect1769-3-2-7-0"
+         style="fill:#eef4d7;stroke:#000000;stroke-width:0.14670815;stroke-miterlimit:4;stroke-dasharray:none" />
+    </g>
+    <text
+       xml:space="preserve"
+       style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:3.70416689px;line-height:1.25;font-family:sans-serif;-inkscape-font-specification:'sans-serif, Normal';font-variant-ligatures:normal;font-variant-caps:normal;font-variant-numeric:normal;font-feature-settings:normal;text-align:start;letter-spacing:0px;word-spacing:0px;writing-mode:lr-tb;text-anchor:start;display:inline;opacity:0.98999999;fill:#000000;fill-opacity:1;stroke:none;stroke-width:0.21267372"
+       x="107.1816"
+       y="111.32291"
+       id="text1773-6-6-5-2-5"
+       transform="scale(0.93214045,1.0727997)"><tspan
+         y="111.32291"
+         x="107.1816"
+         sodipodi:role="line"
+         id="tspan1964-1-2"
+         style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:3.70416689px;font-family:sans-serif;-inkscape-font-specification:'sans-serif, Normal';font-variant-ligatures:normal;font-variant-caps:normal;font-variant-numeric:normal;font-feature-settings:normal;text-align:start;writing-mode:lr-tb;text-anchor:start;stroke-width:0.21267372">vhost</tspan></text>
+    <g
+       style="display:inline;opacity:0.98999999"
+       id="g1263-18"
+       transform="matrix(0.75000001,0,0,0.75000001,-12.007968,14.39228)">
+      <g
+         id="g2377-5-42-8"
+         style="display:inline;fill:#eef4d7"
+         transform="translate(-6.7279778,-3.9309553)">
+        <ellipse
+           style="display:inline;fill:#eef4d7;fill-opacity:1;stroke:#000000;stroke-width:0.35376999;stroke-miterlimit:4;stroke-dasharray:none"
+           id="path1780-3-7-12-8-7"
+           cx="100.0881"
+           cy="141.425"
+           rx="6.5516987"
+           ry="3.1499126"
+           inkscape:transform-center-x="13.229167"
+           inkscape:transform-center-y="-59.720238" />
+        <text
+           xml:space="preserve"
+           style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:4.93888903px;line-height:1.25;font-family:sans-serif;-inkscape-font-specification:'sans-serif, Normal';font-variant-ligatures:normal;font-variant-caps:normal;font-variant-numeric:normal;font-feature-settings:normal;text-align:start;letter-spacing:0px;word-spacing:0px;writing-mode:lr-tb;text-anchor:start;display:inline;fill:#eef4d7;fill-opacity:1;stroke:none;stroke-width:0.28356495"
+           x="102.67519"
+           y="132.96213"
+           id="text1773-6-6-5-2-7-4-3-60-3"
+           transform="scale(0.93214046,1.0727997)"><tspan
+             sodipodi:role="line"
+             id="tspan2372-8-0-6"
+             x="102.67519"
+             y="132.96213">ring</tspan></text>
+      </g>
+      <text
+         transform="scale(0.93214046,1.0727997)"
+         id="text1773-6-6-5-2-7-4-4-2-5"
+         y="129.157"
+         x="95.700722"
+         style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:4.93888903px;line-height:1.25;font-family:sans-serif;-inkscape-font-specification:'sans-serif, Normal';font-variant-ligatures:normal;font-variant-caps:normal;font-variant-numeric:normal;font-feature-settings:normal;text-align:start;letter-spacing:0px;word-spacing:0px;writing-mode:lr-tb;text-anchor:start;display:inline;fill:#000000;fill-opacity:1;stroke:none;stroke-width:0.28356495"
+         xml:space="preserve"><tspan
+           y="129.157"
+           x="95.700722"
+           id="tspan2372-2-3-85"
+           sodipodi:role="line">ring</tspan></text>
+    </g>
+    <g
+       style="display:inline;opacity:0.98999999"
+       id="g1263-5-6"
+       transform="matrix(0.75000001,0,0,0.75000001,-11.724485,20.874574)">
+      <g
+         id="g2377-5-42-7-9"
+         style="display:inline;fill:#eef4d7"
+         transform="translate(-6.7279778,-3.9309553)">
+        <ellipse
+           style="display:inline;fill:#eef4d7;fill-opacity:1;stroke:#000000;stroke-width:0.35376999;stroke-miterlimit:4;stroke-dasharray:none"
+           id="path1780-3-7-12-8-4-8"
+           cx="100.0881"
+           cy="141.425"
+           rx="6.5516987"
+           ry="3.1499126"
+           inkscape:transform-center-x="13.229167"
+           inkscape:transform-center-y="-59.720238" />
+        <text
+           xml:space="preserve"
+           style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:4.93888903px;line-height:1.25;font-family:sans-serif;-inkscape-font-specification:'sans-serif, Normal';font-variant-ligatures:normal;font-variant-caps:normal;font-variant-numeric:normal;font-feature-settings:normal;text-align:start;letter-spacing:0px;word-spacing:0px;writing-mode:lr-tb;text-anchor:start;display:inline;fill:#eef4d7;fill-opacity:1;stroke:none;stroke-width:0.28356495"
+           x="102.67519"
+           y="132.96213"
+           id="text1773-6-6-5-2-7-4-3-60-1-6"
+           transform="scale(0.93214046,1.0727997)"><tspan
+             sodipodi:role="line"
+             id="tspan2372-8-0-0-9"
+             x="102.67519"
+             y="132.96213">ring</tspan></text>
+      </g>
+      <text
+         transform="scale(0.93214046,1.0727997)"
+         id="text1773-6-6-5-2-7-4-4-2-6-1"
+         y="129.157"
+         x="95.700722"
+         style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:4.93888903px;line-height:1.25;font-family:sans-serif;-inkscape-font-specification:'sans-serif, Normal';font-variant-ligatures:normal;font-variant-caps:normal;font-variant-numeric:normal;font-feature-settings:normal;text-align:start;letter-spacing:0px;word-spacing:0px;writing-mode:lr-tb;text-anchor:start;display:inline;fill:#000000;fill-opacity:1;stroke:none;stroke-width:0.28356495"
+         xml:space="preserve"><tspan
+           y="129.157"
+           x="95.700722"
+           id="tspan2372-2-3-9-4"
+           sodipodi:role="line">ring</tspan></text>
+    </g>
+    <path
+       style="display:inline;opacity:0.98999999;fill:none;stroke:#000000;stroke-width:0.241;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1;marker-end:url(#marker14793-2)"
+       d="m 109.41096,114.89574 c 4.20595,0 4.20595,0 4.20595,0"
+       id="path14783-0"
+       inkscape:connector-curvature="0" />
+    <path
+       style="display:inline;opacity:0.98999999;fill:none;stroke:#000000;stroke-width:0.241;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1;marker-start:url(#marker22960-5-7)"
+       d="m 109.62596,121.20249 c 4.20594,0 4.20594,0 4.20594,0"
+       id="path14783-8-7-0"
+       inkscape:connector-curvature="0" />
+    <path
+       style="fill:none;stroke:#000000;stroke-width:0.241;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1;marker-end:url(#marker17252)"
+       d="M 51.850549,69.348147 C 65.374218,74.32076 65.374218,74.32076 65.374218,74.32076"
+       id="path17242"
+       inkscape:connector-curvature="0" />
+    <g
+       style="display:inline"
+       id="g1263-5"
+       transform="matrix(0.75,0,0,0.75,-12.699537,-31.862767)">
+      <g
+         id="g2377-5-42-7"
+         style="display:inline;fill:#eef4d7"
+         transform="translate(-6.7279778,-3.9309553)">
+        <ellipse
+           style="display:inline;fill:#eef4d7;fill-opacity:1;stroke:#000000;stroke-width:0.35376999;stroke-miterlimit:4;stroke-dasharray:none"
+           id="path1780-3-7-12-8-4"
+           cx="100.0881"
+           cy="141.425"
+           rx="6.5516987"
+           ry="3.1499126"
+           inkscape:transform-center-x="13.229167"
+           inkscape:transform-center-y="-59.720238" />
+        <text
+           xml:space="preserve"
+           style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:4.93888903px;line-height:1.25;font-family:sans-serif;-inkscape-font-specification:'sans-serif, Normal';font-variant-ligatures:normal;font-variant-caps:normal;font-variant-numeric:normal;font-feature-settings:normal;text-align:start;letter-spacing:0px;word-spacing:0px;writing-mode:lr-tb;text-anchor:start;display:inline;fill:#eef4d7;fill-opacity:1;stroke:none;stroke-width:0.28356495"
+           x="102.67519"
+           y="132.96213"
+           id="text1773-6-6-5-2-7-4-3-60-1"
+           transform="scale(0.93214046,1.0727997)"><tspan
+             sodipodi:role="line"
+             id="tspan2372-8-0-0"
+             x="102.67519"
+             y="132.96213">ring</tspan></text>
+      </g>
+      <text
+         transform="scale(0.93214046,1.0727997)"
+         id="text1773-6-6-5-2-7-4-4-2-6"
+         y="129.157"
+         x="95.700722"
+         style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:4.93888903px;line-height:1.25;font-family:sans-serif;-inkscape-font-specification:'sans-serif, Normal';font-variant-ligatures:normal;font-variant-caps:normal;font-variant-numeric:normal;font-feature-settings:normal;text-align:start;letter-spacing:0px;word-spacing:0px;writing-mode:lr-tb;text-anchor:start;display:inline;fill:#000000;fill-opacity:1;stroke:none;stroke-width:0.28356495"
+         xml:space="preserve"><tspan
+           y="129.157"
+           x="95.700722"
+           id="tspan2372-2-3-9"
+           sodipodi:role="line">ring</tspan></text>
+    </g>
+    <path
+       style="fill:none;stroke:#000000;stroke-width:0.241;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1;marker-start:url(#marker9343)"
+       d="m 49.55891,89.527187 c 15.9854,-4.679791 15.9854,-4.679791 15.9854,-4.679791 v 0"
+       id="path17770"
+       inkscape:connector-curvature="0" />
+    <path
+       style="fill:none;stroke:#000000;stroke-width:0.241;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1;marker-end:url(#marker17872)"
+       d="M 65.827788,95.560313 C 49.55891,90.407413 49.55891,90.407413 49.55891,90.407413"
+       id="path17862"
+       inkscape:connector-curvature="0" />
+    <path
+       style="fill:none;stroke:#000000;stroke-width:0.241;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1;marker-end:url(#marker18406)"
+       d="M 31.086758,88.99802 C 25.76618,83.755415 25.76618,83.755415 25.76618,83.755415"
+       id="path18396"
+       inkscape:connector-curvature="0" />
+    <g
+       style="display:inline"
+       id="g1263-1"
+       transform="matrix(0.75,0,0,0.75,-11.641198,-17.237352)">
+      <g
+         id="g2377-5-42-1"
+         style="display:inline;fill:#eef4d7"
+         transform="translate(-6.7279778,-3.9309553)">
+        <ellipse
+           style="display:inline;fill:#eef4d7;fill-opacity:1;stroke:#000000;stroke-width:0.35376999;stroke-miterlimit:4;stroke-dasharray:none"
+           id="path1780-3-7-12-8-5"
+           cx="100.0881"
+           cy="141.425"
+           rx="6.5516987"
+           ry="3.1499126"
+           inkscape:transform-center-x="13.229167"
+           inkscape:transform-center-y="-59.720238" />
+        <text
+           xml:space="preserve"
+           style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:4.93888903px;line-height:1.25;font-family:sans-serif;-inkscape-font-specification:'sans-serif, Normal';font-variant-ligatures:normal;font-variant-caps:normal;font-variant-numeric:normal;font-feature-settings:normal;text-align:start;letter-spacing:0px;word-spacing:0px;writing-mode:lr-tb;text-anchor:start;display:inline;fill:#eef4d7;fill-opacity:1;stroke:none;stroke-width:0.28356495"
+           x="102.67519"
+           y="132.96213"
+           id="text1773-6-6-5-2-7-4-3-60-6"
+           transform="scale(0.93214046,1.0727997)"><tspan
+             sodipodi:role="line"
+             id="tspan2372-8-0-1"
+             x="102.67519"
+             y="132.96213">ring</tspan></text>
+      </g>
+      <text
+         transform="scale(0.93214046,1.0727997)"
+         id="text1773-6-6-5-2-7-4-4-2-8"
+         y="129.157"
+         x="95.700722"
+         style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:4.93888903px;line-height:1.25;font-family:sans-serif;-inkscape-font-specification:'sans-serif, Normal';font-variant-ligatures:normal;font-variant-caps:normal;font-variant-numeric:normal;font-feature-settings:normal;text-align:start;letter-spacing:0px;word-spacing:0px;writing-mode:lr-tb;text-anchor:start;display:inline;fill:#000000;fill-opacity:1;stroke:none;stroke-width:0.28356495"
+         xml:space="preserve"><tspan
+           y="129.157"
+           x="95.700722"
+           id="tspan2372-2-3-6"
+           sodipodi:role="line">ring</tspan></text>
+    </g>
+    <g
+       style="display:inline"
+       id="g1263-52"
+       transform="matrix(0.75,0,0,0.75,-11.641198,-10.736158)">
+      <g
+         id="g2377-5-42-19"
+         style="display:inline;fill:#eef4d7"
+         transform="translate(-6.7279778,-3.9309553)">
+        <ellipse
+           style="display:inline;fill:#eef4d7;fill-opacity:1;stroke:#000000;stroke-width:0.35376999;stroke-miterlimit:4;stroke-dasharray:none"
+           id="path1780-3-7-12-8-0"
+           cx="100.0881"
+           cy="141.425"
+           rx="6.5516987"
+           ry="3.1499126"
+           inkscape:transform-center-x="13.229167"
+           inkscape:transform-center-y="-59.720238" />
+        <text
+           xml:space="preserve"
+           style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:4.93888903px;line-height:1.25;font-family:sans-serif;-inkscape-font-specification:'sans-serif, Normal';font-variant-ligatures:normal;font-variant-caps:normal;font-variant-numeric:normal;font-feature-settings:normal;text-align:start;letter-spacing:0px;word-spacing:0px;writing-mode:lr-tb;text-anchor:start;display:inline;fill:#eef4d7;fill-opacity:1;stroke:none;stroke-width:0.28356495"
+           x="102.67519"
+           y="132.96213"
+           id="text1773-6-6-5-2-7-4-3-60-0"
+           transform="scale(0.93214046,1.0727997)"><tspan
+             sodipodi:role="line"
+             id="tspan2372-8-0-3"
+             x="102.67519"
+             y="132.96213">ring</tspan></text>
+      </g>
+      <text
+         transform="scale(0.93214046,1.0727997)"
+         id="text1773-6-6-5-2-7-4-4-2-0"
+         y="129.157"
+         x="95.700722"
+         style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:4.93888903px;line-height:1.25;font-family:sans-serif;-inkscape-font-specification:'sans-serif, Normal';font-variant-ligatures:normal;font-variant-caps:normal;font-variant-numeric:normal;font-feature-settings:normal;text-align:start;letter-spacing:0px;word-spacing:0px;writing-mode:lr-tb;text-anchor:start;display:inline;fill:#000000;fill-opacity:1;stroke:none;stroke-width:0.28356495"
+         xml:space="preserve"><tspan
+           y="129.157"
+           x="95.700722"
+           id="tspan2372-2-3-8"
+           sodipodi:role="line">ring</tspan></text>
+    </g>
+    <path
+       style="display:inline;opacity:0.98999999;fill:none;stroke:#000000;stroke-width:0.241;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1;marker-end:url(#marker6296-4)"
+       d="m 25.454394,126.25419 c 4.786522,-4.88753 4.786522,-4.88753 4.786522,-4.88753"
+       id="path16400-6"
+       inkscape:connector-curvature="0" />
+    <path
+       style="display:inline;opacity:0.98999999;fill:none;stroke:#000000;stroke-width:0.241;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1;marker-end:url(#marker18406-4)"
+       d="m 30.774972,141.1855 c -5.320578,-5.2426 -5.320578,-5.2426 -5.320578,-5.2426"
+       id="path18396-2"
+       inkscape:connector-curvature="0" />
+    <path
+       style="fill:none;stroke:#000000;stroke-width:0.241;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1;marker-end:url(#marker11193)"
+       d="M 86.106872,73.620847 C 99.689413,114.33366 99.689413,114.33366 99.689413,114.33366"
+       id="path11183"
+       inkscape:connector-curvature="0" />
+    <path
+       style="fill:none;stroke:#000000;stroke-width:0.241;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1;marker-end:url(#marker11643)"
+       d="M 99.689413,122.09597 C 86.560442,94.672728 86.560442,94.672728 86.560442,94.672728"
+       id="path11633"
+       inkscape:connector-curvature="0" />
+    <path
+       style="fill:none;stroke:#000000;stroke-width:0.241;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1;marker-end:url(#marker14003)"
+       d="m 86.086632,114.97061 c 13.5543,-26.794505 13.5543,-26.794505 13.5543,-26.794505"
+       id="path13993"
+       inkscape:connector-curvature="0" />
+    <path
+       style="fill:none;stroke:#000000;stroke-width:0.241;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1;marker-end:url(#marker15037)"
+       d="M 99.640931,95.409267 C 86.276967,137.26377 86.276967,137.26377 86.276967,137.26377"
+       id="path15027"
+       inkscape:connector-curvature="0" />
+    <path
+       style="fill:none;stroke:#000000;stroke-width:0.241;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1;marker-end:url(#marker15633)"
+       d="m 86.106875,126.5664 c 13.189286,14.34678 13.189286,14.34678 13.189286,14.34678"
+       id="path15623"
+       inkscape:connector-curvature="0" />
+  </g>
+</svg>
-- 
1.9.1

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

* [spp] [PATCH 18/30] doc: add explanation for terminating spp app
  2018-01-15 11:04 ` [spp] Proposal - spp_vf(SR-IOV like feature) addition to SPP Ferruh Yigit
                     ` (16 preceding siblings ...)
  2018-01-16  5:16   ` [spp] [PATCH 17/30] doc: add spp_sample_usage_svg in docs/spp_vf/ x-fn-spp
@ 2018-01-16  5:16   ` x-fn-spp
  2018-01-16  5:16   ` [spp] [PATCH 19/30] doc: add explanations on options of spp x-fn-spp
                     ` (11 subsequent siblings)
  29 siblings, 0 replies; 97+ messages in thread
From: x-fn-spp @ 2018-01-16  5:16 UTC (permalink / raw)
  To: spp

From: Hiroyuki Nakamura <nakamura.hioryuki@po.ntt-tx.co.jp>

Add a chapter that describes procedures for terminating spp application.

Signed-off-by: Kentaro Watanabe <watanabe.kentaro.z01@as.ntt-tx.co.jp>
Signed-off-by: Naoki Takada <takada.naoki@lab.ntt.co.jp>
---
 docs/spp_vf/sample_usage.md | 46 +++++++++++++++++++++++++++++++--------------
 1 file changed, 32 insertions(+), 14 deletions(-)

diff --git a/docs/spp_vf/sample_usage.md b/docs/spp_vf/sample_usage.md
index ce68867..8653a49 100644
--- a/docs/spp_vf/sample_usage.md
+++ b/docs/spp_vf/sample_usage.md
@@ -188,20 +188,38 @@ Now, you can login VMs.
   $ ssh sppuser@192.168.150.32
   ```
 
-If you unregister the addresses, send request as following.
+## End Application
+
+Describe the procedure to end the application.
+
+### Remove MAC address from Classifier
+
+It is possible to remove the MAC address set by inputting the following
+command from `spp_vf.py` which was started with `Setup SPP`.
+The flush command is required to reflect the setting.
 
   ```sh
-  {
-    "commands": [
-      {
-        "command": "classifier_table",
-        "type": "mac",
-        "value": "52:54:00:12:34:58",
-        "port": "unuse"
-      },
-      {
-        "command": "flush"
-      }
-    ]
-  }
+  spp > classifier_table mac 52:54:00:12:34:56 unuse
+  spp > classifier_table mac 52:54:00:12:34:58 unuse
+  spp > flush
+  ```
+
+### Teardown SPP
+
+Tear down SPP in the reverse order of Setup.
+To stop other than spp_vf.py, press Ctrl + C on the launched screen.
+spp_vf.py can be stopped by the bye command.
+
+  ```sh
+  # stop secondary 2
+  Ctrl + C
+
+  # stop secondary 1
+  Ctrl + C
+
+  # stop primary
+  Ctrl + C
+
+  # stop controller
+  spp > bye
   ```
-- 
1.9.1

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

* [spp] [PATCH 19/30] doc: add explanations on options of spp
  2018-01-15 11:04 ` [spp] Proposal - spp_vf(SR-IOV like feature) addition to SPP Ferruh Yigit
                     ` (17 preceding siblings ...)
  2018-01-16  5:16   ` [spp] [PATCH 18/30] doc: add explanation for terminating spp app x-fn-spp
@ 2018-01-16  5:16   ` x-fn-spp
  2018-01-16  5:16   ` [spp] [PATCH 20/30] doc: update description for the latest spp version x-fn-spp
                     ` (10 subsequent siblings)
  29 siblings, 0 replies; 97+ messages in thread
From: x-fn-spp @ 2018-01-16  5:16 UTC (permalink / raw)
  To: spp

From: Hiroyuki Nakamura <nakamura.hioryuki@po.ntt-tx.co.jp>

Add the following explanations:
* Options for DPDK and ones for spp are available.
* Hyperlink to the reference to DPDK option is inserted.

Signed-off-by: Daiki Yamashita <yamashita.daiki.z01@as.ntt-tx.co.jp>
Signed-off-by: Naoki Takada <takada.naoki@lab.ntt.co.jp>
---
 docs/spp_vf/how_to_use.md | 13 +++++++++++++
 1 file changed, 13 insertions(+)

diff --git a/docs/spp_vf/how_to_use.md b/docs/spp_vf/how_to_use.md
index 6b5019c..e9b752d 100644
--- a/docs/spp_vf/how_to_use.md
+++ b/docs/spp_vf/how_to_use.md
@@ -29,6 +29,11 @@ $ python ./src/spp.py -p 5555 -s 6666
 SPP primary reserves and manages resources for secondary processes.
 You have to run it before secondaries.
 
+SPP primary has two kinds of options, dpdk and spp.
+Option of dpdk is before `--`, option of spp is after `--`.
+
+Option of dpdk are refer to [dpdk documentation](http://dpdk.org/doc/guides/linux_gsg/build_sample_apps.html#running-a-sample-application).
+
 Options of spp primary are
   * -p : port mask
   * -n : number of rings
@@ -45,6 +50,14 @@ $ sudo ./src/primary/x86_64-native-linuxapp-gcc/spp_primary \
 ### SPP Secondary
 
 In `spp_vf`, spp secondary processes are launched by single command.
+
+`spp_vf` has two kinds of options as well as spp primary.
+
+Option of dpdk are refer to [dpdk documentation](http://dpdk.org/doc/guides/linux_gsg/build_sample_apps.html#running-a-sample-application).
+
+Options of `spp_vf` are
+  * TODO
+
 Core assingment and network configuration are defined
 in JSON formatted config file.
 If you run `spp_vf` without giving config file, it refers default
-- 
1.9.1

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

* [spp] [PATCH 20/30] doc: update description for the latest spp version
  2018-01-15 11:04 ` [spp] Proposal - spp_vf(SR-IOV like feature) addition to SPP Ferruh Yigit
                     ` (18 preceding siblings ...)
  2018-01-16  5:16   ` [spp] [PATCH 19/30] doc: add explanations on options of spp x-fn-spp
@ 2018-01-16  5:16   ` x-fn-spp
  2018-01-16  5:16   ` [spp] [PATCH 21/30] doc: update description on dpdk version x-fn-spp
                     ` (9 subsequent siblings)
  29 siblings, 0 replies; 97+ messages in thread
From: x-fn-spp @ 2018-01-16  5:16 UTC (permalink / raw)
  To: spp

From: Hiroyuki Nakamura <nakamura.hioryuki@po.ntt-tx.co.jp>

Update description for the latest version of spp.
* Update syntax and procedures (nic->phy、ring0->ring:0 etc.)
* Change filename spp.py to spp_vf.py.
* Change how to register MAC in Classifier_table.

Signed-off-by: Kentaro Watanabe <watanabe.kentaro.z01@as.ntt-tx.co.jp>
Signed-off-by: Naoki Takada <takada.naoki@lab.ntt.co.jp>
---
 docs/spp_vf/config_manual.md | 58 +++++++++++++++++++++---------------------
 docs/spp_vf/how_to_use.md    |  2 +-
 docs/spp_vf/sample_usage.md  | 60 +++++++++-----------------------------------
 3 files changed, 42 insertions(+), 78 deletions(-)

diff --git a/docs/spp_vf/config_manual.md b/docs/spp_vf/config_manual.md
index 370dfdb..f049407 100644
--- a/docs/spp_vf/config_manual.md
+++ b/docs/spp_vf/config_manual.md
@@ -17,12 +17,12 @@ There are three types of forwarder for 1:1, 1:N and N:1.
 
 There are three port types.
 
-  * nic: Physical NIC
+  * phy: Physical NIC
   * vhost: Vhost PMD for VMs
   * ring: Ring PMD for spp components
 
 Each of ports is identified as resource ID with port type and resource ID.
-For example, resource ID of physical NIC of ID 0 is described as `nic0`.
+For example, resource ID of physical NIC of ID 0 is described as `phy:0`.
 
 ## Config Format
 
@@ -66,76 +66,76 @@ Here is default config `spp.json` and network diagram of it.
         {
           "core": 2,   // Core ID
           "type": "merge",   // Forwarder type
-          "rx_port": ["nic0", "nic1"],  // Rx port, It MUST be a list for merge type
-          "tx_port": "ring8"            // Tx port
+          "rx_port": ["phy:0", "phy:1"],  // Rx port, It MUST be a list for merge type
+          "tx_port": "ring:8"            // Tx port
         },
         {
           "core": 3,
           "type": "classifier_mac",
-          "rx_port": "ring8",        // Rx port, It is not a list because type is classifier_mac
+          "rx_port": "ring:8",        // Rx port, It is not a list because type is classifier_mac
           "tx_port_table": "classifier_mac_table"	// If type is classifier_mac, tx is classifier_mac_table
         },
 
         {
           "core": 4,
           "type": "forward",
-          "rx_port": "ring0",
-          "tx_port": "vhost0"
+          "rx_port": "ring:0",
+          "tx_port": "vhost:0"
         },
         {
           "core": 5,
           "type": "forward",
-          "rx_port": "ring1",
-          "tx_port": "vhost2"
+          "rx_port": "ring:1",
+          "tx_port": "vhost:2"
         },
         {
           "core": 6,
           "type": "forward",
-          "rx_port": "vhost0",
-          "tx_port": "ring2"
+          "rx_port": "vhost:0",
+          "tx_port": "ring:2"
         },
         {
           "core": 7,
           "type": "forward",
-          "rx_port": "vhost2",
-          "tx_port": "ring3"
+          "rx_port": "vhost:2",
+          "tx_port": "ring:3"
         },
         {
           "core": 8,
           "type": "merge",
-          "rx_port": ["ring2", "ring3"],
-          "tx_port": "nic0"
+          "rx_port": ["ring:2", "ring:3"],
+          "tx_port": "phy:0"
         },
 
         {
           "core": 9,
           "type": "forward",
-          "rx_port": "ring4",
-          "tx_port": "vhost1"
+          "rx_port": "ring:4",
+          "tx_port": "vhost:1"
         },
         {
           "core": 10,
           "type": "forward",
-          "rx_port": "ring5",
-          "tx_port": "vhost3"
+          "rx_port": "ring:5",
+          "tx_port": "vhost:3"
         },
         {
           "core": 11,
           "type": "forward",
-          "rx_port": "vhost1",
-          "tx_port": "ring6"
+          "rx_port": "vhost:1",
+          "tx_port": "ring:6"
         },
         {
           "core": 12,
           "type": "forward",
-          "rx_port": "vhost3",
-          "tx_port": "ring7"
+          "rx_port": "vhost:3",
+          "tx_port": "ring:7"
         },
         {
           "core": 13,
           "type": "merge",
-          "rx_port": ["ring6", "ring7"],
-          "tx_port": "nic1"
+          "rx_port": ["ring:6", "ring:7"],
+          "tx_port": "phy:1"
         }
       ]
     }
@@ -145,19 +145,19 @@ Here is default config `spp.json` and network diagram of it.
     "table": [
       {
         "mac":"52:54:00:12:34:56",
-        "port":"ring0"
+        "port":"ring:0"
       },
       {
         "mac":"52:54:00:12:34:57",
-        "port":"ring4"
+        "port":"ring:4"
       },
       {
         "mac":"52:54:00:12:34:58",
-        "port":"ring1"
+        "port":"ring:1"
       },
       {
         "mac":"52:54:00:12:34:59",
-        "port":"ring5"
+        "port":"ring:5"
       }
     ]
   }
diff --git a/docs/spp_vf/how_to_use.md b/docs/spp_vf/how_to_use.md
index 6b5019c..8ac1968 100644
--- a/docs/spp_vf/how_to_use.md
+++ b/docs/spp_vf/how_to_use.md
@@ -21,7 +21,7 @@ Before launching spp, you need to setup described as [setup guide](setup_guide.m
 First, run SPP Controller with port numbers for spp primary and secondary.
 
 ```sh
-$ python ./src/spp.py -p 5555 -s 6666
+$ python ./src/spp_vf.py -p 5555 -s 6666
 ```
 
 ### SPP Primary
diff --git a/docs/spp_vf/sample_usage.md b/docs/spp_vf/sample_usage.md
index 8653a49..abab4d4 100644
--- a/docs/spp_vf/sample_usage.md
+++ b/docs/spp_vf/sample_usage.md
@@ -24,7 +24,7 @@ First, launch spp controller and primary process.
   /path/to/Soft-Patch-Panel
 
   # SPP controller
-  $ python ./src/spp.py -p 5555 -s 6666
+  $ python ./src/spp_vf.py -p 5555 -s 6666
 
   # SPP primary
   $ sudo ./src/primary/x86_64-native-linuxapp-gcc/spp_primary \
@@ -34,18 +34,9 @@ First, launch spp controller and primary process.
   -p 0x03 -n 8 -s 127.0.0.1:5555
   ```
 
-After primary process is launched, run nc command for each of
-seconrdary processes and itselves.
-In this sample, commands for secondary are sent from nc because
-`spp.py` does not support commands for spp_vf.
-nc is a network utility and it can open TCP connections, send UDP
-packets, listen on arbitrary TCP and UDP ports, do port scanning,
-and deal with both IPv4 and IPv6.
+launch secondary process after launch primary process.
 
   ```sh
-  # run nc for secondary 1 with port 11111
-  $ while true; do nc -l 11111; done
-
   # start secondary 1
   $ sudo ./src/vf/x86_64-native-linuxapp-gcc/spp_vf \
   -c 0x00fd -n 4 --proc-type=secondary \
@@ -54,9 +45,6 @@ and deal with both IPv4 and IPv6.
   --config /path/to/spp_vf1_without_cmtab.json \
   -s 127.0.0.1:11111
 
-  # run nc for secondary 2 with port 11112
-  $ while true; do nc -l 11112; done
-
   # start secondary 2
   $ sudo ./src/vf/x86_64-native-linuxapp-gcc/spp_vf \
   -c 0x3f01 -n 4 --proc-type=secondary \
@@ -126,48 +114,20 @@ discarding packets.
 
 ## Test Application
 
-TODO(yasufum) json-based steps will be deprecated.
-
 ### Register MAC address to Classifier
 
 Register MAC addresses to classifier.
 
   ```sh
-  {
-    "commands": [
-      {
-        "command": "classifier_table",
-        "type": "mac",
-        "value": "52:54:00:12:34:56",
-        "port": "ring0"
-      },
-      {
-        "command": "classifier_table",
-        "type": "mac",
-        "value": "52:54:00:12:34:58",
-        "port": "ring1"
-      },
-      {
-        "command": "flush"
-      }
-    ]
-  }
+  spp > classifier_table mac 52:54:00:12:34:56 ring:0
+  spp > classifier_table mac 52:54:00:12:34:58 ring:1
+  spp > flush
   ```
 
   ```sh
-  {
-    "commands": [
-      {
-        "command": "classifier_table",
-        "type": "mac",
-        "value": "52:54:00:12:34:57",
-        "port": "ring4"
-      },
-      {
-                    "command": "flush"
-      }
-    ]
-  }
+  spp > classifier_table mac 52:54:00:12:34:57 ring:4
+  spp > classifier_table mac 52:54:00:12:34:59 ring:5
+  spp > flush
   ```
 
 ### Login to VMs
@@ -201,6 +161,10 @@ The flush command is required to reflect the setting.
   ```sh
   spp > classifier_table mac 52:54:00:12:34:56 unuse
   spp > classifier_table mac 52:54:00:12:34:58 unuse
+
+  spp > classifier_table mac 52:54:00:12:34:57 unuse
+  spp > classifier_table mac 52:54:00:12:34:59 unuse
+
   spp > flush
   ```
 
-- 
1.9.1

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

* [spp] [PATCH 21/30] doc: update description on dpdk version
  2018-01-15 11:04 ` [spp] Proposal - spp_vf(SR-IOV like feature) addition to SPP Ferruh Yigit
                     ` (19 preceding siblings ...)
  2018-01-16  5:16   ` [spp] [PATCH 20/30] doc: update description for the latest spp version x-fn-spp
@ 2018-01-16  5:16   ` x-fn-spp
  2018-01-16  5:16   ` [spp] [PATCH 22/30] doc: fix vm setup procedure for network config x-fn-spp
                     ` (8 subsequent siblings)
  29 siblings, 0 replies; 97+ messages in thread
From: x-fn-spp @ 2018-01-16  5:16 UTC (permalink / raw)
  To: spp

From: Hiroyuki Nakamura <nakamura.hioryuki@po.ntt-tx.co.jp>

Since spp_vf supports DPDK version 17.08,
descriptions on DPDK versions are updated.

Signed-off-by: Daiki Yamashita <yamashita.daiki.z01@as.ntt-tx.co.jp>
Signed-off-by: Naoki Takada <takada.naoki@lab.ntt.co.jp>
---
 docs/spp_vf/how_to_use.md  | 2 +-
 docs/spp_vf/setup_guide.md | 6 +++---
 2 files changed, 4 insertions(+), 4 deletions(-)

diff --git a/docs/spp_vf/how_to_use.md b/docs/spp_vf/how_to_use.md
index e9b752d..7bc747d 100644
--- a/docs/spp_vf/how_to_use.md
+++ b/docs/spp_vf/how_to_use.md
@@ -10,7 +10,7 @@ SPP_VF is a SR-IOV like network functionality for NFV.
 
 * Ubuntu 16.04
 * qemu-kvm
-* DPDK v17.05
+* DPDK v17.05 or later
 
 ## Launch SPP
 
diff --git a/docs/spp_vf/setup_guide.md b/docs/spp_vf/setup_guide.md
index 450e68a..db87ab8 100644
--- a/docs/spp_vf/setup_guide.md
+++ b/docs/spp_vf/setup_guide.md
@@ -4,7 +4,7 @@
 
 * Ubuntu 16.04
 * qemu-kvm
-* DPDK v17.05
+* DPDK v17.05 or later
 
 ## Setting
 
@@ -116,7 +116,7 @@ drwxr-xr-x 10 root root 4096 May 27 10:23 ..
 
 #### Install DPDK
 
-Install DPDK v17.05 in any directory. This is a simple instruction and please refer
+Install DPDK in any directory. This is a simple instruction and please refer
 [Getting Started Guide for Linux](http://dpdk.org/doc/guides/linux_gsg/index.html)
 for details.
 
@@ -124,7 +124,7 @@ for details.
 $ cd /path/to/any_dir
 $ git clone http://dpdk.org/git/dpdk
 $ cd dpdk
-$ git checkout v17.05
+$ git checkout [TAG_NAME(e.g. v17.05)]
 $ export RTE_SDK=`pwd`
 $ export RTE_TARGET=x86_64-native-linuxapp-gcc
 $ make T=x86_64-native-linuxapp-gcc install
-- 
1.9.1

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

* [spp] [PATCH 22/30] doc: fix vm setup procedure for network config
  2018-01-15 11:04 ` [spp] Proposal - spp_vf(SR-IOV like feature) addition to SPP Ferruh Yigit
                     ` (20 preceding siblings ...)
  2018-01-16  5:16   ` [spp] [PATCH 21/30] doc: update description on dpdk version x-fn-spp
@ 2018-01-16  5:16   ` x-fn-spp
  2018-01-16  5:16   ` [spp] [PATCH 23/30] doc: update jansson installation procedure x-fn-spp
                     ` (7 subsequent siblings)
  29 siblings, 0 replies; 97+ messages in thread
From: x-fn-spp @ 2018-01-16  5:16 UTC (permalink / raw)
  To: spp

From: Hiroyuki Nakamura <nakamura.hioryuki@po.ntt-tx.co.jp>

Remove unnecessary procedure for checking the configuration with ssh.

Signed-off-by: Daiki Yamashita <yamashita.daiki.z01@as.ntt-tx.co.jp>
Signed-off-by: Naoki Takada <takada.naoki@lab.ntt.co.jp>
---
 docs/spp_vf/sample_usage.md | 5 -----
 1 file changed, 5 deletions(-)

diff --git a/docs/spp_vf/sample_usage.md b/docs/spp_vf/sample_usage.md
index abab4d4..5220184 100644
--- a/docs/spp_vf/sample_usage.md
+++ b/docs/spp_vf/sample_usage.md
@@ -107,11 +107,6 @@ Configurations for spp-vm2 is same as spp-vm1.
   $ sudo ethtool -K ens5 tx off
   ```
 
-Check the configuration by trying ssh from remote machine that
-connection is accepted but discarded in spp secondary.
-If you do ssh for VM1, you find a messages from spp secondary for
-discarding packets.
-
 ## Test Application
 
 ### Register MAC address to Classifier
-- 
1.9.1

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

* [spp] [PATCH 23/30] doc: update jansson installation procedure
  2018-01-15 11:04 ` [spp] Proposal - spp_vf(SR-IOV like feature) addition to SPP Ferruh Yigit
                     ` (21 preceding siblings ...)
  2018-01-16  5:16   ` [spp] [PATCH 22/30] doc: fix vm setup procedure for network config x-fn-spp
@ 2018-01-16  5:16   ` x-fn-spp
  2018-01-16  5:16   ` [spp] [PATCH 24/30] doc: fix required network configuration x-fn-spp
                     ` (6 subsequent siblings)
  29 siblings, 0 replies; 97+ messages in thread
From: x-fn-spp @ 2018-01-16  5:16 UTC (permalink / raw)
  To: spp

From: Hiroyuki Nakamura <nakamura.hioryuki@po.ntt-tx.co.jp>

Update jansson installation procedure so as to use package
rather than to build a branch.

Signed-off-by: Daiki Yamashita <yamashita.daiki.z01@as.ntt-tx.co.jp>
Signed-off-by: Naoki Takada <takada.naoki@lab.ntt.co.jp>
---
 docs/spp_vf/setup_guide.md | 38 ++------------------------------------
 1 file changed, 2 insertions(+), 36 deletions(-)

diff --git a/docs/spp_vf/setup_guide.md b/docs/spp_vf/setup_guide.md
index db87ab8..4684cf3 100644
--- a/docs/spp_vf/setup_guide.md
+++ b/docs/spp_vf/setup_guide.md
@@ -74,44 +74,10 @@ Network configuration is defined in JSON and `spp_vf` reads config from
 the file while launching.
 [jasson](http://www.digip.org/jansson/) is a JSON library written in C.
 
-It is required to use `json_path` feature of `jasson` for `spp_vf`.
-It has develped under `json_path` branch and you need to checkout and compile
-it manually.
+Install the -dev package.
 
 ```sh
-$ git clone https://github.com/rogerz/jansson
-$ cd jansson
-$ sudo git checkout json_path
-Branch json_path set up to track remote branch json_path from origin. Switched to a new branch 'json_path'
-```
-
-This setup guide expects that `jasson` is placed as `/opt/jasson`.
-
-```sh
-$ sudo mkdir -p /opt/jansson
-$ sudo mv jansson /opt/jansson
-```
-
-Compile it as following.
-
-```sh
-$ cd /opt/jansson/jansson
-$ sudo autoreconf -i
-$ sudo ./configure
-$ sudo make
-$ sudo make install
-$ sudo ldconfig
-```
-
-Then, confirm that header files of jasson are generated in `/usr/local/include`.
-
-```sh
-$ ls -al /usr/local/include
-total 24
-drwxr-xr-x  2 root root 4096 Jul 28 16:45 .
-drwxr-xr-x 10 root root 4096 May 27 10:23 ..
--rw-r--r--  1 root root 1183 Jul 28 16:45 jansson_config.h
--rw-r--r--  1 root root 9499 Jul 28 16:45 jansson.h
+$ sudo apt-get install libjansson-dev
 ```
 
 #### Install DPDK
-- 
1.9.1

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

* [spp] [PATCH 24/30] doc: fix required network configuration
  2018-01-15 11:04 ` [spp] Proposal - spp_vf(SR-IOV like feature) addition to SPP Ferruh Yigit
                     ` (22 preceding siblings ...)
  2018-01-16  5:16   ` [spp] [PATCH 23/30] doc: update jansson installation procedure x-fn-spp
@ 2018-01-16  5:16   ` x-fn-spp
  2018-01-16  5:16   ` [spp] [PATCH 25/30] doc: add how to use vhost-user support x-fn-spp
                     ` (5 subsequent siblings)
  29 siblings, 0 replies; 97+ messages in thread
From: x-fn-spp @ 2018-01-16  5:16 UTC (permalink / raw)
  To: spp

From: Hiroyuki Nakamura <nakamura.hioryuki@po.ntt-tx.co.jp>

Remove unnecessary steps, registation to arp table,
in "additional network configurations" section in how_to_use.md.

Signed-off-by: Daiki Yamashita <yamashita.daiki.z01@as.ntt-tx.co.jp>
Signed-off-by: Naoki Takada <takada.naoki@lab.ntt.co.jp>
---
 docs/spp_vf/how_to_use.md   |  6 ------
 docs/spp_vf/sample_usage.md | 10 +---------
 2 files changed, 1 insertion(+), 15 deletions(-)

diff --git a/docs/spp_vf/how_to_use.md b/docs/spp_vf/how_to_use.md
index e56d5e3..dee4465 100644
--- a/docs/spp_vf/how_to_use.md
+++ b/docs/spp_vf/how_to_use.md
@@ -100,9 +100,6 @@ it is required additional network configurations on host and guest VMss.
 # Interface for vhost
 $ sudo ifconfig [IF_NAME] inet [IP_ADDR] netmask [NETMASK] up
 
-# Register host2 to arp table
-$ sudo arp -s [IP_ADDR] [MAC_ADDR] -i [IF_NAME]
-
 # Disable offload for vhost interface
 $ sudo ethtool -K [IF_NAME] tx off
 ```
@@ -110,9 +107,6 @@ $ sudo ethtool -K [IF_NAME] tx off
 #### Host2
 
 ```sh
-# Register VM to arp table
-$ sudo arp -s [IP_ADDR] [MAC_ADDR] -i [IF_NAME]
-
 # Disable offload for VM interface
 $ ethtool -K [IF_NAME] tx off
 ```
diff --git a/docs/spp_vf/sample_usage.md b/docs/spp_vf/sample_usage.md
index 5220184..dcc051a 100644
--- a/docs/spp_vf/sample_usage.md
+++ b/docs/spp_vf/sample_usage.md
@@ -71,7 +71,7 @@ set `-oStrictHostKeyChecking=no` option for ssh.
   $ ssh -oStrictHostKeyChecking=no sppuser@192.168.122.31
   ```
 
-Up interfaces for vhost and register them to arp table inside spp-vm1.
+Up interfaces for vhost inside spp-vm1.
 In addition, you have to disable TCP offload function, or ssh is faled
 after configuration is done.
 
@@ -80,10 +80,6 @@ after configuration is done.
   $ sudo ifconfig ens4 inet 192.168.140.21 netmask 255.255.255.0 up
   $ sudo ifconfig ens5 inet 192.168.150.22 netmask 255.255.255.0 up
 
-  # register to arp table
-  $ sudo arp -s 192.168.140.11 a0:36:9f:78:86:78 -i ens4
-  $ sudo arp -s 192.168.150.13 a0:36:9f:6c:ed:bc -i ens5
-
   # diable TCP offload
   $ sudo ethtool -K ens4 tx off
   $ sudo ethtool -K ens5 tx off
@@ -98,10 +94,6 @@ Configurations for spp-vm2 is same as spp-vm1.
   $ sudo ifconfig ens4 inet 192.168.140.31 netmask 255.255.255.0 up
   $ sudo ifconfig ens5 inet 192.168.150.32 netmask 255.255.255.0 up
 
-  # register to arp table
-  $ sudo arp -s 192.168.140.11 a0:36:9f:78:86:78 -i ens4
-  $ sudo arp -s 192.168.150.13 a0:36:9f:6c:ed:bc -i ens5
-
   # diable TCP offload
   $ sudo ethtool -K ens4 tx off
   $ sudo ethtool -K ens5 tx off
-- 
1.9.1

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

* [spp] [PATCH 25/30] doc: add how to use vhost-user support
  2018-01-15 11:04 ` [spp] Proposal - spp_vf(SR-IOV like feature) addition to SPP Ferruh Yigit
                     ` (23 preceding siblings ...)
  2018-01-16  5:16   ` [spp] [PATCH 24/30] doc: fix required network configuration x-fn-spp
@ 2018-01-16  5:16   ` x-fn-spp
  2018-01-16  5:16   ` [spp] [PATCH 26/30] doc: add references to hugepages and isolcpus x-fn-spp
                     ` (4 subsequent siblings)
  29 siblings, 0 replies; 97+ messages in thread
From: x-fn-spp @ 2018-01-16  5:16 UTC (permalink / raw)
  To: spp

From: Hiroyuki Nakamura <nakamura.hioryuki@po.ntt-tx.co.jp>

add description on how to use vhost-user client mode.
* Add information on qemu-kvm version.
* Add and explan optional parameters of spp_vf.
* Update qemu parameter for vhost. (xml set by virsh)

Signed-off-by: Kentaro Watanabe <watanabe.kentaro.z01@as.ntt-tx.co.jp>
Signed-off-by: Naoki Takada <takada.naoki@lab.ntt.co.jp>
---
 docs/spp_vf/how_to_use.md   | 24 ++++++++++++++++++++----
 docs/spp_vf/sample_usage.md | 10 ++++++----
 docs/spp_vf/setup_guide.md  | 10 +++++-----
 3 files changed, 31 insertions(+), 13 deletions(-)

diff --git a/docs/spp_vf/how_to_use.md b/docs/spp_vf/how_to_use.md
index dee4465..32c1774 100644
--- a/docs/spp_vf/how_to_use.md
+++ b/docs/spp_vf/how_to_use.md
@@ -9,7 +9,7 @@ SPP_VF is a SR-IOV like network functionality for NFV.
 ## Environment
 
 * Ubuntu 16.04
-* qemu-kvm
+* qemu-kvm 2.7 or later
 * DPDK v17.05 or later
 
 ## Launch SPP
@@ -56,7 +56,10 @@ In `spp_vf`, spp secondary processes are launched by single command.
 Option of dpdk are refer to [dpdk documentation](http://dpdk.org/doc/guides/linux_gsg/build_sample_apps.html#running-a-sample-application).
 
 Options of `spp_vf` are
-  * TODO
+  * --client-id    : client id
+  * --config       : config file path
+  * -s             : Port for ip addr and spp secondary
+  * --vhost-client : vhost-user client enable setting
 
 Core assingment and network configuration are defined
 in JSON formatted config file.
@@ -65,7 +68,19 @@ config file (test/spp_config/spp_config/vf.json).
 
 ```sh
 $ sudo ./src/vf/x86_64-native-linuxapp-gcc/spp_vf \
--c 0x3ffd -n 4 --proc-type=secondary
+-c 0x3ffd -n 4 --proc-type=secondary \
+-- --client-id 1 -s 127.0.0.1:6666 --vhost-client
+```
+
+`--vhost-client` option is used when SPP is a client of vhost-user.
+By choosing not to use `--vhost-client` option,
+It may be possible to use SPP even in qemu (before 2.7 version)
+which can not be used as a vhost-user server.
+
+```sh
+$ sudo ./src/vf/x86_64-native-linuxapp-gcc/spp_vf \
+-c 0x3ffd -n 4 --proc-type=secondary \
+-- --client-id 1 -s 127.0.0.1:6666
 ```
 
 You can also indicate which of config you use explicitly with
@@ -78,7 +93,8 @@ defined in each of config files.
 ```sh
 $ sudo ./src/vf/x86_64-native-linuxapp-gcc/spp_vf \
 -c 0x3ffd -n 4 --proc-type=secondary \
--- --config /path/to/config/spp_vf1.json
+-- --client-id 1 --config /path/to/config/spp_vf1.json \
+-s 127.0.0.1:6666 --vhost-client
 ```
 
 ### SPP VM
diff --git a/docs/spp_vf/sample_usage.md b/docs/spp_vf/sample_usage.md
index dcc051a..47abbec 100644
--- a/docs/spp_vf/sample_usage.md
+++ b/docs/spp_vf/sample_usage.md
@@ -41,17 +41,19 @@ launch secondary process after launch primary process.
   $ sudo ./src/vf/x86_64-native-linuxapp-gcc/spp_vf \
   -c 0x00fd -n 4 --proc-type=secondary \
   -- \
-  --process-id 1 \
+  --client-id 1 \
   --config /path/to/spp_vf1_without_cmtab.json \
-  -s 127.0.0.1:11111
+  -s 127.0.0.1:11111 \
+  --vhost-client
 
   # start secondary 2
   $ sudo ./src/vf/x86_64-native-linuxapp-gcc/spp_vf \
   -c 0x3f01 -n 4 --proc-type=secondary \
   -- \
-  --process-id 2 \
+  --client-id 2 \
   --config /path/to/spp_vf2_without_cmtab.json \
-  -s 127.0.0.1:11112
+  -s 127.0.0.1:11112 \
+  --vhost-client
   ```
 
 ### Setup network configuration for VMs
diff --git a/docs/spp_vf/setup_guide.md b/docs/spp_vf/setup_guide.md
index 4684cf3..f24e43e 100644
--- a/docs/spp_vf/setup_guide.md
+++ b/docs/spp_vf/setup_guide.md
@@ -3,7 +3,7 @@
 ## Environment
 
 * Ubuntu 16.04
-* qemu-kvm
+* qemu-kvm 2.7 or later
 * DPDK v17.05 or later
 
 ## Setting
@@ -205,15 +205,15 @@ $ virsh edit [VM_NAME]
 	    <qemu:arg value='node,memdev=mem'/>
 	    <qemu:arg value='-mem-prealloc'/>
 	    <qemu:arg value='-chardev'/>
-	    <qemu:arg value='socket,id=chr0,path=/tmp/sock0'/>
+	    <qemu:arg value='socket,id=chr0,path=/tmp/sock0,server'/>
 	    <qemu:arg value='-device'/>
-	    <qemu:arg value='virtio-net-pci,netdev=vhost-net0'/>
+	    <qemu:arg value='virtio-net-pci,netdev=vhost-net0,mac=52:54:00:12:34:56'/>
 	    <qemu:arg value='-netdev'/>
 	    <qemu:arg value='vhost-user,id=vhost-net0,chardev=chr0,vhostforce'/>
 	    <qemu:arg value='-chardev'/>
-	    <qemu:arg value='socket,id=chr1,path=/tmp/sock1'/>
+	    <qemu:arg value='socket,id=chr1,path=/tmp/sock1,server'/>
 	    <qemu:arg value='-device'/>
-	    <qemu:arg value='virtio-net-pci,netdev=vhost-net1'/>
+	    <qemu:arg value='virtio-net-pci,netdev=vhost-net1,mac=52:54:00:12:34:57'/>
 	    <qemu:arg value='-netdev'/>
 	    <qemu:arg value='vhost-user,id=vhost-net1,chardev=chr1,vhostforce'/>
 	  </qemu:commandline>
-- 
1.9.1

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

* [spp] [PATCH 26/30] doc: add references to hugepages and isolcpus
  2018-01-15 11:04 ` [spp] Proposal - spp_vf(SR-IOV like feature) addition to SPP Ferruh Yigit
                     ` (24 preceding siblings ...)
  2018-01-16  5:16   ` [spp] [PATCH 25/30] doc: add how to use vhost-user support x-fn-spp
@ 2018-01-16  5:16   ` x-fn-spp
  2018-01-16  5:16   ` [spp] [PATCH 27/30] doc: remove description on classifier_table x-fn-spp
                     ` (3 subsequent siblings)
  29 siblings, 0 replies; 97+ messages in thread
From: x-fn-spp @ 2018-01-16  5:16 UTC (permalink / raw)
  To: spp

From: Hiroyuki Nakamura <nakamura.hioryuki@po.ntt-tx.co.jp>

Add references to hugepages and isolcpus as additional information
in setting grub config.

Signed-off-by: Daiki Yamashita <yamashita.daiki.z01@as.ntt-tx.co.jp>
Signed-off-by: Naoki Takada <takada.naoki@lab.ntt.co.jp>
---
 docs/spp_vf/setup_guide.md | 5 +++++
 1 file changed, 5 insertions(+)

diff --git a/docs/spp_vf/setup_guide.md b/docs/spp_vf/setup_guide.md
index f24e43e..af2e9bf 100644
--- a/docs/spp_vf/setup_guide.md
+++ b/docs/spp_vf/setup_guide.md
@@ -37,6 +37,11 @@ Change grub config for hugepages and isolcpus.
 GRUB_CMDLINE_LINUX_DEFAULT="isolcpus=2,4,6,8,10,12-18,20,22,24,26-42,44,46 hugepagesz=1G hugepages=36 default_hugepagesz=1G"
 ```
 
+For hugepages, isolcpus, refer to the dpdk documentation below.
+* [Use of Hugepages in the Linux Environment](http://dpdk.org/doc/guides/linux_gsg/sys_reqs.html#running-dpdk-applications)
+* [Using Linux Core Isolation to Reduce Context Switches](http://dpdk.org/doc/guides/linux_gsg/enable_func.html#using-linux-core-isolation-to-reduce-context-switches)
+* [Linux boot command line](http://dpdk.org/doc/guides/linux_gsg/nic_perf_intel_platform.html#linux-boot-command-line)
+
 You need to run `update-grub` and reboot to activate grub config.
 
 ```sh
-- 
1.9.1

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

* [spp] [PATCH 27/30] doc: remove description on classifier_table
  2018-01-15 11:04 ` [spp] Proposal - spp_vf(SR-IOV like feature) addition to SPP Ferruh Yigit
                     ` (25 preceding siblings ...)
  2018-01-16  5:16   ` [spp] [PATCH 26/30] doc: add references to hugepages and isolcpus x-fn-spp
@ 2018-01-16  5:16   ` x-fn-spp
  2018-01-16  5:16   ` [spp] [PATCH 28/30] doc: fix typos and erros in texts x-fn-spp
                     ` (2 subsequent siblings)
  29 siblings, 0 replies; 97+ messages in thread
From: x-fn-spp @ 2018-01-16  5:16 UTC (permalink / raw)
  To: spp

From: Hiroyuki Nakamura <nakamura.hioryuki@po.ntt-tx.co.jp>

Since classifire_table is being configured with commands and removed
from configuration file, description on classifier_table is removed.

Signed-off-by: Kentaro Watanabe <watanabe.kentaro.z01@as.ntt-tx.co.jp>
Signed-off-by: Naoki Takada <takada.naoki@lab.ntt.co.jp>
---
 docs/spp_vf/config_manual.md | 39 ++++-----------------------------------
 1 file changed, 4 insertions(+), 35 deletions(-)

diff --git a/docs/spp_vf/config_manual.md b/docs/spp_vf/config_manual.md
index f049407..05a342c 100644
--- a/docs/spp_vf/config_manual.md
+++ b/docs/spp_vf/config_manual.md
@@ -27,10 +27,7 @@ For example, resource ID of physical NIC of ID 0 is described as `phy:0`.
 ## Config Format
 
 Config files is described in JSON format.
-It consists of `vfs` and `classifier_table`.
-`vfs` defines each of spp_vf attributes and
-`classifier_table` defines MAC address and correnpond port for
-determining destination.
+Config file consists of `vfs` and defines the spp_vf attribute.
 
 ### Attributes in Config
 
@@ -42,14 +39,7 @@ determining destination.
       * core: Core ID forwarder running on.
       * type: Forwarder type (`forward`, `classifier_mac`, or `merger`).
       * rx_port: Resource ID(s) of rx port.
-      * tx_port: Resource ID of tx port. If 1:N, which means the dest is `classifier_mac`,
-                 directly described as `classifier_mac_table`.
-
-  * classifier_table
-    * name: Table name for classifier_mac, It MUST be "classifier_mac_table" in current implementation
-    * table: Set of MAC address and port for destination
-      * mac: MAC address
-      * port: Resource ID of port
+      * tx_port: Resource ID(s) of tx port.
 
 ## Sample Config
 
@@ -73,7 +63,7 @@ Here is default config `spp.json` and network diagram of it.
           "core": 3,
           "type": "classifier_mac",
           "rx_port": "ring:8",        // Rx port, It is not a list because type is classifier_mac
-          "tx_port_table": "classifier_mac_table"	// If type is classifier_mac, tx is classifier_mac_table
+          "tx_port": ["ring:0", "ring:1", "ring:4", "ring:5"]
         },
 
         {
@@ -139,28 +129,7 @@ Here is default config `spp.json` and network diagram of it.
         }
       ]
     }
-  ],
-  "classifier_table": {
-    "name":"classifier_mac_table",
-    "table": [
-      {
-        "mac":"52:54:00:12:34:56",
-        "port":"ring:0"
-      },
-      {
-        "mac":"52:54:00:12:34:57",
-        "port":"ring:4"
-      },
-      {
-        "mac":"52:54:00:12:34:58",
-        "port":"ring:1"
-      },
-      {
-        "mac":"52:54:00:12:34:59",
-        "port":"ring:5"
-      }
-    ]
-  }
+  ]
 }
 ```
 
-- 
1.9.1

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

* [spp] [PATCH 28/30] doc: fix typos and erros in texts
  2018-01-15 11:04 ` [spp] Proposal - spp_vf(SR-IOV like feature) addition to SPP Ferruh Yigit
                     ` (26 preceding siblings ...)
  2018-01-16  5:16   ` [spp] [PATCH 27/30] doc: remove description on classifier_table x-fn-spp
@ 2018-01-16  5:16   ` x-fn-spp
  2018-01-16  5:16   ` [spp] [PATCH 29/30] doc: update sample config section x-fn-spp
  2018-01-16  5:16   ` [spp] [PATCH 30/30] doc: align figure title position x-fn-spp
  29 siblings, 0 replies; 97+ messages in thread
From: x-fn-spp @ 2018-01-16  5:16 UTC (permalink / raw)
  To: spp

From: Hiroyuki Nakamura <nakamura.hioryuki@po.ntt-tx.co.jp>

* config_manual.md: correct explanation of 'name' attribute.
* how_to_use.md: correct default config file path.
* how_to_use.md: correct titles.
* correct typos.

Signed-off-by: Daiki Yamashita <yamashita.daiki.z01@as.ntt-tx.co.jp>
Signed-off-by: Naoki Takada <takada.naoki@lab.ntt.co.jp>
---
 docs/spp_vf/config_manual.md | 2 +-
 docs/spp_vf/how_to_use.md    | 8 ++++----
 docs/spp_vf/setup_guide.md   | 2 +-
 3 files changed, 6 insertions(+), 6 deletions(-)

diff --git a/docs/spp_vf/config_manual.md b/docs/spp_vf/config_manual.md
index 05a342c..cdf10b5 100644
--- a/docs/spp_vf/config_manual.md
+++ b/docs/spp_vf/config_manual.md
@@ -32,7 +32,7 @@ Config file consists of `vfs` and defines the spp_vf attribute.
 ### Attributes in Config
 
   * vfs
-    * name: Name of spp_vf component.
+    * name: Name of the configuration. Please set user as desired.
     * num_vhost: Number of vhosts spp_vf use.
     * num_ring: Number of rings spp_vf use.
     * functions: List of forwarders and its attributes (function means a forwarder).
diff --git a/docs/spp_vf/how_to_use.md b/docs/spp_vf/how_to_use.md
index 32c1774..a0da2e8 100644
--- a/docs/spp_vf/how_to_use.md
+++ b/docs/spp_vf/how_to_use.md
@@ -64,7 +64,7 @@ Options of `spp_vf` are
 Core assingment and network configuration are defined
 in JSON formatted config file.
 If you run `spp_vf` without giving config file, it refers default
-config file (test/spp_config/spp_config/vf.json).
+config file (/usr/local/etc/spp/spp.json).
 
 ```sh
 $ sudo ./src/vf/x86_64-native-linuxapp-gcc/spp_vf \
@@ -97,7 +97,7 @@ $ sudo ./src/vf/x86_64-native-linuxapp-gcc/spp_vf \
 -s 127.0.0.1:6666 --vhost-client
 ```
 
-### SPP VM
+### VM
 
 Launch VMs with `virsh` command.
 
@@ -108,9 +108,9 @@ $ virsh start [VM]
 ### Additional Network Configurations
 
 To enable processes running on the VM to communicate through spp,
-it is required additional network configurations on host and guest VMss.
+it is required additional network configurations on host and guest VMs.
 
-#### Host1
+#### Guest VMs 
 
 ```sh
 # Interface for vhost
diff --git a/docs/spp_vf/setup_guide.md b/docs/spp_vf/setup_guide.md
index af2e9bf..a20ae90 100644
--- a/docs/spp_vf/setup_guide.md
+++ b/docs/spp_vf/setup_guide.md
@@ -73,7 +73,7 @@ Finally, you unmount default hugepage.
 $ sudo unmount /dev/hugepages
 ```
 
-#### Install jasson
+#### Install jansson
 
 Network configuration is defined in JSON and `spp_vf` reads config from
 the file while launching.
-- 
1.9.1

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

* [spp] [PATCH 29/30] doc: update sample config section
  2018-01-15 11:04 ` [spp] Proposal - spp_vf(SR-IOV like feature) addition to SPP Ferruh Yigit
                     ` (27 preceding siblings ...)
  2018-01-16  5:16   ` [spp] [PATCH 28/30] doc: fix typos and erros in texts x-fn-spp
@ 2018-01-16  5:16   ` x-fn-spp
  2018-01-16  5:16   ` [spp] [PATCH 30/30] doc: align figure title position x-fn-spp
  29 siblings, 0 replies; 97+ messages in thread
From: x-fn-spp @ 2018-01-16  5:16 UTC (permalink / raw)
  To: spp

From: Hiroyuki Nakamura <nakamura.hioryuki@po.ntt-tx.co.jp>

Update "Sample Config" section in config_manual.md
according to the latest config version format.
Some errors are corrected.
* Replace network diagram ascii art to the link to
  spp_sample_config.svg.
* Change config example to the one aligned to the network diagram.
* Remove comments in config example since no comment is allowed
  in config file.

Signed-off-by: Kentaro Watanabe <watanabe.kentaro.z01@as.ntt-tx.co.jp>
Signed-off-by: Naoki Takada <takada.naoki@lab.ntt.co.jp>
---
 docs/spp_vf/config_manual.md      |  110 +--
 docs/spp_vf/spp_sample_config.svg | 1865 +++++++++++++++++++++++++++++++++++++
 2 files changed, 1878 insertions(+), 97 deletions(-)
 create mode 100644 docs/spp_vf/spp_sample_config.svg

diff --git a/docs/spp_vf/config_manual.md b/docs/spp_vf/config_manual.md
index 05a342c..6a741cc 100644
--- a/docs/spp_vf/config_manual.md
+++ b/docs/spp_vf/config_manual.md
@@ -50,22 +50,21 @@ Here is default config `spp.json` and network diagram of it.
   "vfs": [
     {
       "name": "vf0",
-      "num_vhost": 4,  // Number of vhosts
-      "num_ring": 9,   // Number of rings
-      "functions":[    // Attributes of forward,merge or classifier_mac
+      "num_vhost": 2,
+      "num_ring": 4,
+      "functions":[
         {
-          "core": 2,   // Core ID
-          "type": "merge",   // Forwarder type
-          "rx_port": ["phy:0", "phy:1"],  // Rx port, It MUST be a list for merge type
-          "tx_port": "ring:8"            // Tx port
+          "core": 2,
+          "type": "classifier_mac",
+          "rx_port": "phy:0",
+          "tx_port": ["ring:0", "ring:1"]
         },
         {
           "core": 3,
-          "type": "classifier_mac",
-          "rx_port": "ring:8",        // Rx port, It is not a list because type is classifier_mac
-          "tx_port": ["ring:0", "ring:1", "ring:4", "ring:5"]
+          "type": "merge",
+          "rx_port": ["ring:2", "ring:3"],
+          "tx_port": "phy:0"
         },
-
         {
           "core": 4,
           "type": "forward",
@@ -76,7 +75,7 @@ Here is default config `spp.json` and network diagram of it.
           "core": 5,
           "type": "forward",
           "rx_port": "ring:1",
-          "tx_port": "vhost:2"
+          "tx_port": "vhost:1"
         },
         {
           "core": 6,
@@ -87,45 +86,8 @@ Here is default config `spp.json` and network diagram of it.
         {
           "core": 7,
           "type": "forward",
-          "rx_port": "vhost:2",
-          "tx_port": "ring:3"
-        },
-        {
-          "core": 8,
-          "type": "merge",
-          "rx_port": ["ring:2", "ring:3"],
-          "tx_port": "phy:0"
-        },
-
-        {
-          "core": 9,
-          "type": "forward",
-          "rx_port": "ring:4",
-          "tx_port": "vhost:1"
-        },
-        {
-          "core": 10,
-          "type": "forward",
-          "rx_port": "ring:5",
-          "tx_port": "vhost:3"
-        },
-        {
-          "core": 11,
-          "type": "forward",
           "rx_port": "vhost:1",
-          "tx_port": "ring:6"
-        },
-        {
-          "core": 12,
-          "type": "forward",
-          "rx_port": "vhost:3",
-          "tx_port": "ring:7"
-        },
-        {
-          "core": 13,
-          "type": "merge",
-          "rx_port": ["ring:6", "ring:7"],
-          "tx_port": "phy:1"
+          "tx_port": "ring:3"
         }
       ]
     }
@@ -134,50 +96,4 @@ Here is default config `spp.json` and network diagram of it.
 ```
 
 Network diagram
-[TODO] Replace it to more readable SVG img.
-
-```
-+---------+  +-----------------------------------------------------------------------------------------------+
-|  host2  |  | Host1                                                                                         |
-|         |  |              +------------------------------------------------------+  +-------------------+  |
-|         |  |              | spp_vf                                               |  |                   |  |
-| +-----+ |  | +--------+   | +---+  +----+  +---+     +----+  +---+  +----------+ |  | +----------+      |  |
-| | nic <------>  nic0  +-----> M +--> r8 +--> C +-----> r0 +--> F +-->          +------>          |      |  |
-| +-----+ |  | +----+---+   | +-^-+  +----+  +-+-+     +----+  +---+  |          | |  | |          |      |  |
-|         |  |      ^       |   |              |                      |  vhost0  | |  | |    nic   |      |  |
-|         |  |      |       |   |              |       +----+  +---+  |          | |  | |          |      |  |
-|         |  |      |       |   |       +--------------+ r2 <--+ F <--+          <------+          |      |  |
-|         |  |      |       |   |       |      |       +----+  +---+  +----------+ |  | +----------+      |  |
-|         |  |      |       |   |       |      |                                   |  |             spp vm|  |
-|         |  |      |       |   |       |      |       +----+  +---+  +----------+ |  | +----------+      |  |
-|         |  |      |       |   |       |      +-------> r4 +--+ F +-->          +------>          |      |  |
-|         |  |      |       |   |    +--v--+   |       +----+  +---+  |          | |  | |          |      |  |
-|         |  |      +----------------+  M  |   |                      |  vhost1  | |  | |    nic   |      |  |
-|         |  |              |   |    +--^--+   |       +----+  +---+  |          | |  | |          |      |  |
-|         |  |              |   |       | +------------+ r6 +--+ F <--+          <------+          |      |  |
-|         |  |              |   |       | |    |       +----+  +---+  +----------+ |  | +----------+      |  |
-|         |  |              |   |       | |    |                                   |  |                   |  |
-|         |  |              |   |       | |    |                                   |  +-------------------+  |
-|         |  |              |   |       | |    |                                   |                         |
-|         |  |              |   |       | |    |                                   |  +-------------------+  |
-|         |  |              |   |       | |    |                                   |  |                   |  |
-| +-----+ |  | +--------+   |   |       | |    |       +----+  +---+  +----------+ |  | +----------+      |  |
-| | nic <------>  nic1  +-------+       | |    +-------> r1 +--+ F +-->          +------>          |      |  |
-| +-----+ |  | +----+---+   |           | |    |       +----+  +---+  |          | |  | |          |      |  |
-|         |  |      ^       |           | |    |                      |  vhost2  | |  | |    nic   |      |  |
-|         |  |      |       |           | |    |       +----+  +---+  |          | |  | |          |      |  |
-|         |  |      |       |           +--------------+ r3 +--+ F <--+          <------+          |      |  |
-|         |  |      |       |             |    |       +----+  +---+  +----------+ |  | +----------+      |  |
-|         |  |      |       |             |    |                                   |  |             spp vm|  |
-|         |  |      |       |             |    |       +----+  +---+  +----------+ |  | +----------+      |  |
-|         |  |      |       |             |    +-------> r5 +--+ F +-->          +------>          |      |  |
-|         |  |      |       |        +----v+           +----+  +---+  |          | |  | |          |      |  |
-|         |  |      +----------------+  M  |                          |  vhost3  | |  | |    nic   |      |  |
-|         |  |              |        +--^--+           +----+  +---+  |          | |  | |          |      |  |
-|         |  |              |           +--------------+ r7 +--+ F <--+          <------+          |      |  |
-|         |  |              |                          +----+  +---+  +----------+ |  | +----------+      |  |
-|         |  |              |                                                      |  |                   |  |
-|         |  |              +------------------------------------------------------+  +-------------------+  |
-|         |  |                                                                                               |
-+---------+  +-----------------------------------------------------------------------------------------------+
-```
+![spp_sample_config](spp_sample_config.svg)
diff --git a/docs/spp_vf/spp_sample_config.svg b/docs/spp_vf/spp_sample_config.svg
new file mode 100644
index 0000000..00069f3
--- /dev/null
+++ b/docs/spp_vf/spp_sample_config.svg
@@ -0,0 +1,1865 @@
+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+<!-- Created with Inkscape (http://www.inkscape.org/) -->
+
+<svg
+   xmlns:dc="http://purl.org/dc/elements/1.1/"
+   xmlns:cc="http://creativecommons.org/ns#"
+   xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
+   xmlns:svg="http://www.w3.org/2000/svg"
+   xmlns="http://www.w3.org/2000/svg"
+   xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
+   xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
+   width="172.52679mm"
+   height="120.57605mm"
+   viewBox="0 0 172.52679 120.57605"
+   version="1.1"
+   id="svg4746"
+   inkscape:version="0.92.2 (5c3e80d, 2017-08-06)"
+   sodipodi:docname="spp_sample_config.svg">
+  <defs
+     id="defs4740">
+    <marker
+       inkscape:isstock="true"
+       style="overflow:visible;"
+       id="marker6296"
+       refX="0.0"
+       refY="0.0"
+       orient="auto"
+       inkscape:stockid="Arrow2Lend">
+      <path
+         transform="scale(1.1) rotate(180) translate(1,0)"
+         d="M 8.7185878,4.0337352 L -2.2072895,0.016013256 L 8.7185884,-4.0017078 C 6.9730900,-1.6296469 6.9831476,1.6157441 8.7185878,4.0337352 z "
+         style="fill-rule:evenodd;stroke-width:0.625;stroke-linejoin:round;stroke:#000000;stroke-opacity:1;fill:#000000;fill-opacity:1"
+         id="path6294" />
+    </marker>
+    <marker
+       inkscape:stockid="Arrow2Lend"
+       orient="auto"
+       refY="0.0"
+       refX="0.0"
+       id="marker1654"
+       style="overflow:visible;"
+       inkscape:isstock="true">
+      <path
+         id="path1652"
+         style="fill-rule:evenodd;stroke-width:0.625;stroke-linejoin:round;stroke:#000000;stroke-opacity:1;fill:#000000;fill-opacity:1"
+         d="M 8.7185878,4.0337352 L -2.2072895,0.016013256 L 8.7185884,-4.0017078 C 6.9730900,-1.6296469 6.9831476,1.6157441 8.7185878,4.0337352 z "
+         transform="scale(1.1) rotate(180) translate(1,0)" />
+    </marker>
+    <marker
+       inkscape:stockid="SquareL"
+       orient="auto"
+       refY="0.0"
+       refX="0.0"
+       id="SquareL"
+       style="overflow:visible"
+       inkscape:isstock="true">
+      <path
+         id="path1432"
+         d="M -5.0,-5.0 L -5.0,5.0 L 5.0,5.0 L 5.0,-5.0 L -5.0,-5.0 z "
+         style="fill-rule:evenodd;stroke:#000000;stroke-width:1pt;stroke-opacity:1;fill:#000000;fill-opacity:1"
+         transform="scale(0.8)" />
+    </marker>
+    <marker
+       inkscape:stockid="Arrow2Lend"
+       orient="auto"
+       refY="0.0"
+       refX="0.0"
+       id="Arrow2Lend"
+       style="overflow:visible;"
+       inkscape:isstock="true"
+       inkscape:collect="always">
+      <path
+         id="path1383"
+         style="fill-rule:evenodd;stroke-width:0.625;stroke-linejoin:round;stroke:#000000;stroke-opacity:1;fill:#000000;fill-opacity:1"
+         d="M 8.7185878,4.0337352 L -2.2072895,0.016013256 L 8.7185884,-4.0017078 C 6.9730900,-1.6296469 6.9831476,1.6157441 8.7185878,4.0337352 z "
+         transform="scale(1.1) rotate(180) translate(1,0)" />
+    </marker>
+    <marker
+       inkscape:stockid="Arrow2Lstart"
+       orient="auto"
+       refY="0.0"
+       refX="0.0"
+       id="marker9343"
+       style="overflow:visible"
+       inkscape:isstock="true">
+      <path
+         id="path9341"
+         style="fill-rule:evenodd;stroke-width:0.625;stroke-linejoin:round;stroke:#000000;stroke-opacity:1;fill:#000000;fill-opacity:1"
+         d="M 8.7185878,4.0337352 L -2.2072895,0.016013256 L 8.7185884,-4.0017078 C 6.9730900,-1.6296469 6.9831476,1.6157441 8.7185878,4.0337352 z "
+         transform="scale(1.1) translate(1,0)" />
+    </marker>
+    <marker
+       inkscape:stockid="Arrow2Lstart"
+       orient="auto"
+       refY="0.0"
+       refX="0.0"
+       id="Arrow2Lstart"
+       style="overflow:visible"
+       inkscape:isstock="true">
+      <path
+         id="path1359"
+         style="fill-rule:evenodd;stroke-width:0.625;stroke-linejoin:round;stroke:#000000;stroke-opacity:1;fill:#000000;fill-opacity:1"
+         d="M 8.7185878,4.0337352 L -2.2072895,0.016013256 L 8.7185884,-4.0017078 C 6.9730900,-1.6296469 6.9831476,1.6157441 8.7185878,4.0337352 z "
+         transform="scale(1.1) translate(1,0)" />
+    </marker>
+    <marker
+       inkscape:isstock="true"
+       style="overflow:visible"
+       id="marker4626"
+       refX="0"
+       refY="0"
+       orient="auto"
+       inkscape:stockid="Arrow2Lend">
+      <path
+         inkscape:connector-curvature="0"
+         transform="matrix(-1.1,0,0,-1.1,-1.1,0)"
+         d="M 8.7185878,4.0337352 -2.2072895,0.01601326 8.7185884,-4.0017078 c -1.7454984,2.3720609 -1.7354408,5.6174519 -6e-7,8.035443 z"
+         style="fill:#000000;fill-opacity:1;fill-rule:evenodd;stroke:#000000;stroke-width:0.625;stroke-linejoin:round;stroke-opacity:1"
+         id="path4624" />
+    </marker>
+    <marker
+       inkscape:isstock="true"
+       style="overflow:visible"
+       id="marker3618"
+       refX="0"
+       refY="0"
+       orient="auto"
+       inkscape:stockid="Arrow2Lend">
+      <path
+         inkscape:connector-curvature="0"
+         transform="matrix(-1.1,0,0,-1.1,-1.1,0)"
+         d="M 8.7185878,4.0337352 -2.2072895,0.01601326 8.7185884,-4.0017078 c -1.7454984,2.3720609 -1.7354408,5.6174519 -6e-7,8.035443 z"
+         style="fill:#000000;fill-opacity:1;fill-rule:evenodd;stroke:#000000;stroke-width:0.625;stroke-linejoin:round;stroke-opacity:1"
+         id="path3616" />
+    </marker>
+    <marker
+       inkscape:isstock="true"
+       style="overflow:visible"
+       id="marker1780"
+       refX="0"
+       refY="0"
+       orient="auto"
+       inkscape:stockid="Arrow2Lend">
+      <path
+         inkscape:connector-curvature="0"
+         transform="matrix(-1.1,0,0,-1.1,-1.1,0)"
+         d="M 8.7185878,4.0337352 -2.2072895,0.01601326 8.7185884,-4.0017078 c -1.7454984,2.3720609 -1.7354408,5.6174519 -6e-7,8.035443 z"
+         style="fill:#000000;fill-opacity:1;fill-rule:evenodd;stroke:#000000;stroke-width:0.625;stroke-linejoin:round;stroke-opacity:1"
+         id="path1778" />
+    </marker>
+    <marker
+       inkscape:stockid="Arrow2Lend"
+       orient="auto"
+       refY="0.0"
+       refX="0.0"
+       id="marker1604"
+       style="overflow:visible;"
+       inkscape:isstock="true">
+      <path
+         id="path1362"
+         style="fill-rule:evenodd;stroke-width:0.625;stroke-linejoin:round;stroke:#000000;stroke-opacity:1;fill:#000000;fill-opacity:1"
+         d="M 8.7185878,4.0337352 L -2.2072895,0.016013256 L 8.7185884,-4.0017078 C 6.9730900,-1.6296469 6.9831476,1.6157441 8.7185878,4.0337352 z "
+         transform="scale(1.1) rotate(180) translate(1,0)" />
+    </marker>
+    <marker
+       inkscape:stockid="Arrow2Lend"
+       orient="auto"
+       refY="0"
+       refX="0"
+       id="marker6489"
+       style="overflow:visible"
+       inkscape:isstock="true">
+      <path
+         inkscape:connector-curvature="0"
+         id="path6487"
+         style="fill:#000000;fill-opacity:1;fill-rule:evenodd;stroke:#000000;stroke-width:0.625;stroke-linejoin:round;stroke-opacity:1"
+         d="M 8.7185878,4.0337352 -2.2072895,0.01601326 8.7185884,-4.0017078 c -1.7454984,2.3720609 -1.7354408,5.6174519 -6e-7,8.035443 z"
+         transform="matrix(-1.1,0,0,-1.1,-1.1,0)" />
+    </marker>
+    <marker
+       inkscape:stockid="Arrow2Lend"
+       orient="auto"
+       refY="0"
+       refX="0"
+       id="marker8593"
+       style="overflow:visible"
+       inkscape:isstock="true">
+      <path
+         inkscape:connector-curvature="0"
+         id="path8591"
+         style="fill:#000000;fill-opacity:1;fill-rule:evenodd;stroke:#000000;stroke-width:0.625;stroke-linejoin:round;stroke-opacity:1"
+         d="M 8.7185878,4.0337352 -2.2072895,0.01601326 8.7185884,-4.0017078 c -1.7454984,2.3720609 -1.7354408,5.6174519 -6e-7,8.035443 z"
+         transform="matrix(-1.1,0,0,-1.1,-1.1,0)" />
+    </marker>
+    <marker
+       inkscape:stockid="Arrow2Lend"
+       orient="auto"
+       refY="0"
+       refX="0"
+       id="marker8169"
+       style="overflow:visible"
+       inkscape:isstock="true">
+      <path
+         id="path8167"
+         style="fill:#000000;fill-opacity:1;fill-rule:evenodd;stroke:#000000;stroke-width:0.625;stroke-linejoin:round;stroke-opacity:1"
+         d="M 8.7185878,4.0337352 -2.2072895,0.01601326 8.7185884,-4.0017078 c -1.7454984,2.3720609 -1.7354408,5.6174519 -6e-7,8.035443 z"
+         transform="matrix(-1.1,0,0,-1.1,-1.1,0)"
+         inkscape:connector-curvature="0" />
+    </marker>
+    <marker
+       inkscape:stockid="Arrow1Lend"
+       orient="auto"
+       refY="0"
+       refX="0"
+       id="marker7739"
+       style="overflow:visible"
+       inkscape:isstock="true">
+      <path
+         id="path7737"
+         d="M 0,0 5,-5 -12.5,0 5,5 Z"
+         style="fill:#000000;fill-opacity:1;fill-rule:evenodd;stroke:#000000;stroke-width:1.00000003pt;stroke-opacity:1"
+         transform="matrix(-0.8,0,0,-0.8,-10,0)"
+         inkscape:connector-curvature="0" />
+    </marker>
+    <marker
+       inkscape:stockid="Arrow1Lend"
+       orient="auto"
+       refY="0"
+       refX="0"
+       id="Arrow1Lend"
+       style="overflow:visible"
+       inkscape:isstock="true">
+      <path
+         id="path5589"
+         d="M 0,0 5,-5 -12.5,0 5,5 Z"
+         style="fill:#000000;fill-opacity:1;fill-rule:evenodd;stroke:#000000;stroke-width:1.00000003pt;stroke-opacity:1"
+         transform="matrix(-0.8,0,0,-0.8,-10,0)"
+         inkscape:connector-curvature="0" />
+    </marker>
+    <marker
+       inkscape:isstock="true"
+       style="overflow:visible"
+       id="marker6959"
+       refX="0"
+       refY="0"
+       orient="auto"
+       inkscape:stockid="Arrow2Lend">
+      <path
+         inkscape:connector-curvature="0"
+         transform="matrix(-1.1,0,0,-1.1,-1.1,0)"
+         d="M 8.7185878,4.0337352 -2.2072895,0.01601326 8.7185884,-4.0017078 c -1.7454984,2.3720609 -1.7354408,5.6174519 -6e-7,8.035443 z"
+         style="fill:#000000;fill-opacity:1;fill-rule:evenodd;stroke:#000000;stroke-width:0.625;stroke-linejoin:round;stroke-opacity:1"
+         id="path6957" />
+    </marker>
+    <marker
+       inkscape:isstock="true"
+       style="overflow:visible"
+       id="marker6583"
+       refX="0"
+       refY="0"
+       orient="auto"
+       inkscape:stockid="Arrow2Lend">
+      <path
+         inkscape:connector-curvature="0"
+         transform="matrix(-1.1,0,0,-1.1,-1.1,0)"
+         d="M 8.7185878,4.0337352 -2.2072895,0.01601326 8.7185884,-4.0017078 c -1.7454984,2.3720609 -1.7354408,5.6174519 -6e-7,8.035443 z"
+         style="fill:#000000;fill-opacity:1;fill-rule:evenodd;stroke:#000000;stroke-width:0.625;stroke-linejoin:round;stroke-opacity:1"
+         id="path6581" />
+    </marker>
+    <marker
+       inkscape:isstock="true"
+       style="overflow:visible"
+       id="marker6219"
+       refX="0"
+       refY="0"
+       orient="auto"
+       inkscape:stockid="Arrow2Lend">
+      <path
+         inkscape:connector-curvature="0"
+         transform="matrix(-1.1,0,0,-1.1,-1.1,0)"
+         d="M 8.7185878,4.0337352 -2.2072895,0.01601326 8.7185884,-4.0017078 c -1.7454984,2.3720609 -1.7354408,5.6174519 -6e-7,8.035443 z"
+         style="fill:#000000;fill-opacity:1;fill-rule:evenodd;stroke:#000000;stroke-width:0.625;stroke-linejoin:round;stroke-opacity:1"
+         id="path6217" />
+    </marker>
+    <marker
+       inkscape:stockid="Arrow1Lstart"
+       orient="auto"
+       refY="0"
+       refX="0"
+       id="marker5849"
+       style="overflow:visible"
+       inkscape:isstock="true">
+      <path
+         id="path5586"
+         d="M 0,0 5,-5 -12.5,0 5,5 Z"
+         style="fill:#000000;fill-opacity:1;fill-rule:evenodd;stroke:#000000;stroke-width:1.00000003pt;stroke-opacity:1"
+         transform="matrix(0.8,0,0,0.8,10,0)"
+         inkscape:connector-curvature="0" />
+    </marker>
+    <marker
+       inkscape:stockid="Arrow2Lend"
+       orient="auto"
+       refY="0"
+       refX="0"
+       id="marker2605"
+       style="overflow:visible"
+       inkscape:isstock="true"
+       inkscape:collect="always">
+      <path
+         id="path2603"
+         style="fill:#000000;fill-opacity:1;fill-rule:evenodd;stroke:#000000;stroke-width:0.625;stroke-linejoin:round;stroke-opacity:1"
+         d="M 8.7185878,4.0337352 -2.2072895,0.01601326 8.7185884,-4.0017078 c -1.7454984,2.3720609 -1.7354408,5.6174519 -6e-7,8.035443 z"
+         transform="matrix(-1.1,0,0,-1.1,-1.1,0)"
+         inkscape:connector-curvature="0" />
+    </marker>
+    <marker
+       inkscape:stockid="Arrow2Lend"
+       orient="auto"
+       refY="0"
+       refX="0"
+       id="marker2218"
+       style="overflow:visible"
+       inkscape:isstock="true">
+      <path
+         id="path2216"
+         style="fill:#000000;fill-opacity:1;fill-rule:evenodd;stroke:#000000;stroke-width:0.625;stroke-linejoin:round;stroke-opacity:1"
+         d="M 8.7185878,4.0337352 -2.2072895,0.01601326 8.7185884,-4.0017078 c -1.7454984,2.3720609 -1.7354408,5.6174519 -6e-7,8.035443 z"
+         transform="matrix(-1.1,0,0,-1.1,-1.1,0)"
+         inkscape:connector-curvature="0" />
+    </marker>
+    <marker
+       inkscape:stockid="Arrow2Lend"
+       orient="auto"
+       refY="0"
+       refX="0"
+       id="marker1864"
+       style="overflow:visible"
+       inkscape:isstock="true">
+      <path
+         id="path1862"
+         style="fill:#000000;fill-opacity:1;fill-rule:evenodd;stroke:#000000;stroke-width:0.625;stroke-linejoin:round;stroke-opacity:1"
+         d="M 8.7185878,4.0337352 -2.2072895,0.01601326 8.7185884,-4.0017078 c -1.7454984,2.3720609 -1.7354408,5.6174519 -6e-7,8.035443 z"
+         transform="matrix(-1.1,0,0,-1.1,-1.1,0)"
+         inkscape:connector-curvature="0" />
+    </marker>
+    <marker
+       inkscape:stockid="Arrow2Lend"
+       orient="auto"
+       refY="0"
+       refX="0"
+       id="marker1516"
+       style="overflow:visible"
+       inkscape:isstock="true">
+      <path
+         id="path1514"
+         style="fill:#000000;fill-opacity:1;fill-rule:evenodd;stroke:#000000;stroke-width:0.625;stroke-linejoin:round;stroke-opacity:1"
+         d="M 8.7185878,4.0337352 -2.2072895,0.01601326 8.7185884,-4.0017078 c -1.7454984,2.3720609 -1.7354408,5.6174519 -6e-7,8.035443 z"
+         transform="matrix(-1.1,0,0,-1.1,-1.1,0)"
+         inkscape:connector-curvature="0" />
+    </marker>
+    <marker
+       inkscape:stockid="Arrow2Lend"
+       orient="auto"
+       refY="0"
+       refX="0"
+       id="marker1632"
+       style="overflow:visible"
+       inkscape:isstock="true">
+      <path
+         id="path1630"
+         style="fill:#000000;fill-opacity:1;fill-rule:evenodd;stroke:#000000;stroke-width:0.625;stroke-linejoin:round;stroke-opacity:1"
+         d="M 8.7185878,4.0337352 -2.2072895,0.01601326 8.7185884,-4.0017078 c -1.7454984,2.3720609 -1.7354408,5.6174519 -6e-7,8.035443 z"
+         transform="matrix(-1.1,0,0,-1.1,-1.1,0)"
+         inkscape:connector-curvature="0" />
+    </marker>
+    <marker
+       inkscape:stockid="Arrow2Lend"
+       orient="auto"
+       refY="0"
+       refX="0"
+       id="marker1626"
+       style="overflow:visible"
+       inkscape:isstock="true">
+      <path
+         id="path1624"
+         style="fill:#000000;fill-opacity:1;fill-rule:evenodd;stroke:#000000;stroke-width:0.625;stroke-linejoin:round;stroke-opacity:1"
+         d="M 8.7185878,4.0337352 -2.2072895,0.01601326 8.7185884,-4.0017078 c -1.7454984,2.3720609 -1.7354408,5.6174519 -6e-7,8.035443 z"
+         transform="matrix(-1.1,0,0,-1.1,-1.1,0)"
+         inkscape:connector-curvature="0" />
+    </marker>
+    <marker
+       inkscape:stockid="Arrow2Lend"
+       orient="auto"
+       refY="0"
+       refX="0"
+       id="marker1620"
+       style="overflow:visible"
+       inkscape:isstock="true">
+      <path
+         id="path1618"
+         style="fill:#000000;fill-opacity:1;fill-rule:evenodd;stroke:#000000;stroke-width:0.625;stroke-linejoin:round;stroke-opacity:1"
+         d="M 8.7185878,4.0337352 -2.2072895,0.01601326 8.7185884,-4.0017078 c -1.7454984,2.3720609 -1.7354408,5.6174519 -6e-7,8.035443 z"
+         transform="matrix(-1.1,0,0,-1.1,-1.1,0)"
+         inkscape:connector-curvature="0" />
+    </marker>
+    <marker
+       inkscape:stockid="Arrow2Lend"
+       orient="auto"
+       refY="0"
+       refX="0"
+       id="marker1614"
+       style="overflow:visible"
+       inkscape:isstock="true">
+      <path
+         id="path1612"
+         style="fill:#000000;fill-opacity:1;fill-rule:evenodd;stroke:#000000;stroke-width:0.625;stroke-linejoin:round;stroke-opacity:1"
+         d="M 8.7185878,4.0337352 -2.2072895,0.01601326 8.7185884,-4.0017078 c -1.7454984,2.3720609 -1.7354408,5.6174519 -6e-7,8.035443 z"
+         transform="matrix(-1.1,0,0,-1.1,-1.1,0)"
+         inkscape:connector-curvature="0" />
+    </marker>
+    <marker
+       inkscape:stockid="Arrow2Lend"
+       orient="auto"
+       refY="0"
+       refX="0"
+       id="marker1608"
+       style="overflow:visible"
+       inkscape:isstock="true">
+      <path
+         id="path1606"
+         style="fill:#000000;fill-opacity:1;fill-rule:evenodd;stroke:#000000;stroke-width:0.625;stroke-linejoin:round;stroke-opacity:1"
+         d="M 8.7185878,4.0337352 -2.2072895,0.01601326 8.7185884,-4.0017078 c -1.7454984,2.3720609 -1.7354408,5.6174519 -6e-7,8.035443 z"
+         transform="matrix(-1.1,0,0,-1.1,-1.1,0)"
+         inkscape:connector-curvature="0" />
+    </marker>
+    <marker
+       inkscape:stockid="Arrow2Lend"
+       orient="auto"
+       refY="0"
+       refX="0"
+       id="marker1560"
+       style="overflow:visible"
+       inkscape:isstock="true">
+      <path
+         id="path1558"
+         style="fill:#000000;fill-opacity:1;fill-rule:evenodd;stroke:#000000;stroke-width:0.625;stroke-linejoin:round;stroke-opacity:1"
+         d="M 8.7185878,4.0337352 -2.2072895,0.01601326 8.7185884,-4.0017078 c -1.7454984,2.3720609 -1.7354408,5.6174519 -6e-7,8.035443 z"
+         transform="matrix(-1.1,0,0,-1.1,-1.1,0)"
+         inkscape:connector-curvature="0" />
+    </marker>
+    <marker
+       inkscape:stockid="Arrow2Lend"
+       orient="auto"
+       refY="0"
+       refX="0"
+       id="marker1552"
+       style="overflow:visible"
+       inkscape:isstock="true">
+      <path
+         id="path1550"
+         style="fill:#000000;fill-opacity:1;fill-rule:evenodd;stroke:#000000;stroke-width:0.625;stroke-linejoin:round;stroke-opacity:1"
+         d="M 8.7185878,4.0337352 -2.2072895,0.01601326 8.7185884,-4.0017078 c -1.7454984,2.3720609 -1.7354408,5.6174519 -6e-7,8.035443 z"
+         transform="matrix(-1.1,0,0,-1.1,-1.1,0)"
+         inkscape:connector-curvature="0" />
+    </marker>
+    <marker
+       inkscape:isstock="true"
+       style="overflow:visible"
+       id="marker4611"
+       refX="0"
+       refY="0"
+       orient="auto"
+       inkscape:stockid="Arrow2Lend">
+      <path
+         transform="matrix(-1.1,0,0,-1.1,-1.1,0)"
+         d="M 8.7185878,4.0337352 -2.2072895,0.01601326 8.7185884,-4.0017078 c -1.7454984,2.3720609 -1.7354408,5.6174519 -6e-7,8.035443 z"
+         style="fill:#000000;fill-opacity:1;fill-rule:evenodd;stroke:#000000;stroke-width:0.625;stroke-linejoin:round;stroke-opacity:1"
+         id="path4609"
+         inkscape:connector-curvature="0" />
+    </marker>
+    <marker
+       inkscape:isstock="true"
+       style="overflow:visible"
+       id="marker26660"
+       refX="0"
+       refY="0"
+       orient="auto"
+       inkscape:stockid="Arrow2Lend"
+       inkscape:collect="always">
+      <path
+         transform="matrix(-1.1,0,0,-1.1,-1.1,0)"
+         d="M 8.7185878,4.0337352 -2.2072895,0.01601326 8.7185884,-4.0017078 c -1.7454984,2.3720609 -1.7354408,5.6174519 -6e-7,8.035443 z"
+         style="fill:#000000;fill-opacity:1;fill-rule:evenodd;stroke:#000000;stroke-width:0.625;stroke-linejoin:round;stroke-opacity:1"
+         id="path26658"
+         inkscape:connector-curvature="0" />
+    </marker>
+    <marker
+       inkscape:isstock="true"
+       style="overflow:visible"
+       id="marker24654"
+       refX="0"
+       refY="0"
+       orient="auto"
+       inkscape:stockid="Arrow2Lstart">
+      <path
+         transform="matrix(1.1,0,0,1.1,1.1,0)"
+         d="M 8.7185878,4.0337352 -2.2072895,0.01601326 8.7185884,-4.0017078 c -1.7454984,2.3720609 -1.7354408,5.6174519 -6e-7,8.035443 z"
+         style="fill:#000000;fill-opacity:1;fill-rule:evenodd;stroke:#000000;stroke-width:0.625;stroke-linejoin:round;stroke-opacity:1"
+         id="path24652"
+         inkscape:connector-curvature="0" />
+    </marker>
+    <marker
+       inkscape:isstock="true"
+       style="overflow:visible"
+       id="marker23978"
+       refX="0"
+       refY="0"
+       orient="auto"
+       inkscape:stockid="Arrow2Lend">
+      <path
+         transform="matrix(-1.1,0,0,-1.1,-1.1,0)"
+         d="M 8.7185878,4.0337352 -2.2072895,0.01601326 8.7185884,-4.0017078 c -1.7454984,2.3720609 -1.7354408,5.6174519 -6e-7,8.035443 z"
+         style="fill:#000000;fill-opacity:1;fill-rule:evenodd;stroke:#000000;stroke-width:0.625;stroke-linejoin:round;stroke-opacity:1"
+         id="path23976"
+         inkscape:connector-curvature="0" />
+    </marker>
+    <marker
+       inkscape:isstock="true"
+       style="overflow:visible"
+       id="marker23136"
+       refX="0"
+       refY="0"
+       orient="auto"
+       inkscape:stockid="Arrow2Lend">
+      <path
+         transform="matrix(-1.1,0,0,-1.1,-1.1,0)"
+         d="M 8.7185878,4.0337352 -2.2072895,0.01601326 8.7185884,-4.0017078 c -1.7454984,2.3720609 -1.7354408,5.6174519 -6e-7,8.035443 z"
+         style="fill:#000000;fill-opacity:1;fill-rule:evenodd;stroke:#000000;stroke-width:0.625;stroke-linejoin:round;stroke-opacity:1"
+         id="path23134"
+         inkscape:connector-curvature="0" />
+    </marker>
+    <marker
+       inkscape:isstock="true"
+       style="overflow:visible"
+       id="marker22960"
+       refX="0"
+       refY="0"
+       orient="auto"
+       inkscape:stockid="Arrow2Lstart">
+      <path
+         transform="matrix(1.1,0,0,1.1,1.1,0)"
+         d="M 8.7185878,4.0337352 -2.2072895,0.01601326 8.7185884,-4.0017078 c -1.7454984,2.3720609 -1.7354408,5.6174519 -6e-7,8.035443 z"
+         style="fill:#000000;fill-opacity:1;fill-rule:evenodd;stroke:#000000;stroke-width:0.625;stroke-linejoin:round;stroke-opacity:1"
+         id="path22958"
+         inkscape:connector-curvature="0" />
+    </marker>
+    <marker
+       inkscape:isstock="true"
+       style="overflow:visible"
+       id="marker14793"
+       refX="0"
+       refY="0"
+       orient="auto"
+       inkscape:stockid="Arrow2Lend">
+      <path
+         transform="matrix(-1.1,0,0,-1.1,-1.1,0)"
+         d="M 8.7185878,4.0337352 -2.2072895,0.01601326 8.7185884,-4.0017078 c -1.7454984,2.3720609 -1.7354408,5.6174519 -6e-7,8.035443 z"
+         style="fill:#000000;fill-opacity:1;fill-rule:evenodd;stroke:#000000;stroke-width:0.625;stroke-linejoin:round;stroke-opacity:1"
+         id="path14791"
+         inkscape:connector-curvature="0" />
+    </marker>
+    <marker
+       inkscape:isstock="true"
+       style="overflow:visible"
+       id="marker13092"
+       refX="0"
+       refY="0"
+       orient="auto"
+       inkscape:stockid="Arrow2Lend">
+      <path
+         transform="matrix(-1.1,0,0,-1.1,-1.1,0)"
+         d="M 8.7185878,4.0337352 -2.2072895,0.01601326 8.7185884,-4.0017078 c -1.7454984,2.3720609 -1.7354408,5.6174519 -6e-7,8.035443 z"
+         style="fill:#000000;fill-opacity:1;fill-rule:evenodd;stroke:#000000;stroke-width:0.625;stroke-linejoin:round;stroke-opacity:1"
+         id="path13090"
+         inkscape:connector-curvature="0" />
+    </marker>
+    <marker
+       inkscape:isstock="true"
+       style="overflow:visible"
+       id="marker12910"
+       refX="0"
+       refY="0"
+       orient="auto"
+       inkscape:stockid="Arrow2Lend">
+      <path
+         transform="matrix(-1.1,0,0,-1.1,-1.1,0)"
+         d="M 8.7185878,4.0337352 -2.2072895,0.01601326 8.7185884,-4.0017078 c -1.7454984,2.3720609 -1.7354408,5.6174519 -6e-7,8.035443 z"
+         style="fill:#000000;fill-opacity:1;fill-rule:evenodd;stroke:#000000;stroke-width:0.625;stroke-linejoin:round;stroke-opacity:1"
+         id="path12908"
+         inkscape:connector-curvature="0" />
+    </marker>
+    <marker
+       inkscape:isstock="true"
+       style="overflow:visible"
+       id="marker12568"
+       refX="0"
+       refY="0"
+       orient="auto"
+       inkscape:stockid="Arrow2Lend">
+      <path
+         transform="matrix(-1.1,0,0,-1.1,-1.1,0)"
+         d="M 8.7185878,4.0337352 -2.2072895,0.01601326 8.7185884,-4.0017078 c -1.7454984,2.3720609 -1.7354408,5.6174519 -6e-7,8.035443 z"
+         style="fill:#000000;fill-opacity:1;fill-rule:evenodd;stroke:#000000;stroke-width:0.625;stroke-linejoin:round;stroke-opacity:1"
+         id="path12566"
+         inkscape:connector-curvature="0" />
+    </marker>
+    <marker
+       inkscape:isstock="true"
+       style="overflow:visible"
+       id="marker5180"
+       refX="0"
+       refY="0"
+       orient="auto"
+       inkscape:stockid="Arrow1Lend">
+      <path
+         transform="matrix(-0.8,0,0,-0.8,-10,0)"
+         style="fill:#000000;fill-opacity:1;fill-rule:evenodd;stroke:#000000;stroke-width:1.00000003pt;stroke-opacity:1"
+         d="M 0,0 5,-5 -12.5,0 5,5 Z"
+         id="path5178"
+         inkscape:connector-curvature="0" />
+    </marker>
+    <marker
+       inkscape:stockid="Arrow1Lend"
+       orient="auto"
+       refY="0"
+       refX="0"
+       id="marker4816"
+       style="overflow:visible"
+       inkscape:isstock="true">
+      <path
+         id="path4814"
+         d="M 0,0 5,-5 -12.5,0 5,5 Z"
+         style="fill:#000000;fill-opacity:1;fill-rule:evenodd;stroke:#000000;stroke-width:1.00000003pt;stroke-opacity:1"
+         transform="matrix(-0.8,0,0,-0.8,-10,0)"
+         inkscape:connector-curvature="0" />
+    </marker>
+    <marker
+       inkscape:stockid="Arrow2Lend"
+       orient="auto"
+       refY="0"
+       refX="0"
+       id="marker4059"
+       style="overflow:visible"
+       inkscape:isstock="true">
+      <path
+         id="path4057"
+         style="fill:#000000;fill-opacity:1;fill-rule:evenodd;stroke:#000000;stroke-width:0.625;stroke-linejoin:round;stroke-opacity:1"
+         d="M 8.7185878,4.0337352 -2.2072895,0.01601326 8.7185884,-4.0017078 c -1.7454984,2.3720609 -1.7354408,5.6174519 -6e-7,8.035443 z"
+         transform="matrix(-1.1,0,0,-1.1,-1.1,0)"
+         inkscape:connector-curvature="0" />
+    </marker>
+    <marker
+       inkscape:stockid="Arrow1Lstart"
+       orient="auto"
+       refY="0"
+       refX="0"
+       id="Arrow1Lstart"
+       style="overflow:visible"
+       inkscape:isstock="true">
+      <path
+         id="path5293"
+         d="M 0,0 5,-5 -12.5,0 5,5 Z"
+         style="fill-rule:evenodd;stroke:#000000;stroke-width:1.00000003pt"
+         transform="matrix(0.8,0,0,0.8,10,0)"
+         inkscape:connector-curvature="0" />
+    </marker>
+    <marker
+       inkscape:stockid="Arrow2Lend"
+       orient="auto"
+       refY="0"
+       refX="0"
+       id="Arrow2Lend-4"
+       style="overflow:visible"
+       inkscape:isstock="true">
+      <path
+         inkscape:connector-curvature="0"
+         id="path2284-4"
+         style="fill:#000000;fill-opacity:1;fill-rule:evenodd;stroke:#000000;stroke-width:0.625;stroke-linejoin:round;stroke-opacity:1"
+         d="M 8.7185878,4.0337352 -2.2072895,0.01601326 8.7185884,-4.0017078 c -1.7454984,2.3720609 -1.7354408,5.6174519 -6e-7,8.035443 z"
+         transform="matrix(-1.1,0,0,-1.1,-1.1,0)" />
+    </marker>
+    <marker
+       inkscape:stockid="Arrow2Lend"
+       orient="auto"
+       refY="0"
+       refX="0"
+       id="marker4059-8"
+       style="overflow:visible"
+       inkscape:isstock="true">
+      <path
+         inkscape:connector-curvature="0"
+         id="path4057-0"
+         style="fill:#000000;fill-opacity:1;fill-rule:evenodd;stroke:#000000;stroke-width:0.625;stroke-linejoin:round;stroke-opacity:1"
+         d="M 8.7185878,4.0337352 -2.2072895,0.01601326 8.7185884,-4.0017078 c -1.7454984,2.3720609 -1.7354408,5.6174519 -6e-7,8.035443 z"
+         transform="matrix(-1.1,0,0,-1.1,-1.1,0)" />
+    </marker>
+    <marker
+       inkscape:stockid="Arrow2Lend"
+       orient="auto"
+       refY="0"
+       refX="0"
+       id="Arrow2Lend-2"
+       style="overflow:visible"
+       inkscape:isstock="true">
+      <path
+         inkscape:connector-curvature="0"
+         id="path2284-6"
+         style="fill:#000000;fill-opacity:1;fill-rule:evenodd;stroke:#000000;stroke-width:0.625;stroke-linejoin:round;stroke-opacity:1"
+         d="M 8.7185878,4.0337352 -2.2072895,0.01601326 8.7185884,-4.0017078 c -1.7454984,2.3720609 -1.7354408,5.6174519 -6e-7,8.035443 z"
+         transform="matrix(-1.1,0,0,-1.1,-1.1,0)" />
+    </marker>
+    <marker
+       inkscape:stockid="Arrow2Lend"
+       orient="auto"
+       refY="0"
+       refX="0"
+       id="Arrow2Lend-2-4"
+       style="overflow:visible"
+       inkscape:isstock="true">
+      <path
+         inkscape:connector-curvature="0"
+         id="path2284-6-0"
+         style="fill:#000000;fill-opacity:1;fill-rule:evenodd;stroke:#000000;stroke-width:0.625;stroke-linejoin:round;stroke-opacity:1"
+         d="M 8.7185878,4.0337352 -2.2072895,0.01601326 8.7185884,-4.0017078 c -1.7454984,2.3720609 -1.7354408,5.6174519 -6e-7,8.035443 z"
+         transform="matrix(-1.1,0,0,-1.1,-1.1,0)" />
+    </marker>
+    <marker
+       inkscape:stockid="Arrow2Lend"
+       orient="auto"
+       refY="0"
+       refX="0"
+       id="Arrow2Lend-2-2"
+       style="overflow:visible"
+       inkscape:isstock="true">
+      <path
+         inkscape:connector-curvature="0"
+         id="path2284-6-6"
+         style="fill:#000000;fill-opacity:1;fill-rule:evenodd;stroke:#000000;stroke-width:0.625;stroke-linejoin:round;stroke-opacity:1"
+         d="M 8.7185878,4.0337352 -2.2072895,0.01601326 8.7185884,-4.0017078 c -1.7454984,2.3720609 -1.7354408,5.6174519 -6e-7,8.035443 z"
+         transform="matrix(-1.1,0,0,-1.1,-1.1,0)" />
+    </marker>
+    <marker
+       inkscape:stockid="Arrow2Lend"
+       orient="auto"
+       refY="0"
+       refX="0"
+       id="Arrow2Lend-2-6"
+       style="overflow:visible"
+       inkscape:isstock="true">
+      <path
+         inkscape:connector-curvature="0"
+         id="path2284-6-3"
+         style="fill:#000000;fill-opacity:1;fill-rule:evenodd;stroke:#000000;stroke-width:0.625;stroke-linejoin:round;stroke-opacity:1"
+         d="M 8.7185878,4.0337352 -2.2072895,0.01601326 8.7185884,-4.0017078 c -1.7454984,2.3720609 -1.7354408,5.6174519 -6e-7,8.035443 z"
+         transform="matrix(-1.1,0,0,-1.1,-1.1,0)" />
+    </marker>
+    <marker
+       inkscape:stockid="Arrow2Lend"
+       orient="auto"
+       refY="0"
+       refX="0"
+       id="Arrow2Lend-2-6-2"
+       style="overflow:visible"
+       inkscape:isstock="true">
+      <path
+         inkscape:connector-curvature="0"
+         id="path2284-6-3-4"
+         style="fill:#000000;fill-opacity:1;fill-rule:evenodd;stroke:#000000;stroke-width:0.625;stroke-linejoin:round;stroke-opacity:1"
+         d="M 8.7185878,4.0337352 -2.2072895,0.01601326 8.7185884,-4.0017078 c -1.7454984,2.3720609 -1.7354408,5.6174519 -6e-7,8.035443 z"
+         transform="matrix(-1.1,0,0,-1.1,-1.1,0)" />
+    </marker>
+    <marker
+       inkscape:stockid="Arrow2Lend"
+       orient="auto"
+       refY="0"
+       refX="0"
+       id="Arrow2Lend-5"
+       style="overflow:visible"
+       inkscape:isstock="true">
+      <path
+         inkscape:connector-curvature="0"
+         id="path2284-8"
+         style="fill:#000000;fill-opacity:1;fill-rule:evenodd;stroke:#000000;stroke-width:0.625;stroke-linejoin:round;stroke-opacity:1"
+         d="M 8.7185878,4.0337352 -2.2072895,0.01601326 8.7185884,-4.0017078 c -1.7454984,2.3720609 -1.7354408,5.6174519 -6e-7,8.035443 z"
+         transform="matrix(-1.1,0,0,-1.1,-1.1,0)" />
+    </marker>
+    <marker
+       inkscape:stockid="Arrow2Lend"
+       orient="auto"
+       refY="0"
+       refX="0"
+       id="marker4059-8-1"
+       style="overflow:visible"
+       inkscape:isstock="true">
+      <path
+         inkscape:connector-curvature="0"
+         id="path4057-0-9"
+         style="fill:#000000;fill-opacity:1;fill-rule:evenodd;stroke:#000000;stroke-width:0.625;stroke-linejoin:round;stroke-opacity:1"
+         d="M 8.7185878,4.0337352 -2.2072895,0.01601326 8.7185884,-4.0017078 c -1.7454984,2.3720609 -1.7354408,5.6174519 -6e-7,8.035443 z"
+         transform="matrix(-1.1,0,0,-1.1,-1.1,0)" />
+    </marker>
+    <marker
+       inkscape:stockid="Arrow2Lend"
+       orient="auto"
+       refY="0"
+       refX="0"
+       id="marker4059-8-1-6"
+       style="overflow:visible"
+       inkscape:isstock="true">
+      <path
+         inkscape:connector-curvature="0"
+         id="path4057-0-9-1"
+         style="fill:#000000;fill-opacity:1;fill-rule:evenodd;stroke:#000000;stroke-width:0.625;stroke-linejoin:round;stroke-opacity:1"
+         d="M 8.7185878,4.0337352 -2.2072895,0.01601326 8.7185884,-4.0017078 c -1.7454984,2.3720609 -1.7354408,5.6174519 -6e-7,8.035443 z"
+         transform="matrix(-1.1,0,0,-1.1,-1.1,0)" />
+    </marker>
+    <marker
+       inkscape:stockid="Arrow2Lend"
+       orient="auto"
+       refY="0"
+       refX="0"
+       id="Arrow2Lend-2-4-1"
+       style="overflow:visible"
+       inkscape:isstock="true">
+      <path
+         inkscape:connector-curvature="0"
+         id="path2284-6-0-0"
+         style="fill:#000000;fill-opacity:1;fill-rule:evenodd;stroke:#000000;stroke-width:0.625;stroke-linejoin:round;stroke-opacity:1"
+         d="M 8.7185878,4.0337352 -2.2072895,0.01601326 8.7185884,-4.0017078 c -1.7454984,2.3720609 -1.7354408,5.6174519 -6e-7,8.035443 z"
+         transform="matrix(-1.1,0,0,-1.1,-1.1,0)" />
+    </marker>
+    <marker
+       inkscape:stockid="Arrow2Lend"
+       orient="auto"
+       refY="0"
+       refX="0"
+       id="Arrow2Lend-2-4-1-9"
+       style="overflow:visible"
+       inkscape:isstock="true">
+      <path
+         inkscape:connector-curvature="0"
+         id="path2284-6-0-0-3"
+         style="fill:#000000;fill-opacity:1;fill-rule:evenodd;stroke:#000000;stroke-width:0.625;stroke-linejoin:round;stroke-opacity:1"
+         d="M 8.7185878,4.0337352 -2.2072895,0.01601326 8.7185884,-4.0017078 c -1.7454984,2.3720609 -1.7354408,5.6174519 -6e-7,8.035443 z"
+         transform="matrix(-1.1,0,0,-1.1,-1.1,0)" />
+    </marker>
+    <marker
+       inkscape:stockid="Arrow2Lend"
+       orient="auto"
+       refY="0"
+       refX="0"
+       id="Arrow2Lend-2-4-1-7"
+       style="overflow:visible"
+       inkscape:isstock="true">
+      <path
+         inkscape:connector-curvature="0"
+         id="path2284-6-0-0-0"
+         style="fill:#000000;fill-opacity:1;fill-rule:evenodd;stroke:#000000;stroke-width:0.625;stroke-linejoin:round;stroke-opacity:1"
+         d="M 8.7185878,4.0337352 -2.2072895,0.01601326 8.7185884,-4.0017078 c -1.7454984,2.3720609 -1.7354408,5.6174519 -6e-7,8.035443 z"
+         transform="matrix(-1.1,0,0,-1.1,-1.1,0)" />
+    </marker>
+    <marker
+       inkscape:stockid="Arrow2Lend"
+       orient="auto"
+       refY="0"
+       refX="0"
+       id="Arrow2Lend-2-4-1-7-7"
+       style="overflow:visible"
+       inkscape:isstock="true">
+      <path
+         inkscape:connector-curvature="0"
+         id="path2284-6-0-0-0-8"
+         style="fill:#000000;fill-opacity:1;fill-rule:evenodd;stroke:#000000;stroke-width:0.625;stroke-linejoin:round;stroke-opacity:1"
+         d="M 8.7185878,4.0337352 -2.2072895,0.01601326 8.7185884,-4.0017078 c -1.7454984,2.3720609 -1.7354408,5.6174519 -6e-7,8.035443 z"
+         transform="matrix(-1.1,0,0,-1.1,-1.1,0)" />
+    </marker>
+    <marker
+       inkscape:isstock="true"
+       style="overflow:visible"
+       id="marker5180-9"
+       refX="0"
+       refY="0"
+       orient="auto"
+       inkscape:stockid="Arrow1Lend">
+      <path
+         inkscape:connector-curvature="0"
+         transform="matrix(-0.8,0,0,-0.8,-10,0)"
+         style="fill:#000000;fill-opacity:1;fill-rule:evenodd;stroke:#000000;stroke-width:1.00000003pt;stroke-opacity:1"
+         d="M 0,0 5,-5 -12.5,0 5,5 Z"
+         id="path5178-1" />
+    </marker>
+    <marker
+       inkscape:isstock="true"
+       style="overflow:visible"
+       id="marker5180-9-9"
+       refX="0"
+       refY="0"
+       orient="auto"
+       inkscape:stockid="Arrow1Lend">
+      <path
+         inkscape:connector-curvature="0"
+         transform="matrix(-0.8,0,0,-0.8,-10,0)"
+         style="fill:#000000;fill-opacity:1;fill-rule:evenodd;stroke:#000000;stroke-width:1.00000003pt;stroke-opacity:1"
+         d="M 0,0 5,-5 -12.5,0 5,5 Z"
+         id="path5178-1-4" />
+    </marker>
+    <marker
+       inkscape:stockid="Arrow2Lstart"
+       orient="auto"
+       refY="0"
+       refX="0"
+       id="Arrow2Lstart-6"
+       style="overflow:visible"
+       inkscape:isstock="true">
+      <path
+         inkscape:connector-curvature="0"
+         id="path1110-1"
+         style="fill:#000000;fill-opacity:1;fill-rule:evenodd;stroke:#000000;stroke-width:0.625;stroke-linejoin:round;stroke-opacity:1"
+         d="M 8.7185878,4.0337352 -2.2072895,0.01601326 8.7185884,-4.0017078 c -1.7454984,2.3720609 -1.7354408,5.6174519 -6e-7,8.035443 z"
+         transform="matrix(1.1,0,0,1.1,1.1,0)" />
+    </marker>
+    <marker
+       inkscape:isstock="true"
+       style="overflow:visible"
+       id="marker14793-9"
+       refX="0"
+       refY="0"
+       orient="auto"
+       inkscape:stockid="Arrow2Lend">
+      <path
+         inkscape:connector-curvature="0"
+         transform="matrix(-1.1,0,0,-1.1,-1.1,0)"
+         d="M 8.7185878,4.0337352 -2.2072895,0.01601326 8.7185884,-4.0017078 c -1.7454984,2.3720609 -1.7354408,5.6174519 -6e-7,8.035443 z"
+         style="fill:#000000;fill-opacity:1;fill-rule:evenodd;stroke:#000000;stroke-width:0.625;stroke-linejoin:round;stroke-opacity:1"
+         id="path14791-9" />
+    </marker>
+    <marker
+       inkscape:isstock="true"
+       style="overflow:visible"
+       id="marker14793-5"
+       refX="0"
+       refY="0"
+       orient="auto"
+       inkscape:stockid="Arrow2Lend">
+      <path
+         inkscape:connector-curvature="0"
+         transform="matrix(-1.1,0,0,-1.1,-1.1,0)"
+         d="M 8.7185878,4.0337352 -2.2072895,0.01601326 8.7185884,-4.0017078 c -1.7454984,2.3720609 -1.7354408,5.6174519 -6e-7,8.035443 z"
+         style="fill:#000000;fill-opacity:1;fill-rule:evenodd;stroke:#000000;stroke-width:0.625;stroke-linejoin:round;stroke-opacity:1"
+         id="path14791-0" />
+    </marker>
+    <marker
+       inkscape:isstock="true"
+       style="overflow:visible"
+       id="marker14793-1"
+       refX="0"
+       refY="0"
+       orient="auto"
+       inkscape:stockid="Arrow2Lend">
+      <path
+         inkscape:connector-curvature="0"
+         transform="matrix(-1.1,0,0,-1.1,-1.1,0)"
+         d="M 8.7185878,4.0337352 -2.2072895,0.01601326 8.7185884,-4.0017078 c -1.7454984,2.3720609 -1.7354408,5.6174519 -6e-7,8.035443 z"
+         style="fill:#000000;fill-opacity:1;fill-rule:evenodd;stroke:#000000;stroke-width:0.625;stroke-linejoin:round;stroke-opacity:1"
+         id="path14791-4" />
+    </marker>
+    <marker
+       inkscape:isstock="true"
+       style="overflow:visible"
+       id="marker22960-5"
+       refX="0"
+       refY="0"
+       orient="auto"
+       inkscape:stockid="Arrow2Lstart">
+      <path
+         inkscape:connector-curvature="0"
+         transform="matrix(1.1,0,0,1.1,1.1,0)"
+         d="M 8.7185878,4.0337352 -2.2072895,0.01601326 8.7185884,-4.0017078 c -1.7454984,2.3720609 -1.7354408,5.6174519 -6e-7,8.035443 z"
+         style="fill:#000000;fill-opacity:1;fill-rule:evenodd;stroke:#000000;stroke-width:0.625;stroke-linejoin:round;stroke-opacity:1"
+         id="path22958-6" />
+    </marker>
+    <marker
+       inkscape:stockid="Arrow2Lend"
+       orient="auto"
+       refY="0"
+       refX="0"
+       id="marker1560-3"
+       style="overflow:visible"
+       inkscape:isstock="true">
+      <path
+         inkscape:connector-curvature="0"
+         id="path1558-3"
+         style="fill:#000000;fill-opacity:1;fill-rule:evenodd;stroke:#000000;stroke-width:0.625;stroke-linejoin:round;stroke-opacity:1"
+         d="M 8.7185878,4.0337352 -2.2072895,0.01601326 8.7185884,-4.0017078 c -1.7454984,2.3720609 -1.7354408,5.6174519 -6e-7,8.035443 z"
+         transform="matrix(-1.1,0,0,-1.1,-1.1,0)" />
+    </marker>
+    <marker
+       inkscape:isstock="true"
+       style="overflow:visible"
+       id="marker22960-7"
+       refX="0"
+       refY="0"
+       orient="auto"
+       inkscape:stockid="Arrow2Lstart">
+      <path
+         inkscape:connector-curvature="0"
+         transform="matrix(1.1,0,0,1.1,1.1,0)"
+         d="M 8.7185878,4.0337352 -2.2072895,0.01601326 8.7185884,-4.0017078 c -1.7454984,2.3720609 -1.7354408,5.6174519 -6e-7,8.035443 z"
+         style="fill:#000000;fill-opacity:1;fill-rule:evenodd;stroke:#000000;stroke-width:0.625;stroke-linejoin:round;stroke-opacity:1"
+         id="path22958-61" />
+    </marker>
+    <marker
+       inkscape:isstock="true"
+       style="overflow:visible"
+       id="marker22960-5-6"
+       refX="0"
+       refY="0"
+       orient="auto"
+       inkscape:stockid="Arrow2Lstart">
+      <path
+         inkscape:connector-curvature="0"
+         transform="matrix(1.1,0,0,1.1,1.1,0)"
+         d="M 8.7185878,4.0337352 -2.2072895,0.01601326 8.7185884,-4.0017078 c -1.7454984,2.3720609 -1.7354408,5.6174519 -6e-7,8.035443 z"
+         style="fill:#000000;fill-opacity:1;fill-rule:evenodd;stroke:#000000;stroke-width:0.625;stroke-linejoin:round;stroke-opacity:1"
+         id="path22958-6-8" />
+    </marker>
+    <marker
+       inkscape:isstock="true"
+       style="overflow:visible"
+       id="marker14793-1-4"
+       refX="0"
+       refY="0"
+       orient="auto"
+       inkscape:stockid="Arrow2Lend">
+      <path
+         inkscape:connector-curvature="0"
+         transform="matrix(-1.1,0,0,-1.1,-1.1,0)"
+         d="M 8.7185878,4.0337352 -2.2072895,0.01601326 8.7185884,-4.0017078 c -1.7454984,2.3720609 -1.7354408,5.6174519 -6e-7,8.035443 z"
+         style="fill:#000000;fill-opacity:1;fill-rule:evenodd;stroke:#000000;stroke-width:0.625;stroke-linejoin:round;stroke-opacity:1"
+         id="path14791-4-5" />
+    </marker>
+    <marker
+       inkscape:isstock="true"
+       style="overflow:visible"
+       id="marker22960-9"
+       refX="0"
+       refY="0"
+       orient="auto"
+       inkscape:stockid="Arrow2Lstart">
+      <path
+         inkscape:connector-curvature="0"
+         transform="matrix(1.1,0,0,1.1,1.1,0)"
+         d="M 8.7185878,4.0337352 -2.2072895,0.01601326 8.7185884,-4.0017078 c -1.7454984,2.3720609 -1.7354408,5.6174519 -6e-7,8.035443 z"
+         style="fill:#000000;fill-opacity:1;fill-rule:evenodd;stroke:#000000;stroke-width:0.625;stroke-linejoin:round;stroke-opacity:1"
+         id="path22958-60" />
+    </marker>
+    <marker
+       inkscape:isstock="true"
+       style="overflow:visible"
+       id="marker14793-1-9"
+       refX="0"
+       refY="0"
+       orient="auto"
+       inkscape:stockid="Arrow2Lend"
+       inkscape:collect="always">
+      <path
+         inkscape:connector-curvature="0"
+         transform="matrix(-1.1,0,0,-1.1,-1.1,0)"
+         d="M 8.7185878,4.0337352 -2.2072895,0.01601326 8.7185884,-4.0017078 c -1.7454984,2.3720609 -1.7354408,5.6174519 -6e-7,8.035443 z"
+         style="fill:#000000;fill-opacity:1;fill-rule:evenodd;stroke:#000000;stroke-width:0.625;stroke-linejoin:round;stroke-opacity:1"
+         id="path14791-4-1" />
+    </marker>
+    <marker
+       inkscape:isstock="true"
+       style="overflow:visible"
+       id="marker14793-1-9-6"
+       refX="0"
+       refY="0"
+       orient="auto"
+       inkscape:stockid="Arrow2Lend">
+      <path
+         inkscape:connector-curvature="0"
+         transform="matrix(-1.1,0,0,-1.1,-1.1,0)"
+         d="M 8.7185878,4.0337352 -2.2072895,0.01601326 8.7185884,-4.0017078 c -1.7454984,2.3720609 -1.7354408,5.6174519 -6e-7,8.035443 z"
+         style="fill:#000000;fill-opacity:1;fill-rule:evenodd;stroke:#000000;stroke-width:0.625;stroke-linejoin:round;stroke-opacity:1"
+         id="path14791-4-1-5" />
+    </marker>
+    <marker
+       inkscape:isstock="true"
+       style="overflow:visible"
+       id="marker22960-9-7"
+       refX="0"
+       refY="0"
+       orient="auto"
+       inkscape:stockid="Arrow2Lstart">
+      <path
+         inkscape:connector-curvature="0"
+         transform="matrix(1.1,0,0,1.1,1.1,0)"
+         d="M 8.7185878,4.0337352 -2.2072895,0.01601326 8.7185884,-4.0017078 c -1.7454984,2.3720609 -1.7354408,5.6174519 -6e-7,8.035443 z"
+         style="fill:#000000;fill-opacity:1;fill-rule:evenodd;stroke:#000000;stroke-width:0.625;stroke-linejoin:round;stroke-opacity:1"
+         id="path22958-60-6" />
+    </marker>
+  </defs>
+  <sodipodi:namedview
+     id="base"
+     pagecolor="#ffffff"
+     bordercolor="#666666"
+     borderopacity="1.0"
+     inkscape:pageopacity="0.0"
+     inkscape:pageshadow="2"
+     inkscape:zoom="0.9899495"
+     inkscape:cx="396.94548"
+     inkscape:cy="268.20932"
+     inkscape:document-units="mm"
+     inkscape:current-layer="layer1"
+     showgrid="false"
+     inkscape:window-width="1280"
+     inkscape:window-height="1002"
+     inkscape:window-x="78"
+     inkscape:window-y="-8"
+     inkscape:window-maximized="1"
+     fit-margin-top="0"
+     fit-margin-left="0"
+     fit-margin-right="0"
+     fit-margin-bottom="0"
+     viewbox-x="0"
+     scale-x="1" />
+  <metadata
+     id="metadata4743">
+    <rdf:RDF>
+      <cc:Work
+         rdf:about="">
+        <dc:format>image/svg+xml</dc:format>
+        <dc:type
+           rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
+        <dc:title></dc:title>
+      </cc:Work>
+    </rdf:RDF>
+  </metadata>
+  <g
+     inkscape:label="host"
+     inkscape:groupmode="layer"
+     id="layer1"
+     style="display:inline;opacity:0.98999999"
+     transform="translate(22.342263,-42.641668)">
+    <rect
+       style="fill:#ffffff;fill-opacity:1;stroke:#000000;stroke-width:0.3065601;stroke-miterlimit:4;stroke-dasharray:none"
+       id="rect5291"
+       width="133.51352"
+       height="83.053703"
+       x="16.513613"
+       y="43.498409"
+       ry="0" />
+    <text
+       xml:space="preserve"
+       style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:4.76249981px;line-height:1.25;font-family:sans-serif;-inkscape-font-specification:'sans-serif, Normal';font-variant-ligatures:normal;font-variant-caps:normal;font-variant-numeric:normal;font-feature-settings:normal;text-align:start;letter-spacing:0px;word-spacing:0px;writing-mode:lr-tb;text-anchor:start;fill:#000000;fill-opacity:1;stroke:none;stroke-width:0.19843748"
+       x="17.927746"
+       y="48.597805"
+       id="text5577"><tspan
+         sodipodi:role="line"
+         id="tspan5575"
+         x="17.927746"
+         y="48.597805"
+         style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:4.76249981px;font-family:sans-serif;-inkscape-font-specification:'sans-serif, Normal';font-variant-ligatures:normal;font-variant-caps:normal;font-variant-numeric:normal;font-feature-settings:normal;text-align:start;writing-mode:lr-tb;text-anchor:start;stroke-width:0.19843748">host1</tspan></text>
+    <flowRoot
+       xml:space="preserve"
+       id="flowRoot5610"
+       style="font-style:normal;font-weight:normal;font-size:40px;line-height:1.25;font-family:sans-serif;letter-spacing:0px;word-spacing:0px;fill:#000000;fill-opacity:1;stroke:none"
+       transform="scale(0.26458333)"><flowRegion
+         id="flowRegion5612"><rect
+           id="rect5614"
+           width="12.857142"
+           height="94.285713"
+           x="147.14285"
+           y="89.662544" /></flowRegion><flowPara
+         id="flowPara5616" /></flowRoot>    <rect
+       style="opacity:1;fill:#ffff00;fill-opacity:1;stroke:#000000;stroke-width:0.12471945;stroke-miterlimit:4;stroke-dasharray:none"
+       id="rect1139-1-3"
+       width="10.275963"
+       height="16.561275"
+       x="16.555996"
+       y="78.303352" />
+    <text
+       xml:space="preserve"
+       style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:3.70416665px;line-height:1.25;font-family:sans-serif;-inkscape-font-specification:'sans-serif, Normal';font-variant-ligatures:normal;font-variant-caps:normal;font-variant-numeric:normal;font-feature-settings:normal;text-align:start;letter-spacing:0px;word-spacing:0px;writing-mode:lr-tb;text-anchor:start;fill:#000000;fill-opacity:1;stroke:none;stroke-width:0.19843748"
+       x="17.14814"
+       y="87.313164"
+       id="text2024-9-4-2"><tspan
+         sodipodi:role="line"
+         id="tspan1377"
+         x="17.14814"
+         y="87.313164">NIC0</tspan></text>
+    <rect
+       style="display:inline;fill:#ffffff;fill-opacity:1;stroke:#000000;stroke-width:0.13039371;stroke-miterlimit:4;stroke-dasharray:none"
+       id="rect5291-3"
+       width="67.19873"
+       height="29.854179"
+       x="15.828302"
+       y="133.1078"
+       ry="0" />
+    <text
+       xml:space="preserve"
+       style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:4.76249981px;line-height:1.25;font-family:sans-serif;-inkscape-font-specification:'sans-serif, Normal';font-variant-ligatures:normal;font-variant-caps:normal;font-variant-numeric:normal;font-feature-settings:normal;text-align:start;letter-spacing:0px;word-spacing:0px;writing-mode:lr-tb;text-anchor:start;display:inline;fill:#000000;fill-opacity:1;stroke:none;stroke-width:0.19843748"
+       x="17.12682"
+       y="138.31961"
+       id="text5577-4"><tspan
+         sodipodi:role="line"
+         id="tspan29058"
+         x="17.12682"
+         y="138.31961"
+         style="stroke-width:0.19843748">host2</tspan></text>
+    <rect
+       style="display:inline;opacity:1;fill:#ffff00;fill-opacity:1;stroke:#000000;stroke-width:0.10945041;stroke-miterlimit:4;stroke-dasharray:none"
+       id="rect1139-1-3-3"
+       width="9.7703886"
+       height="13.414387"
+       x="15.910673"
+       y="141.81795" />
+    <text
+       xml:space="preserve"
+       style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:3.70416665px;line-height:1.25;font-family:sans-serif;-inkscape-font-specification:'sans-serif, Normal';font-variant-ligatures:normal;font-variant-caps:normal;font-variant-numeric:normal;font-feature-settings:normal;text-align:start;letter-spacing:0px;word-spacing:0px;writing-mode:lr-tb;text-anchor:start;display:inline;fill:#000000;fill-opacity:1;stroke:none;stroke-width:0.19843748"
+       x="16.710455"
+       y="149.19623"
+       id="text2024-9-4-2-1"><tspan
+         sodipodi:role="line"
+         id="tspan1379"
+         x="16.710455"
+         y="149.19623">NIC1</tspan></text>
+    <path
+       style="fill:none;stroke:#000000;stroke-width:0.2295;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1;marker-end:url(#marker6219)"
+       d="m -8.6649471,115.81761 c 0,0 2.429464,-24.597571 25.0354661,-33.266048"
+       id="path29105"
+       inkscape:connector-curvature="0" />
+    <path
+       style="display:inline;fill:none;stroke:#000000;stroke-width:0.1579186;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
+       d="m -0.09414816,115.70324 c 0,0 1.61663996,-17.511419 16.65936316,-23.682657"
+       id="path29105-6"
+       inkscape:connector-curvature="0" />
+    <path
+       style="display:inline;opacity:1;fill:#fff6d5;fill-opacity:1;stroke:#000000;stroke-width:0.27943447;stroke-miterlimit:4;stroke-dasharray:none"
+       d="m -6.0207701,101.38013 a 4.7988532,3.4968177 0 0 0 -4.7043999,2.80729 4.7988532,3.4968177 0 0 0 -2.107118,-0.35952 4.7988532,3.4968177 0 0 0 -4.798788,3.49669 4.7988532,3.4968177 0 0 0 0.666675,1.76985 4.7988532,3.4968177 0 0 0 -0.511754,-0.0215 4.7988532,3.4968177 0 0 0 -4.798789,3.49716 4.7988532,3.4968177 0 0 0 2.265001,2.96412 4.7988532,3.4968177 0 0 0 -1.645734,2.6304 4.7988532,3.4968177 0 0 0 3.540784,3.37048 4.7988532,3.4968177 0 0 0 -0.754294,1.87503 4.7988532,3.4968177 0 0 0 4.798786,3.49669 4.7988532,3.4968177 0 0 0 2.637498,-0.57753 4.7988532,3.4968177 0 0 0 4.7928659,3.37526 4.7988532,3.4968177 0 0 0 4.400904,-2.10642 4.7988532,3.4968177 0 0 0 2.10076694,0.3576 4.7988532,3.4968177 0 0 0 4.79879306,-3.49669 4.7988532,3.4968177 0 0 0 -4.26e-4,-0.006 4.7988532,3.4968177 0 0 0 0.155347,0.006 4.7988532,3.4968177 0 0 0 4.798795,-3.49668 4.7988532,3.4968177 0 0 0 -1.157688,-2.27185 4.7988532,3.4968177 0 0 0 3.3249111,-3.32315 4.7988532,3.4968177 0 0 0 -2.3551!
 641,-3.00475 4.7988532,3.4968177 0 0 0 0.497361,-1.54133 4.7988532,3.4968177 0 0 0 -3.906929,-3.43357 4.7988532,3.4968177 0 0 0 0.03724,-0.41259 4.7988532,3.4968177 0 0 0 -4.7992171,-3.49716 4.7988532,3.4968177 0 0 0 -2.6192899,0.56844 4.7988532,3.4968177 0 0 0 -4.656146,-2.66625 z"
+       id="path3410"
+       inkscape:connector-curvature="0" />
+    <text
+       xml:space="preserve"
+       style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:4.76249981px;line-height:1.25;font-family:sans-serif;-inkscape-font-specification:'sans-serif, Normal';font-variant-ligatures:normal;font-variant-caps:normal;font-variant-numeric:normal;font-feature-settings:normal;text-align:start;letter-spacing:0px;word-spacing:0px;writing-mode:lr-tb;text-anchor:start;display:inline;fill:#000000;fill-opacity:1;stroke:none;stroke-width:0.19843748"
+       x="-15.203279"
+       y="118.08487"
+       id="text5577-1"><tspan
+         sodipodi:role="line"
+         id="tspan28860"
+         x="-15.203279"
+         y="118.08487"
+         style="stroke-width:0.19843748">network</tspan></text>
+    <path
+       style="fill:none;stroke:#000000;stroke-width:0.17807341px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;marker-end:url(#marker8593)"
+       d="m -0.68301513,127.63222 c 0,0 1.39932195,16.54751 16.45012913,17.35664"
+       id="path3498"
+       inkscape:connector-curvature="0" />
+    <path
+       style="display:inline;opacity:0.98999999;fill:none;stroke:#000000;stroke-width:0.23871794px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
+       d="m -7.2736641,129.63943 c 0,0 1.97461,21.07376 23.2130541,22.10422"
+       id="path3498-4"
+       inkscape:connector-curvature="0" />
+  </g>
+  <g
+     inkscape:groupmode="layer"
+     id="layer3"
+     inkscape:label="spp_vf_process"
+     style="display:inline"
+     transform="translate(22.342263,-42.641668)">
+    <rect
+       style="fill:#ffccaa;fill-opacity:1;stroke:#000000;stroke-width:0.20625183;stroke-miterlimit:4;stroke-dasharray:none"
+       id="rect1763"
+       width="67.423866"
+       height="63.660942"
+       x="28.270718"
+       y="56.240303"
+       ry="3.3188167" />
+    <text
+       xml:space="preserve"
+       style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:3.70416689px;line-height:1.25;font-family:sans-serif;-inkscape-font-specification:'sans-serif, Normal';font-variant-ligatures:normal;font-variant-caps:normal;font-variant-numeric:normal;font-feature-settings:normal;text-align:start;letter-spacing:0px;word-spacing:0px;writing-mode:lr-tb;text-anchor:start;fill:#000000;fill-opacity:1;stroke:none;stroke-width:0.19843748"
+       x="31.534889"
+       y="61.07103"
+       id="text1767"><tspan
+         sodipodi:role="line"
+         id="tspan1765"
+         x="31.534889"
+         y="61.07103"
+         style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:3.70416689px;font-family:sans-serif;-inkscape-font-specification:'sans-serif, Normal';font-variant-ligatures:normal;font-variant-caps:normal;font-variant-numeric:normal;font-feature-settings:normal;text-align:start;writing-mode:lr-tb;text-anchor:start;stroke-width:0.19843748">spp_vf</tspan></text>
+  </g>
+  <g
+     inkscape:groupmode="layer"
+     id="layer4"
+     inkscape:label="guests"
+     style="display:inline"
+     transform="translate(22.342263,-42.641668)">
+    <rect
+       style="fill:#f9f9f9;fill-opacity:1;stroke:#000000;stroke-width:0.17461418;stroke-miterlimit:4;stroke-dasharray:none"
+       id="rect2020"
+       width="28.352047"
+       height="33.515587"
+       x="118.85268"
+       y="48.505085"
+       ry="2.7929652" />
+    <text
+       xml:space="preserve"
+       style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:3.70416689px;line-height:1.25;font-family:sans-serif;-inkscape-font-specification:'sans-serif, Normal';font-variant-ligatures:normal;font-variant-caps:normal;font-variant-numeric:normal;font-feature-settings:normal;text-align:start;letter-spacing:0px;word-spacing:0px;writing-mode:lr-tb;text-anchor:start;fill:#000000;fill-opacity:1;stroke:none;stroke-width:0.19843748"
+       x="119.69781"
+       y="56.421913"
+       id="text2024"><tspan
+         sodipodi:role="line"
+         id="tspan2022"
+         x="119.69781"
+         y="56.421913"
+         style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:3.70416689px;font-family:sans-serif;-inkscape-font-specification:'sans-serif, Normal';font-variant-ligatures:normal;font-variant-caps:normal;font-variant-numeric:normal;font-feature-settings:normal;text-align:start;writing-mode:lr-tb;text-anchor:start;stroke-width:0.19843748">guest vm1</tspan></text>
+    <rect
+       style="fill:#f9f9f9;fill-opacity:1;stroke:#000000;stroke-width:0.17601651;stroke-miterlimit:4;stroke-dasharray:none"
+       id="rect2020-5"
+       width="28.62668"
+       height="33.729359"
+       x="118.56235"
+       y="88.59964"
+       ry="2.8107796" />
+    <text
+       xml:space="preserve"
+       style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:3.70416689px;line-height:1.25;font-family:sans-serif;-inkscape-font-specification:'sans-serif, Normal';font-variant-ligatures:normal;font-variant-caps:normal;font-variant-numeric:normal;font-feature-settings:normal;text-align:start;letter-spacing:0px;word-spacing:0px;writing-mode:lr-tb;text-anchor:start;fill:#000000;fill-opacity:1;stroke:none;stroke-width:0.19843748"
+       x="119.40305"
+       y="93.332886"
+       id="text2024-5"><tspan
+         sodipodi:role="line"
+         id="tspan2202"
+         x="119.40305"
+         y="93.332886"
+         style="stroke-width:0.19843748">guest vm2</tspan></text>
+    <rect
+       style="opacity:1;fill:#ffff00;fill-opacity:1;stroke:#000000;stroke-width:0.11156943;stroke-miterlimit:4;stroke-dasharray:none"
+       id="rect1139"
+       width="10.349"
+       height="13.159518"
+       x="118.85532"
+       y="62.9557" />
+    <text
+       xml:space="preserve"
+       style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:3.70416689px;line-height:1.25;font-family:sans-serif;-inkscape-font-specification:'sans-serif, Normal';font-variant-ligatures:normal;font-variant-caps:normal;font-variant-numeric:normal;font-feature-settings:normal;text-align:start;letter-spacing:0px;word-spacing:0px;writing-mode:lr-tb;text-anchor:start;fill:#000000;fill-opacity:1;stroke:none;stroke-width:0.19843748"
+       x="119.4705"
+       y="70.884201"
+       id="text2024-9"><tspan
+         sodipodi:role="line"
+         id="tspan1504"
+         x="119.4705"
+         y="70.884201"
+         style="stroke-width:0.19843748">vNIC</tspan></text>
+    <rect
+       style="opacity:1;fill:#ffff00;fill-opacity:1;stroke:#000000;stroke-width:0.11284375;stroke-miterlimit:4;stroke-dasharray:none"
+       id="rect1139-1"
+       width="10.353926"
+       height="13.455435"
+       x="118.52364"
+       y="99.103775" />
+    <text
+       xml:space="preserve"
+       style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:3.70416689px;line-height:1.25;font-family:sans-serif;-inkscape-font-specification:'sans-serif, Normal';font-variant-ligatures:normal;font-variant-caps:normal;font-variant-numeric:normal;font-feature-settings:normal;text-align:start;letter-spacing:0px;word-spacing:0px;writing-mode:lr-tb;text-anchor:start;fill:#000000;fill-opacity:1;stroke:none;stroke-width:0.19843748"
+       x="119.14127"
+       y="106.98555"
+       id="text2024-9-4"><tspan
+         sodipodi:role="line"
+         id="tspan1502"
+         x="119.14127"
+         y="106.98555"
+         style="stroke-width:0.19843748">vNIC</tspan></text>
+  </g>
+  <g
+     inkscape:groupmode="layer"
+     id="layer2"
+     inkscape:label="spp_vf_threads"
+     style="display:inline;opacity:0.98999999"
+     transform="translate(22.342263,-42.641668)">
+    <path
+       style="fill:none;stroke:#000000;stroke-width:0.241;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;marker-end:url(#marker6296);stroke-miterlimit:4;stroke-dasharray:none"
+       d="M 100.80696,76.449807 C 92.088084,96.087573 92.088084,96.087573 92.088084,96.087573"
+       id="path6286"
+       inkscape:connector-curvature="0" />
+    <path
+       style="fill:none;stroke:#000000;stroke-width:0.241;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1;marker-end:url(#Arrow2Lend)"
+       d="m 89.320737,76.353127 c 9.452951,19.668818 9.452951,19.668818 9.452951,19.668818"
+       id="path6138"
+       inkscape:connector-curvature="0" />
+    <path
+       style="fill:none;stroke:#000000;stroke-width:0.241;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1;marker-end:url(#marker1780)"
+       d="m 25.766181,78.300049 5.164281,-5.567772"
+       id="path4812"
+       inkscape:connector-curvature="0" />
+    <rect
+       style="fill:#ffe6d5;fill-opacity:1;stroke:#000000;stroke-width:0.13431512;stroke-miterlimit:4;stroke-dasharray:none"
+       id="rect1769"
+       width="21.297846"
+       height="5.9898095"
+       x="30.552704"
+       y="67.062508"
+       ry="1.3525398" />
+    <text
+       xml:space="preserve"
+       style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:3.70416689px;line-height:1.25;font-family:sans-serif;-inkscape-font-specification:'sans-serif, Normal';font-variant-ligatures:normal;font-variant-caps:normal;font-variant-numeric:normal;font-feature-settings:normal;text-align:start;letter-spacing:0px;word-spacing:0px;writing-mode:lr-tb;text-anchor:start;fill:#000000;fill-opacity:1;stroke:none;stroke-width:0.19843748"
+       x="33.065685"
+       y="71.049599"
+       id="text1773"><tspan
+         sodipodi:role="line"
+         id="tspan1461"
+         x="33.065685"
+         y="71.049599"
+         style="stroke-width:0.19843748">classifier</tspan></text>
+    <g
+       id="g1969-0"
+       transform="matrix(0.74487285,0,0,2.6794736,5.5667349,-232.75776)"
+       style="fill:#dedbe3">
+      <rect
+         ry="1.8106976"
+         y="122.52335"
+         x="124.54029"
+         height="8.0187912"
+         width="18.980101"
+         id="rect1769-3-2-7-7"
+         style="fill:#eef4d7;stroke:#000000;stroke-width:0.14670815;stroke-miterlimit:4;stroke-dasharray:none" />
+    </g>
+    <text
+       xml:space="preserve"
+       style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:3.70416665px;line-height:1.25;font-family:sans-serif;-inkscape-font-specification:'sans-serif, Normal';font-variant-ligatures:normal;font-variant-caps:normal;font-variant-numeric:normal;font-feature-settings:normal;text-align:start;letter-spacing:0px;word-spacing:0px;writing-mode:lr-tb;text-anchor:start;fill:#000000;fill-opacity:1;stroke:none;stroke-width:0.21267372"
+       x="107.11629"
+       y="99.856544"
+       id="text1773-6-6-5-2-7"
+       transform="scale(0.93214046,1.0727997)"><tspan
+         sodipodi:role="line"
+         id="tspan1459"
+         x="107.11629"
+         y="99.856544">vhost1</tspan></text>
+    <path
+       style="fill:none;stroke:#000000;stroke-width:0.24075001;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1;marker-end:url(#marker14793)"
+       d="m 112.38085,66.046195 c 6.21402,0 6.21402,0 6.21402,0"
+       id="path14783"
+       inkscape:connector-curvature="0" />
+    <path
+       style="display:inline;fill:none;stroke:#000000;stroke-width:0.24075001;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1;marker-start:url(#marker22960)"
+       d="m 112.47118,108.69207 c 6.21402,0 6.21402,0 6.21402,0"
+       id="path14783-8"
+       inkscape:connector-curvature="0" />
+    <path
+       style="fill:none;stroke:#000000;stroke-width:0.24075001;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1;marker-end:url(#marker26660)"
+       d="M 35.08879,104.73064 25.534813,95.139839"
+       id="path26650"
+       inkscape:connector-curvature="0" />
+    <path
+       style="display:inline;fill:none;stroke:#000000;stroke-width:0.24075001;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1;marker-end:url(#marker14793-1)"
+       d="m 112.11808,102.39221 c 6.21402,0 6.21402,0 6.21402,0"
+       id="path14783-87"
+       inkscape:connector-curvature="0" />
+    <path
+       style="display:inline;fill:none;stroke:#000000;stroke-width:0.24075001;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1;marker-start:url(#marker22960-5)"
+       d="m 112.7259,72.352919 c 6.21402,0 6.21402,0 6.21402,0"
+       id="path14783-8-7"
+       inkscape:connector-curvature="0" />
+    <path
+       style="fill:none;stroke:#000000;stroke-width:0.24075001;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1;marker-end:url(#marker1560)"
+       d="m 91.74648,62.375041 c 6.66183,0 6.66183,0 6.66183,0"
+       id="path1556"
+       inkscape:connector-curvature="0" />
+    <path
+       style="display:inline;fill:none;stroke:#000000;stroke-width:0.23020414;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1;marker-start:url(#marker22960-7)"
+       d="m 92.70317,113.68427 c 5.68154,0 5.68154,0 5.68154,0"
+       id="path14783-8-2"
+       inkscape:connector-curvature="0" />
+    <path
+       style="display:inline;fill:none;stroke:#000000;stroke-width:0.24075001;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1;marker-end:url(#marker2218)"
+       d="m 71.365131,98.43499 c -21.806219,6.92139 -21.806219,6.92139 -21.806219,6.92139"
+       id="path2208"
+       inkscape:connector-curvature="0" />
+    <path
+       style="fill:none;stroke:#000000;stroke-width:0.24075001;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1;marker-end:url(#marker2605)"
+       d="M 71.648601,114.47803 C 49.558912,106.19594 49.558912,106.19594 49.558912,106.19594"
+       id="path2595"
+       inkscape:connector-curvature="0" />
+    <rect
+       style="fill:#ffe6d5;fill-opacity:1;stroke:#000000;stroke-width:0.12518337;stroke-miterlimit:4;stroke-dasharray:none"
+       id="rect1769-3"
+       width="18.472155"
+       height="5.9989409"
+       x="31.086758"
+       y="102.57824"
+       ry="1.3546017" />
+    <text
+       xml:space="preserve"
+       style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:3.70416689px;line-height:1.25;font-family:sans-serif;-inkscape-font-specification:'sans-serif, Normal';font-variant-ligatures:normal;font-variant-caps:normal;font-variant-numeric:normal;font-feature-settings:normal;text-align:start;letter-spacing:0px;word-spacing:0px;writing-mode:lr-tb;text-anchor:start;fill:#000000;fill-opacity:1;stroke:none;stroke-width:0.19843748"
+       x="33.207432"
+       y="106.17302"
+       id="text1773-6"><tspan
+         sodipodi:role="line"
+         id="tspan1463"
+         x="33.207432"
+         y="106.17302"
+         style="stroke-width:0.19843748">merger</tspan></text>
+    <g
+       id="g2295"
+       transform="matrix(0.75,0,0,0.75,-8.8329671,40.613879)">
+      <rect
+         ry="1.8039205"
+         y="25.020494"
+         x="106.67704"
+         height="7.9887786"
+         width="27.643539"
+         id="rect1769-3-2"
+         style="fill:#ffe6d5;fill-opacity:1;stroke:#000000;stroke-width:0.17672074;stroke-miterlimit:4;stroke-dasharray:none" />
+      <text
+         id="text1773-6-6"
+         y="30.337786"
+         x="107.9122"
+         style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:4.93888903px;line-height:1.25;font-family:sans-serif;-inkscape-font-specification:'sans-serif, Normal';font-variant-ligatures:normal;font-variant-caps:normal;font-variant-numeric:normal;font-feature-settings:normal;text-align:start;letter-spacing:0px;word-spacing:0px;writing-mode:lr-tb;text-anchor:start;fill:#000000;fill-opacity:1;stroke:none;stroke-width:0.26458332"
+         xml:space="preserve"><tspan
+           id="tspan3024"
+           sodipodi:role="line"
+           x="107.9122"
+           y="30.337786">forwarder</tspan></text>
+    </g>
+    <g
+       transform="matrix(0.75,0,0,0.75,-8.6426321,76.494617)"
+       style="display:inline"
+       id="g2295-3">
+      <rect
+         ry="1.8039205"
+         y="25.020494"
+         x="106.67704"
+         height="7.9887786"
+         width="27.643539"
+         id="rect1769-3-2-4"
+         style="fill:#ffe6d5;fill-opacity:1;stroke:#000000;stroke-width:0.17672074;stroke-miterlimit:4;stroke-dasharray:none" />
+      <text
+         id="text1773-6-6-0"
+         y="30.337786"
+         x="107.9122"
+         style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:4.93888903px;line-height:1.25;font-family:sans-serif;-inkscape-font-specification:'sans-serif, Normal';font-variant-ligatures:normal;font-variant-caps:normal;font-variant-numeric:normal;font-feature-settings:normal;text-align:start;letter-spacing:0px;word-spacing:0px;writing-mode:lr-tb;text-anchor:start;fill:#000000;fill-opacity:1;stroke:none;stroke-width:0.26458332"
+         xml:space="preserve"><tspan
+           id="tspan3024-5"
+           sodipodi:role="line"
+           x="107.9122"
+           y="30.337786">forwarder</tspan></text>
+    </g>
+    <g
+       transform="matrix(0.75,0,0,0.75,-8.8127251,55.913811)"
+       style="display:inline"
+       id="g2295-5">
+      <rect
+         ry="1.8039205"
+         y="25.020494"
+         x="106.67704"
+         height="7.9887786"
+         width="27.643539"
+         id="rect1769-3-2-2"
+         style="fill:#ffe6d5;fill-opacity:1;stroke:#000000;stroke-width:0.17672074;stroke-miterlimit:4;stroke-dasharray:none" />
+      <text
+         id="text1773-6-6-6"
+         y="30.337786"
+         x="107.9122"
+         style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:4.93888903px;line-height:1.25;font-family:sans-serif;-inkscape-font-specification:'sans-serif, Normal';font-variant-ligatures:normal;font-variant-caps:normal;font-variant-numeric:normal;font-feature-settings:normal;text-align:start;letter-spacing:0px;word-spacing:0px;writing-mode:lr-tb;text-anchor:start;fill:#000000;fill-opacity:1;stroke:none;stroke-width:0.26458332"
+         xml:space="preserve"><tspan
+           id="tspan3024-9"
+           sodipodi:role="line"
+           x="107.9122"
+           y="30.337786">forwarder</tspan></text>
+    </g>
+    <g
+       transform="matrix(0.75,0,0,0.75,-8.3591551,92.140786)"
+       style="display:inline"
+       id="g2295-0">
+      <rect
+         ry="1.8039205"
+         y="25.020494"
+         x="106.67704"
+         height="7.9887786"
+         width="27.643539"
+         id="rect1769-3-2-8"
+         style="fill:#ffe6d5;fill-opacity:1;stroke:#000000;stroke-width:0.17672074;stroke-miterlimit:4;stroke-dasharray:none" />
+      <text
+         id="text1773-6-6-8"
+         y="30.337786"
+         x="107.9122"
+         style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:4.93888903px;line-height:1.25;font-family:sans-serif;-inkscape-font-specification:'sans-serif, Normal';font-variant-ligatures:normal;font-variant-caps:normal;font-variant-numeric:normal;font-feature-settings:normal;text-align:start;letter-spacing:0px;word-spacing:0px;writing-mode:lr-tb;text-anchor:start;fill:#000000;fill-opacity:1;stroke:none;stroke-width:0.26458332"
+         xml:space="preserve"><tspan
+           id="tspan3024-96"
+           sodipodi:role="line"
+           x="107.9122"
+           y="30.337786">forwarder</tspan></text>
+    </g>
+    <rect
+       style="display:inline;fill:#ffccaa;fill-opacity:1;stroke:#000000;stroke-width:0.25501901;stroke-miterlimit:4;stroke-dasharray:none"
+       id="rect1769-5"
+       width="39.860424"
+       height="11.537248"
+       x="32.144726"
+       y="141.47868"
+       ry="2.6051891" />
+    <text
+       xml:space="preserve"
+       style="font-style:normal;font-weight:normal;font-size:3.88410258px;line-height:125%;font-family:sans-serif;letter-spacing:0px;word-spacing:0px;fill:#000000;fill-opacity:1;stroke:none;stroke-width:0.09710257px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
+       x="39.476479"
+       y="139.37953"
+       id="text237"
+       transform="scale(0.93752888,1.0666338)"><tspan
+         sodipodi:role="line"
+         id="tspan235"
+         x="39.476479"
+         y="139.37953"
+         style="stroke-width:0.09710257px">traffic generator</tspan></text>
+    <path
+       style="display:inline;fill:none;stroke:#000000;stroke-width:0.24075001;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1;marker-start:url(#marker22960-5-6)"
+       d="m 25.530253,151.42019 c 6.21402,0 6.21402,0 6.21402,0"
+       id="path14783-8-7-9"
+       inkscape:connector-curvature="0" />
+    <path
+       style="display:inline;fill:none;stroke:#000000;stroke-width:0.24075001;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1;marker-end:url(#marker14793-1-4)"
+       d="m 25.464472,144.88242 c 6.21402,0 6.21402,0 6.21402,0"
+       id="path14783-87-8"
+       inkscape:connector-curvature="0" />
+    <rect
+       style="display:inline;fill:#ffccaa;fill-opacity:1;stroke:#000000;stroke-width:0.11807317;stroke-miterlimit:4;stroke-dasharray:none"
+       id="rect1769-5-6-3"
+       width="10.223983"
+       height="9.6423111"
+       x="135.23622"
+       y="100.41351"
+       ry="2.1772995" />
+    <text
+       xml:space="preserve"
+       style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:3.70416665px;line-height:1.25;font-family:sans-serif;-inkscape-font-specification:'sans-serif, Normal';font-variant-ligatures:normal;font-variant-caps:normal;font-variant-numeric:normal;font-feature-settings:normal;text-align:start;letter-spacing:0px;word-spacing:0px;writing-mode:lr-tb;text-anchor:start;display:inline;fill:#000000;fill-opacity:1;stroke:none;stroke-width:0.21267371"
+       x="145.62817"
+       y="99.263878"
+       id="text1773-6-6-5-2-7-8"
+       transform="scale(0.93214045,1.0727997)"><tspan
+         y="99.263878"
+         x="145.62817"
+         sodipodi:role="line"
+         id="tspan1964-1-7-0"
+         style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:3.70416665px;font-family:sans-serif;-inkscape-font-specification:'sans-serif, Normal';font-variant-ligatures:normal;font-variant-caps:normal;font-variant-numeric:normal;font-feature-settings:normal;text-align:start;writing-mode:lr-tb;text-anchor:start;stroke-width:0.21267371">app2</tspan></text>
+    <path
+       style="display:inline;fill:none;stroke:#000000;stroke-width:0.24075001;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1;marker-start:url(#marker22960-9)"
+       d="m 129.07059,107.59371 c 6.21402,0 6.21402,0 6.21402,0"
+       id="path14783-8-5"
+       inkscape:connector-curvature="0" />
+    <path
+       style="display:inline;fill:none;stroke:#000000;stroke-width:0.24075001;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1;marker-end:url(#marker14793-1-9)"
+       d="m 128.71749,103.67511 c 6.21402,0 6.21402,0 6.21402,0"
+       id="path14783-87-5"
+       inkscape:connector-curvature="0" />
+    <rect
+       style="display:inline;fill:#ffccaa;fill-opacity:1;stroke:#000000;stroke-width:0.11807317;stroke-miterlimit:4;stroke-dasharray:none"
+       id="rect1769-5-6-3-4"
+       width="10.223983"
+       height="9.6423111"
+       x="135.76675"
+       y="63.378746"
+       ry="2.1772995" />
+    <text
+       xml:space="preserve"
+       style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:3.70416665px;line-height:1.25;font-family:sans-serif;-inkscape-font-specification:'sans-serif, Normal';font-variant-ligatures:normal;font-variant-caps:normal;font-variant-numeric:normal;font-feature-settings:normal;text-align:start;letter-spacing:0px;word-spacing:0px;writing-mode:lr-tb;text-anchor:start;display:inline;fill:#000000;fill-opacity:1;stroke:none;stroke-width:0.21267371"
+       x="146.19733"
+       y="64.742287"
+       id="text1773-6-6-5-2-7-8-7"
+       transform="scale(0.93214045,1.0727997)"><tspan
+         y="64.742287"
+         x="146.19733"
+         sodipodi:role="line"
+         id="tspan1964-1-7-0-4"
+         style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:3.70416665px;font-family:sans-serif;-inkscape-font-specification:'sans-serif, Normal';font-variant-ligatures:normal;font-variant-caps:normal;font-variant-numeric:normal;font-feature-settings:normal;text-align:start;writing-mode:lr-tb;text-anchor:start;stroke-width:0.21267371">app1</tspan></text>
+    <path
+       style="display:inline;fill:none;stroke:#000000;stroke-width:0.24075001;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1;marker-start:url(#marker22960-9-7)"
+       d="m 129.60112,70.558963 c 6.21402,0 6.21402,0 6.21402,0"
+       id="path14783-8-5-3"
+       inkscape:connector-curvature="0" />
+    <path
+       style="display:inline;fill:none;stroke:#000000;stroke-width:0.24075001;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1;marker-end:url(#marker14793-1-9-6)"
+       d="m 129.24802,66.640363 c 6.21402,0 6.21402,0 6.21402,0"
+       id="path14783-87-5-1"
+       inkscape:connector-curvature="0" />
+    <g
+       id="g1969"
+       transform="matrix(0.74487285,0,0,2.6794736,5.8732829,-268.99875)"
+       style="fill:#eef4d7">
+      <rect
+         ry="1.8106976"
+         y="122.52335"
+         x="124.54029"
+         height="8.0187912"
+         width="18.980101"
+         id="rect1769-3-2-7"
+         style="fill:#eef4d7;stroke:#000000;stroke-width:0.14670815;stroke-miterlimit:4;stroke-dasharray:none" />
+    </g>
+    <text
+       xml:space="preserve"
+       style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:3.70416665px;line-height:1.25;font-family:sans-serif;-inkscape-font-specification:'sans-serif, Normal';font-variant-ligatures:normal;font-variant-caps:normal;font-variant-numeric:normal;font-feature-settings:normal;text-align:start;letter-spacing:0px;word-spacing:0px;writing-mode:lr-tb;text-anchor:start;fill:#000000;fill-opacity:1;stroke:none;stroke-width:0.21267372"
+       x="107.18159"
+       y="65.916351"
+       id="text1773-6-6-5-2"
+       transform="scale(0.93214046,1.0727997)"><tspan
+         sodipodi:role="line"
+         id="tspan1457"
+         x="107.18159"
+         y="65.916351">vhost0</tspan></text>
+    <path
+       style="fill:none;stroke:#000000;stroke-width:0.241;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1;marker-end:url(#marker3618)"
+       d="M 51.850549,69.877318 C 71.174813,62.195833 71.174813,62.195833 71.174813,62.195833"
+       id="path3608"
+       inkscape:connector-curvature="0" />
+    <path
+       style="fill:none;stroke:#000000;stroke-width:0.241;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1;marker-end:url(#marker4626)"
+       d="m 51.850549,69.708341 c 19.344505,7.616675 19.344505,7.616675 19.344505,7.616675"
+       id="path4616"
+       inkscape:connector-curvature="0" />
+    <g
+       transform="matrix(0.9779811,0,0,0.74420896,-36.583751,-39.321733)"
+       style="display:inline;fill:#eef4d7"
+       id="g2377-5-42">
+      <ellipse
+         inkscape:transform-center-y="-59.720238"
+         inkscape:transform-center-x="13.229167"
+         ry="3.1499126"
+         rx="6.5516987"
+         cy="141.425"
+         cx="100.0881"
+         id="path1780-3-7-12-8"
+         style="display:inline;fill:#eef4d7;fill-opacity:1;stroke:#000000;stroke-width:0.35376999;stroke-miterlimit:4;stroke-dasharray:none" />
+      <text
+         transform="scale(0.93214046,1.0727997)"
+         id="text1773-6-6-5-2-7-4-3-60"
+         y="132.96213"
+         x="102.67519"
+         style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:4.93888903px;line-height:1.25;font-family:sans-serif;-inkscape-font-specification:'sans-serif, Normal';font-variant-ligatures:normal;font-variant-caps:normal;font-variant-numeric:normal;font-feature-settings:normal;text-align:start;letter-spacing:0px;word-spacing:0px;writing-mode:lr-tb;text-anchor:start;display:inline;fill:#eef4d7;fill-opacity:1;stroke:none;stroke-width:0.28356495"
+         xml:space="preserve"><tspan
+           y="132.96213"
+           x="102.67519"
+           id="tspan2372-8-0"
+           sodipodi:role="line">ring</tspan></text>
+    </g>
+    <text
+       xml:space="preserve"
+       style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:3.70416665px;line-height:1.25;font-family:sans-serif;-inkscape-font-specification:'sans-serif, Normal';font-variant-ligatures:normal;font-variant-caps:normal;font-variant-numeric:normal;font-feature-settings:normal;text-align:start;letter-spacing:0px;word-spacing:0px;writing-mode:lr-tb;text-anchor:start;display:inline;fill:#000000;fill-opacity:1;stroke:none;stroke-width:0.21267372"
+       x="61.204704"
+       y="62.727623"
+       id="text1773-6-6-5-2-7-4-4-2"
+       transform="scale(0.93214045,1.0727997)"><tspan
+         sodipodi:role="line"
+         id="tspan1387"
+         x="61.204704"
+         y="62.727623">ring0</tspan></text>
+    <g
+       transform="matrix(0.97798109,0,0,0.74420897,-36.693791,-31.801383)"
+       style="display:inline;opacity:0.98999999;fill:#eef4d7"
+       id="g2377-5-42-1">
+      <ellipse
+         inkscape:transform-center-y="-59.720238"
+         inkscape:transform-center-x="13.229167"
+         ry="3.1499126"
+         rx="6.5516987"
+         cy="141.425"
+         cx="100.0881"
+         id="path1780-3-7-12-8-7"
+         style="display:inline;fill:#eef4d7;fill-opacity:1;stroke:#000000;stroke-width:0.35376999;stroke-miterlimit:4;stroke-dasharray:none" />
+      <text
+         transform="scale(0.93214046,1.0727997)"
+         id="text1773-6-6-5-2-7-4-3-60-5"
+         y="132.96213"
+         x="102.67519"
+         style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:4.93888903px;line-height:1.25;font-family:sans-serif;-inkscape-font-specification:'sans-serif, Normal';font-variant-ligatures:normal;font-variant-caps:normal;font-variant-numeric:normal;font-feature-settings:normal;text-align:start;letter-spacing:0px;word-spacing:0px;writing-mode:lr-tb;text-anchor:start;display:inline;fill:#eef4d7;fill-opacity:1;stroke:none;stroke-width:0.28356495"
+         xml:space="preserve"><tspan
+           y="132.96213"
+           x="102.67519"
+           id="tspan2372-8-0-8"
+           sodipodi:role="line">ring</tspan></text>
+    </g>
+    <text
+       xml:space="preserve"
+       style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:3.70416667px;line-height:1.25;font-family:sans-serif;-inkscape-font-specification:'sans-serif, Normal';font-variant-ligatures:normal;font-variant-caps:normal;font-variant-numeric:normal;font-feature-settings:normal;text-align:start;letter-spacing:0px;word-spacing:0px;writing-mode:lr;text-anchor:start;display:inline;opacity:0.98999999;fill:#000000;fill-opacity:1;stroke:none;stroke-width:0.21267372;"
+       x="61.086658"
+       y="69.73761"
+       id="text1773-6-6-5-2-7-4-4-2-8"
+       transform="scale(0.93214045,1.0727997)"><tspan
+         sodipodi:role="line"
+         id="tspan1451">ring1</tspan></text>
+    <g
+       transform="matrix(0.97798109,0,0,0.74420897,-36.315815,-3.8311448)"
+       style="display:inline;opacity:0.98999999;fill:#eef4d7"
+       id="g2377-5-42-7">
+      <ellipse
+         inkscape:transform-center-y="-59.720238"
+         inkscape:transform-center-x="13.229167"
+         ry="3.1499126"
+         rx="6.5516987"
+         cy="141.425"
+         cx="100.0881"
+         id="path1780-3-7-12-8-3"
+         style="display:inline;fill:#eef4d7;fill-opacity:1;stroke:#000000;stroke-width:0.35376999;stroke-miterlimit:4;stroke-dasharray:none" />
+      <text
+         transform="scale(0.93214046,1.0727997)"
+         id="text1773-6-6-5-2-7-4-3-60-1"
+         y="132.96213"
+         x="102.67519"
+         style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:4.93888903px;line-height:1.25;font-family:sans-serif;-inkscape-font-specification:'sans-serif, Normal';font-variant-ligatures:normal;font-variant-caps:normal;font-variant-numeric:normal;font-feature-settings:normal;text-align:start;letter-spacing:0px;word-spacing:0px;writing-mode:lr-tb;text-anchor:start;display:inline;fill:#eef4d7;fill-opacity:1;stroke:none;stroke-width:0.28356495"
+         xml:space="preserve"><tspan
+           y="132.96213"
+           x="102.67519"
+           id="tspan2372-8-0-3"
+           sodipodi:role="line">ring</tspan></text>
+    </g>
+    <text
+       xml:space="preserve"
+       style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:3.70416667px;line-height:1.25;font-family:sans-serif;-inkscape-font-specification:'sans-serif, Normal';font-variant-ligatures:normal;font-variant-caps:normal;font-variant-numeric:normal;font-feature-settings:normal;text-align:start;letter-spacing:0px;word-spacing:0px;writing-mode:lr;text-anchor:start;display:inline;opacity:0.98999999;fill:#000000;fill-opacity:1;stroke:none;stroke-width:0.21267372;"
+       x="61.492149"
+       y="95.809807"
+       id="text1773-6-6-5-2-7-4-4-2-1"
+       transform="scale(0.93214045,1.0727997)"><tspan
+         sodipodi:role="line"
+         id="tspan1453">ring2</tspan></text>
+    <g
+       transform="matrix(0.97798109,0,0,0.74420897,-36.315815,5.8450456)"
+       style="display:inline;opacity:0.98999999;fill:#eef4d7"
+       id="g2377-5-42-6">
+      <ellipse
+         inkscape:transform-center-y="-59.720238"
+         inkscape:transform-center-x="13.229167"
+         ry="3.1499126"
+         rx="6.5516987"
+         cy="141.425"
+         cx="100.0881"
+         id="path1780-3-7-12-8-0"
+         style="display:inline;fill:#eef4d7;fill-opacity:1;stroke:#000000;stroke-width:0.35376999;stroke-miterlimit:4;stroke-dasharray:none" />
+      <text
+         transform="scale(0.93214046,1.0727997)"
+         id="text1773-6-6-5-2-7-4-3-60-6"
+         y="132.96213"
+         x="102.67519"
+         style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:4.93888903px;line-height:1.25;font-family:sans-serif;-inkscape-font-specification:'sans-serif, Normal';font-variant-ligatures:normal;font-variant-caps:normal;font-variant-numeric:normal;font-feature-settings:normal;text-align:start;letter-spacing:0px;word-spacing:0px;writing-mode:lr-tb;text-anchor:start;display:inline;fill:#eef4d7;fill-opacity:1;stroke:none;stroke-width:0.28356495"
+         xml:space="preserve"><tspan
+           y="132.96213"
+           x="102.67519"
+           id="tspan2372-8-0-5"
+           sodipodi:role="line">ring</tspan></text>
+    </g>
+    <text
+       xml:space="preserve"
+       style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:3.70416667px;line-height:1.25;font-family:sans-serif;-inkscape-font-specification:'sans-serif, Normal';font-variant-ligatures:normal;font-variant-caps:normal;font-variant-numeric:normal;font-feature-settings:normal;text-align:start;letter-spacing:0px;word-spacing:0px;writing-mode:lr;text-anchor:start;display:inline;opacity:0.98999999;fill:#000000;fill-opacity:1;stroke:none;stroke-width:0.21267372;"
+       x="61.492153"
+       y="104.82938"
+       id="text1773-6-6-5-2-7-4-4-2-3"
+       transform="scale(0.93214045,1.0727997)"><tspan
+         sodipodi:role="line"
+         id="tspan1455">ring3</tspan></text>
+  </g>
+</svg>
-- 
1.9.1

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

* [spp] [PATCH 30/30] doc: align figure title position
  2018-01-15 11:04 ` [spp] Proposal - spp_vf(SR-IOV like feature) addition to SPP Ferruh Yigit
                     ` (28 preceding siblings ...)
  2018-01-16  5:16   ` [spp] [PATCH 29/30] doc: update sample config section x-fn-spp
@ 2018-01-16  5:16   ` x-fn-spp
  29 siblings, 0 replies; 97+ messages in thread
From: x-fn-spp @ 2018-01-16  5:16 UTC (permalink / raw)
  To: spp

From: Hiroyuki Nakamura <nakamura.hioryuki@po.ntt-tx.co.jp>

Align the position of figure title "Network diagram"

Signed-off-by: Kentaro Watanabe <watanabe.kentaro.z01@as.ntt-tx.co.jp>
Signed-off-by: Naoki Takada <takada.naoki@lab.ntt.co.jp>
---
 docs/spp_vf/config_manual.md | 1 +
 1 file changed, 1 insertion(+)

diff --git a/docs/spp_vf/config_manual.md b/docs/spp_vf/config_manual.md
index 49f9701..656bd88 100644
--- a/docs/spp_vf/config_manual.md
+++ b/docs/spp_vf/config_manual.md
@@ -96,4 +96,5 @@ Here is default config `spp.json` and network diagram of it.
 ```
 
 Network diagram
+
 ![spp_sample_config](spp_sample_config.svg)
-- 
1.9.1

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

* Re: [spp] [PATCH 01/30] doc: add setup guide
  2018-01-16  5:16   ` [spp] [PATCH 01/30] doc: add setup guide x-fn-spp
@ 2018-01-19  0:52     ` Yasufumi Ogawa
  2018-01-22 14:37       ` Ferruh Yigit
  0 siblings, 1 reply; 97+ messages in thread
From: Yasufumi Ogawa @ 2018-01-19  0:52 UTC (permalink / raw)
  To: x-fn-spp, spp

On 2018/01/16 14:16, x-fn-spp@sl.ntt-tx.co.jp wrote:
> From: Hiroyuki Nakamura <nakamura.hioryuki@po.ntt-tx.co.jp>
> 
> Hi all,
> 
>> Series applied, thanks.
> 
> Ferruh, thank you for accepting our patches.
> 
> We will post the document patches for spp_vf on DPDK17.08 in the
> following emails.
> 
> 
> Translate Japanese setup guide to English.
> 
> Signed-off-by: Naoki Takada <takada.naoki@lab.ntt.co.jp>

I tried to apply your patches but failed because of an error in 8th 
patch as following. Could you fix it? Thanks.

Applying: doc: modify figure in spp_vf_overview
error: patch failed: docs/spp_vf/spp_vf_overview.svg:215
error: docs/spp_vf/spp_vf_overview.svg: patch does not apply
Patch failed at 0008 doc: modify figure in spp_vf_overview

Yasufumi

> ---
>   docs/spp_vf/setup.md | 288 +++++++++++++++++++++++++++++++++++++++++++++++++++
>   1 file changed, 288 insertions(+)
>   create mode 100644 docs/spp_vf/setup.md
> 
> diff --git a/docs/spp_vf/setup.md b/docs/spp_vf/setup.md
> new file mode 100644
> index 0000000..572777b
> --- /dev/null
> +++ b/docs/spp_vf/setup.md
> @@ -0,0 +1,288 @@
> +# Setup Guide
> +
> +## Environment
> +
> +* Ubuntu 16.04
> +* qemu-kvm
> +* DPDK v17.05
> +
> +## Setting
> +
> +### Host
> +
> +#### Edit Config
> +
> +Uncomment user and group in `/etc/libvirt/qemu.conf`.
> +
> +```sh
> +# /etc/libvirt/qemu.conf
> +
> +user = "root"
> +group = "root"
> +```
> +
> +Change `KVM_HUGEPAGES` from 0 to 1 in `/etc/default/qemu-kvm`.
> +
> +```sh
> +# /etc/default/qemu-kvm
> +
> +KVM_HUGEPAGES=1
> +```
> +
> +Change grub config for hugepages and isolcpus.
> +
> +```sh
> +# /etc/default/grub
> +
> +GRUB_CMDLINE_LINUX_DEFAULT="isolcpus=2,4,6,8,10,12-18,20,22,24,26-42,44,46 hugepagesz=1G hugepages=36 default_hugepagesz=1G"
> +```
> +
> +You need to run `update-grub` and reboot to activate grub config.
> +
> +```sh
> +$ sudo upadte-grub
> +$ sudo reboot
> +```
> +
> +You can check hugepage settings as following.
> +
> +```sh
> +$ cat /proc/meminfo | grep -i huge
> +AnonHugePages:      2048 kB
> +HugePages_Total:      36		#	/etc/default/grub
> +HugePages_Free:       36
> +HugePages_Rsvd:        0
> +HugePages_Surp:        0
> +Hugepagesize:    1048576 kB		#	/etc/default/grub
> +
> +$ mount | grep -i huge
> +cgroup on /sys/fs/cgroup/hugetlb type cgroup (rw,nosuid,nodev,noexec,relatime,hugetlb,release_agent=/run/cgmanager/agents/cgm-release-agent.hugetlb,nsroot=/)
> +hugetlbfs on /dev/hugepages type hugetlbfs (rw,relatime)
> +hugetlbfs-kvm on /run/hugepages/kvm type hugetlbfs (rw,relatime,mode=775,gid=117)
> +hugetlb on /run/lxcfs/controllers/hugetlb type cgroup (rw,relatime,hugetlb,release_agent=/run/cgmanager/agents/cgm-release-agent.hugetlb,nsroot=/)
> +```
> +
> +Finally, you unmount default hugepage.
> +
> +```sh
> +$ sudo unmount /dev/hugepages
> +```
> +
> +#### Install jasson
> +
> +Network configuration is defined in JSON and `spp_vf` reads config from
> +the file while launching.
> +[jasson](http://www.digip.org/jansson/) is a JSON library written in C.
> +
> +It is required to use `json_path` feature of `jasson` for `spp_vf`.
> +It has develped under `json_path` branch and you need to checkout and compile
> +it manually.
> +
> +```sh
> +$ git clone https://github.com/rogerz/jansson
> +$ cd jansson
> +$ sudo git checkout json_path
> +Branch json_path set up to track remote branch json_path from origin. Switched to a new branch 'json_path'
> +```
> +
> +This setup guide expects that `jasson` is placed as `/opt/jasson`.
> +
> +```sh
> +$ sudo mkdir -p /opt/jansson
> +$ sudo mv jansson /opt/jansson
> +```
> +
> +Compile it as following.
> +
> +```sh
> +$ cd /opt/jansson/jansson
> +$ sudo autoreconf -i
> +$ sudo ./configure
> +$ sudo make
> +$ sudo make install
> +$ sudo ldconfig
> +```
> +
> +Then, confirm that header files of jasson are generated in `/usr/local/include`.
> +
> +```sh
> +$ ls -al /usr/local/include
> +total 24
> +drwxr-xr-x  2 root root 4096 Jul 28 16:45 .
> +drwxr-xr-x 10 root root 4096 May 27 10:23 ..
> +-rw-r--r--  1 root root 1183 Jul 28 16:45 jansson_config.h
> +-rw-r--r--  1 root root 9499 Jul 28 16:45 jansson.h
> +```
> +
> +#### Install DPDK
> +
> +Install DPDK v17.05 in any directory. This is a simple instruction and please refer
> +[Getting Started Guide for Linux](http://dpdk.org/doc/guides/linux_gsg/index.html)
> +for details.
> +
> +```sh
> +$ cd /path/to/any_dir
> +$ git clone http://dpdk.org/git/dpdk
> +$ cd dpdk
> +$ git checkout v17.05
> +$ export RTE_SDK=`pwd`
> +$ export RTE_TARGET=x86_64-native-linuxapp-gcc
> +$ make T=x86_64-native-linuxapp-gcc install
> +```
> +
> +#### Install SPP
> +
> +Clone SPP in any directory and compile it.
> +
> +```sh
> +$ cd /path/to/spp_home/
> +$ git clone https://github.com/ntt-ns/Soft-Patch-Panel.git
> +export SPP_HOME=/path/to/spp_home/Soft-Patch-Panel
> +$ cd $SPP_HOME
> +$ make
> +```
> +
> +#### Setup for DPDK
> +
> +Load igb_uio module.
> +
> +```sh
> +$ sudo modprobe uio
> +$ sudo insmod $RTE_SDK/x86_64-native-linuxapp-gcc/kmod/igb_uio.ko
> +$ lsmod | grep uio
> +igb_uio                16384  0  # igb_uio is loaded
> +uio                    20480  1 igb_uio
> +```
> +
> +Then, bind it with PCI_Number.
> +```sh
> +$ $RTE_SDK/usertools/dpdk-devbind.py --status
> +# check your device for PCI_Number
> +
> +$ sudo $RTE_SDK/usertools/dpdk-devbind.py --bind=igb_uio [PCI_Number]
> +```
> +
> +#### virsh setup
> +
> +Edit VM configuration with virsh.
> +
> +```sh
> +$ virsh edit [VM_NAME]
> +<domain type='kvm' xmlns:qemu='http://libvirt.org/schemas/domain/qemu/1.0'>
> +	  <name>spp-vm1</name>
> +	  <uuid>d90f5420-861a-4479-8559-62d7a1545cb9</uuid>
> +	  <memory unit='KiB'>4194304</memory>
> +	  <currentMemory unit='KiB'>4194304</currentMemory>
> +	  <memoryBacking>
> +	    <hugepages/>
> +	  </memoryBacking>
> +	  <vcpu placement='static'>4</vcpu>
> +	  <os>
> +	    <type arch='x86_64' machine='pc-i440fx-2.3'>hvm</type>
> +	    <boot dev='hd'/>
> +	  </os>
> +	  <features>
> +	    <acpi/>
> +	    <apic/>
> +	    <pae/>
> +	  </features>
> +	  <clock offset='utc'/>
> +	  <on_poweroff>destroy</on_poweroff>
> +	  <on_reboot>restart</on_reboot>
> +	  <on_crash>restart</on_crash>
> +	  <devices>
> +	    <emulator>/usr/local/bin/qemu-system-x86_64</emulator>
> +	    <disk type='file' device='disk'>
> +	      <driver name='qemu' type='raw'/>
> +	      <source file='/var/lib/libvirt/images/spp-vm1.qcow2'/>
> +	      <target dev='hda' bus='ide'/>
> +	      <address type='drive' controller='0' bus='0' target='0' unit='0'/>
> +	    </disk>
> +	    <disk type='block' device='cdrom'>
> +	      <driver name='qemu' type='raw'/>
> +	      <target dev='hdc' bus='ide'/>
> +	      <readonly/>
> +	      <address type='drive' controller='0' bus='1' target='0' unit='0'/>
> +	    </disk>
> +	    <controller type='usb' index='0'>
> +	      <address type='pci' domain='0x0000' bus='0x00' slot='0x01' function='0x2'/>
> +	    </controller>
> +	    <controller type='pci' index='0' model='pci-root'/>
> +	    <controller type='ide' index='0'>
> +	      <address type='pci' domain='0x0000' bus='0x00' slot='0x01' function='0x1'/>
> +	    </controller>
> +	    <interface type='network'>
> +	      <mac address='52:54:00:99:aa:7f'/>
> +	      <source network='default'/>
> +	      <model type='rtl8139'/>
> +	      <address type='pci' domain='0x0000' bus='0x00' slot='0x02' function='0x0'/>
> +	    </interface>
> +	    <serial type='pty'>
> +	      <target type='isa-serial' port='0'/>
> +	    </serial>
> +	    <console type='pty'>
> +	      <target type='serial' port='0'/>
> +	    </console>
> +	    <memballoon model='virtio'>
> +	      <address type='pci' domain='0x0000' bus='0x00' slot='0x03' function='0x0'/>
> +	    </memballoon>
> +	  </devices>
> +	  <qemu:commandline>
> +	    <qemu:arg value='-cpu'/>
> +	    <qemu:arg value='host'/>
> +	    <qemu:arg value='-object'/>
> +	    <qemu:arg value='memory-backend-file,id=mem,size=4096M,mem-path=/run/hugepages/kvm,share=on'/>
> +	    <qemu:arg value='-numa'/>
> +	    <qemu:arg value='node,memdev=mem'/>
> +	    <qemu:arg value='-mem-prealloc'/>
> +	    <qemu:arg value='-chardev'/>
> +	    <qemu:arg value='socket,id=chr0,path=/tmp/sock0'/>
> +	    <qemu:arg value='-device'/>
> +	    <qemu:arg value='virtio-net-pci,netdev=vhost-net0'/>
> +	    <qemu:arg value='-netdev'/>
> +	    <qemu:arg value='vhost-user,id=vhost-net0,chardev=chr0,vhostforce'/>
> +	    <qemu:arg value='-chardev'/>
> +	    <qemu:arg value='socket,id=chr1,path=/tmp/sock1'/>
> +	    <qemu:arg value='-device'/>
> +	    <qemu:arg value='virtio-net-pci,netdev=vhost-net1'/>
> +	    <qemu:arg value='-netdev'/>
> +	    <qemu:arg value='vhost-user,id=vhost-net1,chardev=chr1,vhostforce'/>
> +	  </qemu:commandline>
> +	</domain>
> +```
> +
> +### Trouble Shooting
> +
> +You might encounter a permission error for `tmp/sockN` because of appamor.
> +In this case, you should try it.
> +
> +```sh
> +$ sudo ln -s /etc/apparmor.d/usr.lib.libvirt.virt-aa-helper /etc/apparmor.d/disable/usr.lib.libvirt.virt-aa-helper
> +$ sudo ln -s /etc/apparmor.d/usr.sbin.libvirtd /etc/apparmor.d/disable/usr.sbin.libvirtd
> +$ sudo apparmor_parser -R /etc/apparmor.d/usr.lib.libvirt.virt-aa-helper
> +$ sudo apparmor_parser -R /etc/apparmor.d/usr.sbin.libvirtd
> +$ sudo service apparmor reload
> +$ sudo service apparmor restart
> +$ sudo service libvirt-bin restart
> +```
> +
> +Or, you remove appamor.
> +
> +```sh
> +$ sudo apt-get remove apparmor
> +```
> +
> +If you use CentOS, not Ubuntu, confirm that SELinux doesn't prevent for permission.
> +SELinux should be disabled in this case.
> +
> +```sh
> +# /etc/selinux/config
> +SELINUX=disabled
> +```
> +
> +Check your SELinux configuration.
> +
> +```sh
> +$ getenforce
> +Disabled
> +```
> 


-- 
Yasufumi Ogawa
NTT Network Service Systems Labs

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

* Re: [spp] [PATCH 01/30] doc: add setup guide
  2018-01-19  0:52     ` Yasufumi Ogawa
@ 2018-01-22 14:37       ` Ferruh Yigit
  2018-01-23  0:25         ` Yasufumi Ogawa
  0 siblings, 1 reply; 97+ messages in thread
From: Ferruh Yigit @ 2018-01-22 14:37 UTC (permalink / raw)
  To: Yasufumi Ogawa, x-fn-spp, spp

On 1/19/2018 12:52 AM, Yasufumi Ogawa wrote:
> On 2018/01/16 14:16, x-fn-spp@sl.ntt-tx.co.jp wrote:
>> From: Hiroyuki Nakamura <nakamura.hioryuki@po.ntt-tx.co.jp>
>>
>> Hi all,
>>
>>> Series applied, thanks.
>> Ferruh, thank you for accepting our patches.
>>
>> We will post the document patches for spp_vf on DPDK17.08 in the
>> following emails.
>>
>>
>> Translate Japanese setup guide to English.
>>
>> Signed-off-by: Naoki Takada <takada.naoki@lab.ntt.co.jp>

Thank you for patches! Great to see document is improving.

> I tried to apply your patches but failed because of an error in 8th 
> patch as following. Could you fix it? Thanks.

+1 same here.

> 
> Applying: doc: modify figure in spp_vf_overview
> error: patch failed: docs/spp_vf/spp_vf_overview.svg:215
> error: docs/spp_vf/spp_vf_overview.svg: patch does not apply
> Patch failed at 0008 doc: modify figure in spp_vf_overview
> 
> Yasufumi
> 

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

* Re: [spp] [PATCH 01/30] doc: add setup guide
  2018-01-22 14:37       ` Ferruh Yigit
@ 2018-01-23  0:25         ` Yasufumi Ogawa
  0 siblings, 0 replies; 97+ messages in thread
From: Yasufumi Ogawa @ 2018-01-23  0:25 UTC (permalink / raw)
  To: Ferruh Yigit, x-fn-spp, spp

Hi Ferruh, Hiroyuki

It is another fatal error in 29th patch other than 8th. The reason of 
Both of errors seems a too long line in svg files. It is possibly 
happened if complex shaped object is included. In this case, cloud 
object for depicting network causes this problem.

Hiroyuki, I fixed the problem by replacing cloud object with ellipse and 
created modified patches. It is also fixed several warnings of format in 
examples of source code.

Ferruh, could you merge my patches instead of Hiroyuki's. Although the 
total number of patches are different, it works as smae as Hiroyuki's 
patches.

Thanks,
Yasufumi

On 2018/01/22 23:37, Ferruh Yigit wrote:
> On 1/19/2018 12:52 AM, Yasufumi Ogawa wrote:
>> On 2018/01/16 14:16, x-fn-spp@sl.ntt-tx.co.jp wrote:
>>> From: Hiroyuki Nakamura <nakamura.hioryuki@po.ntt-tx.co.jp>
>>>
>>> Hi all,
>>>
>>>> Series applied, thanks.
>>> Ferruh, thank you for accepting our patches.
>>>
>>> We will post the document patches for spp_vf on DPDK17.08 in the
>>> following emails.
>>>
>>>
>>> Translate Japanese setup guide to English.
>>>
>>> Signed-off-by: Naoki Takada <takada.naoki@lab.ntt.co.jp>
> 
> Thank you for patches! Great to see document is improving.
> 
>> I tried to apply your patches but failed because of an error in 8th
>> patch as following. Could you fix it? Thanks.
> 
> +1 same here.
> 
>>
>> Applying: doc: modify figure in spp_vf_overview
>> error: patch failed: docs/spp_vf/spp_vf_overview.svg:215
>> error: docs/spp_vf/spp_vf_overview.svg: patch does not apply
>> Patch failed at 0008 doc: modify figure in spp_vf_overview
>>
>> Yasufumi
>>
> 
> 


-- 
Yasufumi Ogawa
NTT Network Service Systems Labs

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

* Re: [spp] [PATCH 02/57] spp_vf: support multi process
  2017-12-28  4:55   ` [spp] [PATCH 02/57] spp_vf: support multi process x-fn-spp
@ 2018-02-07 16:50     ` Ferruh Yigit
  2018-02-08  1:21       ` Yasufumi Ogawa
  2018-02-08  6:44       ` [spp] [spp 02168] " Nakamura Hioryuki
  0 siblings, 2 replies; 97+ messages in thread
From: Ferruh Yigit @ 2018-02-07 16:50 UTC (permalink / raw)
  To: x-fn-spp, spp

On 12/28/2017 4:55 AM, x-fn-spp@sl.ntt-tx.co.jp wrote:
> From: Hiroyuki Nakamura <nakamura.hioryuki@po.ntt-tx.co.jp>
> 
> spp_vf was only a single process so far, but spp_vf supported
> multi process. Following modification has been made.
> 
> * Change naming machanism to allow hashtable on shared memory
>   to be operated by multiple processes.
> * Get config file path from command line argument.
> 
> And following modification has been made.
> * Modify comment.
> * Add and modify log message.
> * Add function to remove vhost socket file.
> 
> Signed-off-by: Daiki Yamashita <yamashita.daiki.z01@as.ntt-tx.co.jp>
> Signed-off-by: Yasufum Ogawa <ogawa.yasufumi@lab.ntt.co.jp>

<...>

> @@ -669,6 +732,24 @@ print_ring_latency_stats()
>  #endif /* SPP_RINGLATENCYSTATS_ENABLE */
>  
>  /*
> + * VHOST用ソケットファイル削除
> + */
> +static void
> +del_vhost_sockfile(struct patch_info *vhost_patchs)
> +{
> +	int cnt;
> +	for (cnt = 0; cnt < RTE_MAX_ETHPORTS; cnt++) {
> +		if (likely(vhost_patchs[cnt].use_flg == 0)) {
> +			/* VHOST未使用はスキップ */
> +			continue;
> +		}
> +
> +		/* 使用していたVHOSTについて削除を行う */

Would you mind translating comments to English. It helps if code understood by
more people.

<...>

>  		}
> +
> +		/* Skip dpdk parameters */
> +		argc -= ret_dpdk;
> +		argv += ret_dpdk;
> +
> +		/* Set log level  */
> +		rte_log_set_global_level(RTE_LOG_LEVEL);

Hi Daiki, Yasufum,

This breaks the build with dpdk master because RTE_LOG_LEVEL removed in this
release.

Can you please check this?

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

* Re: [spp] [PATCH 02/57] spp_vf: support multi process
  2018-02-07 16:50     ` Ferruh Yigit
@ 2018-02-08  1:21       ` Yasufumi Ogawa
  2018-02-08  6:44       ` [spp] [spp 02168] " Nakamura Hioryuki
  1 sibling, 0 replies; 97+ messages in thread
From: Yasufumi Ogawa @ 2018-02-08  1:21 UTC (permalink / raw)
  To: Ferruh Yigit, x-fn-spp, spp

On 2018/02/08 1:50, Ferruh Yigit wrote:
> On 12/28/2017 4:55 AM, x-fn-spp@sl.ntt-tx.co.jp wrote:
>> From: Hiroyuki Nakamura <nakamura.hioryuki@po.ntt-tx.co.jp>
>>
>> spp_vf was only a single process so far, but spp_vf supported
>> multi process. Following modification has been made.
>>
>> * Change naming machanism to allow hashtable on shared memory
>>    to be operated by multiple processes.
>> * Get config file path from command line argument.
>>
>> And following modification has been made.
>> * Modify comment.
>> * Add and modify log message.
>> * Add function to remove vhost socket file.
>>
>> Signed-off-by: Daiki Yamashita <yamashita.daiki.z01@as.ntt-tx.co.jp>
>> Signed-off-by: Yasufum Ogawa <ogawa.yasufumi@lab.ntt.co.jp>
> 
> <...>
> 
>> @@ -669,6 +732,24 @@ print_ring_latency_stats()
>>   #endif /* SPP_RINGLATENCYSTATS_ENABLE */
>>   
>>   /*
>> + * VHOST用ソケットファイル削除
>> + */
>> +static void
>> +del_vhost_sockfile(struct patch_info *vhost_patchs)
>> +{
>> +	int cnt;
>> +	for (cnt = 0; cnt < RTE_MAX_ETHPORTS; cnt++) {
>> +		if (likely(vhost_patchs[cnt].use_flg == 0)) {
>> +			/* VHOST未使用はスキップ */
>> +			continue;
>> +		}
>> +
>> +		/* 使用していたVHOSTについて削除を行う */
> 
> Would you mind translating comments to English. It helps if code understood by
> more people.
> 
> <...>
> 
>>   		}
>> +
>> +		/* Skip dpdk parameters */
>> +		argc -= ret_dpdk;
>> +		argv += ret_dpdk;
>> +
>> +		/* Set log level  */
>> +		rte_log_set_global_level(RTE_LOG_LEVEL);
> 
> Hi Daiki, Yasufum,
> 
> This breaks the build with dpdk master because RTE_LOG_LEVEL removed in this
> release.
> 
> Can you please check this?
Hi Ferruh,

We have talked how to fix this issue and are preparing a patch for. As 
you mention before, this is because difference of versions of DPDK, 1711 
and 1802. I think we should also update version of SPP, so I send 
another patch for updating.

To clear which of DPDK version for compiling SPP, I will check for it is 
safely compiled with latest DPDK and update the version immediately in 
future.

Thanks,
> 
> 


-- 
Yasufumi Ogawa
NTT Network Service Systems Labs

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

* Re: [spp] [spp 02168] Re: [PATCH 02/57] spp_vf: support multi process
  2018-02-07 16:50     ` Ferruh Yigit
  2018-02-08  1:21       ` Yasufumi Ogawa
@ 2018-02-08  6:44       ` Nakamura Hioryuki
  1 sibling, 0 replies; 97+ messages in thread
From: Nakamura Hioryuki @ 2018-02-08  6:44 UTC (permalink / raw)
  To: Ferruh Yigit; +Cc: spp

> On 12/28/2017 4:55 AM, x-fn-spp@sl.ntt-tx.co.jp wrote:
> > From: Hiroyuki Nakamura <nakamura.hioryuki@po.ntt-tx.co.jp>
> > 
> > spp_vf was only a single process so far, but spp_vf supported
> > multi process. Following modification has been made.
> > 
> > * Change naming machanism to allow hashtable on shared memory
> >   to be operated by multiple processes.
> > * Get config file path from command line argument.
> > 
> > And following modification has been made.
> > * Modify comment.
> > * Add and modify log message.
> > * Add function to remove vhost socket file.
> > 
> > Signed-off-by: Daiki Yamashita <yamashita.daiki.z01@as.ntt-tx.co.jp>
> > Signed-off-by: Yasufum Ogawa <ogawa.yasufumi@lab.ntt.co.jp>
> 
<snip>
> 
> Would you mind translating comments to English. It helps if code understood by
> more people.


All the comment of latest code on http://dpdk.org/git/apps/spp has
already been translated to English. 

> > +
> > +		/* Set log level  */
> > +		rte_log_set_global_level(RTE_LOG_LEVEL);
> 
> Hi Daiki, Yasufum,
> 
> This breaks the build with dpdk master because RTE_LOG_LEVEL removed in this
> release.
> 
> Can you please check this?

We've sent a patch,
[PATCH 9/9] spp_vf: change log level setting

This will enable spp_vf to build on dpdk master.

Thanks,

-- 
Nakamura Hioryuki <nakamua.hiroyuki@po.ntt-tx.co.jp>
-- 
Nakamura Hioryuki <nakamua.hiroyuki@po.ntt-tx.co.jp>
NTTテクノクロス フューチャーネットワーク事業部 第一事業ユニット
〒167-0043 杉並区上荻1-2-1 インテグラルタワー 14階
TEL:03-5347-8024 FAX:03-3392-2907

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

end of thread, other threads:[~2018-02-08  6:45 UTC | newest]

Thread overview: 97+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2017-12-25  4:41 [spp] Proposal - spp_vf(SR-IOV like feature) addition to SPP Nakamura Hioryuki
2017-12-26  1:54 ` Yasufumi Ogawa
2017-12-28  4:55   ` [spp] [PATCH 01/57] spp_vf: add vf functions x-fn-spp
2017-12-28  8:49     ` Yasufumi Ogawa
2017-12-28  4:55   ` [spp] [PATCH 02/57] spp_vf: support multi process x-fn-spp
2018-02-07 16:50     ` Ferruh Yigit
2018-02-08  1:21       ` Yasufumi Ogawa
2018-02-08  6:44       ` [spp] [spp 02168] " Nakamura Hioryuki
2017-12-28  4:55   ` [spp] [PATCH 03/57] spp_vf: comment out check of using cores x-fn-spp
2017-12-28  4:55   ` [spp] [PATCH 04/57] spp_vf: modify classifier for upd command x-fn-spp
2017-12-28  4:55   ` [spp] [PATCH 05/57] spp_vf: add procedure that mac address is null x-fn-spp
2017-12-28  4:55   ` [spp] [PATCH 06/57] spp_vf: change config format for upd command x-fn-spp
2017-12-28  4:55   ` [spp] [PATCH 07/57] spp_vf: fix compiler warning in classifier_mac.c x-fn-spp
2017-12-28  4:55   ` [spp] [PATCH 08/57] spp_vf: modify data struct for upd command x-fn-spp
2017-12-28  4:55   ` [spp] [PATCH 09/57] spp_vf: add functions of command acceptance x-fn-spp
2017-12-28  4:55   ` [spp] [PATCH 10/57] spp_vf: add command acceptance calling x-fn-spp
2017-12-28  4:55   ` [spp] [PATCH 11/57] spp_vf: fix compiler warning in command_proc.c x-fn-spp
2017-12-28  4:55   ` [spp] [PATCH 12/57] " x-fn-spp
2017-12-28  4:55   ` [spp] [PATCH 13/57] spp_vf: refactor command acceptance/decode x-fn-spp
2017-12-28  4:55   ` [spp] [PATCH 14/57] spp_vf: fix return value overwrite problem x-fn-spp
2017-12-28  4:55   ` [spp] [PATCH 15/57] spp_vf: initialize message buffer x-fn-spp
2017-12-28  4:55   ` [spp] [PATCH 16/57] spp_vf: add const keyword to parameter x-fn-spp
2017-12-28  4:55   ` [spp] [PATCH 17/57] spp_vf: fix wrong comparison operator x-fn-spp
2017-12-28  4:55   ` [spp] [PATCH 18/57] spp_vf: fix wrong variable to be assigned x-fn-spp
2017-12-28  4:55   ` [spp] [PATCH 19/57] spp_vf: refactor parsing server ip address x-fn-spp
2017-12-28  4:55   ` [spp] [PATCH 20/57] spp_vf: fix error in command decode x-fn-spp
2017-12-28  4:55   ` [spp] [PATCH 21/57] spp_vf: fix comparison operator in spp_vf.c x-fn-spp
2017-12-28  4:55   ` [spp] [PATCH 22/57] spp_vf: check upper limit to the number of process x-fn-spp
2017-12-28  4:55   ` [spp] [PATCH 23/57] spp_vf: display usage message x-fn-spp
2017-12-28  4:55   ` [spp] [PATCH 24/57] spp_vf: split command processing source file x-fn-spp
2017-12-28  4:55   ` [spp] [PATCH 25/57] spp_vf: add new log and line break x-fn-spp
2017-12-28  4:55   ` [spp] [PATCH 26/57] spp_vf: support get-process-id command x-fn-spp
2017-12-28  4:55   ` [spp] [PATCH 27/57] spp_vf: update socket creation procedure x-fn-spp
2017-12-28  4:55   ` [spp] [PATCH 28/57] spp_vf: change log level and add line break x-fn-spp
2017-12-28  4:55   ` [spp] [PATCH 29/57] spp_vf: replace unsupported jansson api x-fn-spp
2017-12-28  4:55   ` [spp] [PATCH 30/57] spp_vf: change order of command result in json object x-fn-spp
2017-12-28  4:55   ` [spp] [PATCH 31/57] spp_vf: use prediction keywords x-fn-spp
2017-12-28  4:55   ` [spp] [PATCH 32/57] spp_vf: fix wrong comparison x-fn-spp
2017-12-28  4:55   ` [spp] [PATCH 33/57] spp_vf: update sending error status x-fn-spp
2017-12-28  4:55   ` [spp] [PATCH 34/57] spp_vf: modify conditional statement x-fn-spp
2017-12-28  4:55   ` [spp] [PATCH 35/57] spp_vf: add proc on receiving l2 multicast x-fn-spp
2017-12-28  4:55   ` [spp] [PATCH 36/57] spp_vf: extend limit on number of usable cores x-fn-spp
2017-12-28  4:55   ` [spp] [PATCH 37/57] spp_vf: add restart procedure for vhost client x-fn-spp
2017-12-28  4:55   ` [spp] [PATCH 38/57] spp_vf: fix classifier mbuf handling x-fn-spp
2017-12-28  4:55   ` [spp] [PATCH 39/57] spp_vf: add status command x-fn-spp
2017-12-28  4:55   ` [spp] [PATCH 40/57] spp_vf: add output source information in error log x-fn-spp
2017-12-28  4:55   ` [spp] [PATCH 41/57] spp_vf: change function names x-fn-spp
2017-12-28  4:55   ` [spp] [PATCH 42/57] spp_vf: change how to request commands x-fn-spp
2017-12-28  4:55   ` [spp] [PATCH 43/57] spp_vf: update command decode procedure x-fn-spp
2017-12-28  4:55   ` [spp] [PATCH 44/57] spp_vf: remove debug log output procedures x-fn-spp
2017-12-28  4:55   ` [spp] [PATCH 45/57] spp_vf: improve command_decoder program code x-fn-spp
2017-12-28  4:55   ` [spp] [PATCH 46/57] spp_vf: fix a bug in status command x-fn-spp
2017-12-28  4:55   ` [spp] [PATCH 47/57] spp_vf: add spp_vf.py instead of spp.py x-fn-spp
2017-12-28  4:55   ` [spp] [PATCH 48/57] spp_vf: refactor for commnets in spp_vf.c x-fn-spp
2017-12-28  4:55   ` [spp] [PATCH 49/57] spp_vf: refactor comments in classifier_mac.c x-fn-spp
2017-12-28  4:55   ` [spp] [PATCH 50/57] spp_vf: refactor comments in spp_forward.c x-fn-spp
2017-12-28  4:55   ` [spp] [PATCH 51/57] spp_vf: refactor for commnets in spp_config.c x-fn-spp
2017-12-28  4:55   ` [spp] [PATCH 52/57] spp_vf: refactor no self-explanatory comments x-fn-spp
2017-12-28  4:56   ` [spp] [PATCH 53/57] spp_vf: correct typo of function name x-fn-spp
2017-12-28  4:56   ` [spp] [PATCH 54/57] spp_vf: support new command x-fn-spp
2017-12-28  4:56   ` [spp] [PATCH 55/57] spp_vf: add display of status command x-fn-spp
2017-12-28  4:56   ` [spp] [PATCH 56/57] spp_vf: fix " x-fn-spp
2017-12-28  4:56   ` [spp] [PATCH 57/57] spp_vf: fix l2 multicast packet forwarding x-fn-spp
2018-01-15 11:04 ` [spp] Proposal - spp_vf(SR-IOV like feature) addition to SPP Ferruh Yigit
2018-01-16  5:16   ` [spp] [PATCH 01/30] doc: add setup guide x-fn-spp
2018-01-19  0:52     ` Yasufumi Ogawa
2018-01-22 14:37       ` Ferruh Yigit
2018-01-23  0:25         ` Yasufumi Ogawa
2018-01-16  5:16   ` [spp] [PATCH 02/30] doc: add how_to_use.md x-fn-spp
2018-01-16  5:16   ` [spp] [PATCH 03/30] doc: add config_manual.md x-fn-spp
2018-01-16  5:16   ` [spp] [PATCH 04/30] doc: add spp_vf.md x-fn-spp
2018-01-16  5:16   ` [spp] [PATCH 05/30] doc: revise spp_vf.md x-fn-spp
2018-01-16  5:16   ` [spp] [PATCH 06/30] doc: add config section x-fn-spp
2018-01-16  5:16   ` [spp] [PATCH 07/30] doc: update jp setup manual x-fn-spp
2018-01-16  5:16   ` [spp] [PATCH 08/30] doc: modify figure in spp_vf_overview x-fn-spp
2018-01-16  5:16   ` [spp] [PATCH 09/30] doc: fix " x-fn-spp
2018-01-16  5:16   ` [spp] [PATCH 10/30] doc: fix figure in overview x-fn-spp
2018-01-16  5:16   ` [spp] [PATCH 11/30] doc: add sample usage x-fn-spp
2018-01-16  5:16   ` [spp] [PATCH 12/30] doc: revice path descs x-fn-spp
2018-01-16  5:16   ` [spp] [PATCH 13/30] doc: add network configuration diagram x-fn-spp
2018-01-16  5:16   ` [spp] [PATCH 14/30] doc: update user account x-fn-spp
2018-01-16  5:16   ` [spp] [PATCH 15/30] doc: update descriptions for todo x-fn-spp
2018-01-16  5:16   ` [spp] [PATCH 16/30] doc: add description for explanation section x-fn-spp
2018-01-16  5:16   ` [spp] [PATCH 17/30] doc: add spp_sample_usage_svg in docs/spp_vf/ x-fn-spp
2018-01-16  5:16   ` [spp] [PATCH 18/30] doc: add explanation for terminating spp app x-fn-spp
2018-01-16  5:16   ` [spp] [PATCH 19/30] doc: add explanations on options of spp x-fn-spp
2018-01-16  5:16   ` [spp] [PATCH 20/30] doc: update description for the latest spp version x-fn-spp
2018-01-16  5:16   ` [spp] [PATCH 21/30] doc: update description on dpdk version x-fn-spp
2018-01-16  5:16   ` [spp] [PATCH 22/30] doc: fix vm setup procedure for network config x-fn-spp
2018-01-16  5:16   ` [spp] [PATCH 23/30] doc: update jansson installation procedure x-fn-spp
2018-01-16  5:16   ` [spp] [PATCH 24/30] doc: fix required network configuration x-fn-spp
2018-01-16  5:16   ` [spp] [PATCH 25/30] doc: add how to use vhost-user support x-fn-spp
2018-01-16  5:16   ` [spp] [PATCH 26/30] doc: add references to hugepages and isolcpus x-fn-spp
2018-01-16  5:16   ` [spp] [PATCH 27/30] doc: remove description on classifier_table x-fn-spp
2018-01-16  5:16   ` [spp] [PATCH 28/30] doc: fix typos and erros in texts x-fn-spp
2018-01-16  5:16   ` [spp] [PATCH 29/30] doc: update sample config section x-fn-spp
2018-01-16  5:16   ` [spp] [PATCH 30/30] doc: align figure title position x-fn-spp

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