[spp] [PATCH 54/57] spp_vf: support new command

x-fn-spp at sl.ntt-tx.co.jp x-fn-spp at sl.ntt-tx.co.jp
Thu Dec 28 05:56:01 CET 2017


From: Hiroyuki Nakamura <nakamura.hioryuki at 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 at as.ntt-tx.co.jp>
Signed-off-by: Yasufum Ogawa <ogawa.yasufumi at 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



More information about the spp mailing list