[spp] [PATCH v2 7/9] spp_vf: add VID classification to the classifier

ogawa.yasufumi at lab.ntt.co.jp ogawa.yasufumi at lab.ntt.co.jp
Tue Feb 27 13:34:27 CET 2018


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

Classifier has a table for virtual MAC address for resolving the
destination MAC address and port incoming packets are sent to.

This patch for adding another type of table to support vlan-tag
(TPID:0x8100). If TPID of an incoming packet equals to 0x8100,
classifier looks up the new table.

Signed-off-by: Daiki Yamashita <yamashita.daiki.z01 at as.ntt-tx.co.jp>
Signed-off-by: Naoki Takada <takada.naoki at lab.ntt.co.jp>
---
 src/vf/classifier_mac.c | 656 +++++++++++++++++++++++++++++++++++-------------
 src/vf/command_dec.c    |  87 +++++--
 src/vf/command_dec.h    |  41 ++-
 src/vf/command_proc.c   |  41 ++-
 src/vf/spp_vf.c         | 150 ++++++-----
 src/vf/spp_vf.h         |  41 +--
 6 files changed, 728 insertions(+), 288 deletions(-)

diff --git a/src/vf/classifier_mac.c b/src/vf/classifier_mac.c
index 1719889..d07870d 100644
--- a/src/vf/classifier_mac.c
+++ b/src/vf/classifier_mac.c
@@ -78,6 +78,9 @@
 /* interval that transmit burst packet, if buffer is not filled (nano second) */
 #define DRAIN_TX_PACKET_INTERVAL 100
 
+/* VID of VLAN untagged */
+#define VLAN_UNTAGGED_VID 0x0fff
+
 /*
  * hash table name buffer size
  *[reson for value]
@@ -116,13 +119,10 @@ struct classified_data {
 	struct rte_mbuf *pkts[MAX_PKT_BURST];
 };
 
-/* classifier component information */
-struct component_info {
-	/* component name */
-	char name[SPP_NAME_STR_LEN];
-
-	/* hash table keeps classifier_table */
-	struct rte_hash *classifier_table;
+/* mac address classification */
+struct mac_classification {
+	/* hash table keeps classification */
+	struct rte_hash *classification_tab;
 
 	/* number of valid classification */
 	int num_active_classified;
@@ -132,6 +132,15 @@ struct component_info {
 
 	/* index of default classification */
 	int default_classified;
+};
+
+/* classifier component information */
+struct component_info {
+	/* component name */
+	char name[SPP_NAME_STR_LEN];
+
+	/* mac address classification per vlan-id */
+	struct mac_classification *mac_classifications[SPP_NUM_VLAN_VID];
 
 	/* number of transmission ports */
 	int n_classified_data_tx;
@@ -153,6 +162,9 @@ struct management_info {
 
 	/* Update index number for classifier information */
 	volatile int upd_index;
+
+	/* used flag */
+	volatile int is_used;
 };
 
 /* classifier information per lcore */
@@ -166,11 +178,200 @@ static struct management_info g_mng_infos[RTE_MAX_LCORE];
  */
 static rte_atomic16_t g_hash_table_count = RTE_ATOMIC16_INIT(0xff);
 
+/* get vid from packet */
+static inline uint16_t
+get_vid(const struct rte_mbuf *pkt)
+{
+	struct ether_hdr *eth;
+	struct vlan_hdr *vh;
+
+	eth = rte_pktmbuf_mtod(pkt, struct ether_hdr *);
+	if (eth->ether_type == rte_cpu_to_be_16(ETHER_TYPE_VLAN)) {
+		/* vlan tagged */
+		vh = (struct vlan_hdr *)(eth + 1);
+		return rte_be_to_cpu_16(vh->vlan_tci) & 0x0fff;
+	}
+
+	/* vlan untagged */
+	return VLAN_UNTAGGED_VID;
+}
+
+#if RTE_LOG_DP_LEVEL >= RTE_LOG_DEBUG
+
+#define LOG_DBG(name, fmt, ...)                                        \
+		RTE_LOG_DP(DEBUG, SPP_CLASSIFIER_MAC,                  \
+				"[%s]Log(%s:%d):"fmt,                  \
+				name, __func__, __LINE__, __VA_ARGS__)
+
+static void
+log_packet(const char *name, struct rte_mbuf *pkt,
+		const char *func_name, int line_num)
+{
+	struct ether_hdr *eth;
+	uint16_t vid;
+	char mac_addr_str[2][ETHER_ADDR_STR_BUF_SZ];
+
+	eth = rte_pktmbuf_mtod(pkt, struct ether_hdr *);
+	vid = get_vid(pkt);
+
+	ether_format_addr(mac_addr_str[0], sizeof(mac_addr_str),
+			&eth->d_addr);
+	ether_format_addr(mac_addr_str[1], sizeof(mac_addr_str),
+			&eth->s_addr);
+
+	RTE_LOG_DP(DEBUG, SPP_CLASSIFIER_MAC,
+			"[%s]Packet(%s:%d). d_addr=%s, s_addr=%s, vid=%hu, pktlen=%u\n",
+			name,
+			func_name,
+			line_num,
+			mac_addr_str[0],
+			mac_addr_str[1],
+			vid,
+			rte_pktmbuf_pkt_len(pkt));
+}
+
+#define LOG_PKT(name, pkt) \
+		log_packet(name, pkt, __func__, __LINE__)
+
+static void
+log_classification(
+		long clsd_idx,
+		struct rte_mbuf *pkt,
+		struct component_info *cmp_info,
+		struct classified_data *clsd_data,
+		const char *func_name,
+		int line_num)
+{
+	struct ether_hdr *eth;
+	uint16_t vid;
+	char mac_addr_str[2][ETHER_ADDR_STR_BUF_SZ];
+	char iface_str[SPP_NAME_STR_LEN];
+
+	eth = rte_pktmbuf_mtod(pkt, struct ether_hdr *);
+	vid = get_vid(pkt);
+
+	ether_format_addr(mac_addr_str[0], sizeof(mac_addr_str),
+			&eth->d_addr);
+	ether_format_addr(mac_addr_str[1], sizeof(mac_addr_str),
+			&eth->s_addr);
+
+	if (clsd_idx < 0)
+		snprintf(iface_str, sizeof(iface_str), "%ld", clsd_idx);
+	else
+		spp_format_port_string(
+				iface_str,
+				clsd_data[clsd_idx].iface_type,
+				clsd_data[clsd_idx].iface_no_global);
+
+	RTE_LOG_DP(DEBUG, SPP_CLASSIFIER_MAC,
+			"[%s]Classification(%s:%d). d_addr=%s, s_addr=%s, vid=%hu, pktlen=%u, tx_iface=%s\n",
+			cmp_info->name,
+			func_name,
+			line_num,
+			mac_addr_str[0],
+			mac_addr_str[1],
+			vid,
+			rte_pktmbuf_pkt_len(pkt),
+			iface_str);
+}
+
+#define LOG_CLS(clsd_idx, pkt, cmp_info, clsd_data)                    \
+		log_classification(clsd_idx, pkt, cmp_info, clsd_data, \
+				__func__, __LINE__)
+
+static void
+log_entry(
+		long clsd_idx,
+		uint16_t vid,
+		const char *mac_addr_str,
+		struct component_info *cmp_info,
+		struct classified_data *clsd_data,
+		const char *func_name,
+		int line_num)
+{
+	char iface_str[SPP_NAME_STR_LEN];
+
+	if (clsd_idx < 0)
+		snprintf(iface_str, sizeof(iface_str), "%ld", clsd_idx);
+	else
+		spp_format_port_string(
+				iface_str,
+				clsd_data[clsd_idx].iface_type,
+				clsd_data[clsd_idx].iface_no_global);
+
+	RTE_LOG_DP(DEBUG, SPP_CLASSIFIER_MAC,
+			"[%s]Entry(%s:%d). vid=%hu, mac_addr=%s, iface=%s\n",
+			cmp_info->name,
+			func_name,
+			line_num,
+			vid,
+			mac_addr_str,
+			iface_str);
+}
+#define LOG_ENT(clsd_idx, vid, mac_addr_str, cmp_info, clsd_data)           \
+		log_entry(clsd_idx, vid, mac_addr_str, cmp_info, clsd_data, \
+				__func__, __LINE__)
+#else
+#define LOG_DBG(name, fmt, ...)
+#define LOG_PKT(name, pkt)
+#define LOG_CLS(pkt, clsd_idx, cmp_info, clsd_data)
+#define LOG_ENT(clsd_idx, vid, mac_addr_str, cmp_info, clsd_data)
+#endif
+
+/* check if management information is used. */
 static inline int
 is_used_mng_info(const struct management_info *mng_info)
 {
-	return (mng_info != NULL &&
-			mng_info->cmp_infos[0].classifier_table != NULL);
+	return (mng_info != NULL && mng_info->is_used);
+}
+
+/* create mac classification instance. */
+static struct mac_classification *
+create_mac_classification(void)
+{
+	struct mac_classification *mac_cls;
+	char hash_tab_name[HASH_TABLE_NAME_BUF_SZ];
+	struct rte_hash **mac_cls_tab;
+
+	mac_cls = (struct mac_classification *)rte_zmalloc(
+			NULL, sizeof(struct mac_classification), 0);
+
+	if (unlikely(mac_cls == NULL))
+		return NULL;
+
+	mac_cls->num_active_classified = 0;
+	mac_cls->default_classified = -1;
+
+	mac_cls_tab = &mac_cls->classification_tab;
+
+	/* make hash table name(require uniqueness between processes) */
+	sprintf(hash_tab_name, "cmtab_%07x%02hx",
+			getpid(),
+			rte_atomic16_add_return(&g_hash_table_count, 1));
+
+	RTE_LOG(INFO, SPP_CLASSIFIER_MAC, "Create table. name=%s, bufsz=%lu\n",
+			hash_tab_name, HASH_TABLE_NAME_BUF_SZ);
+
+	/* set hash creating parameters */
+	struct rte_hash_parameters hash_params = {
+			.name      = hash_tab_name,
+			.entries   = NUM_CLASSIFIER_MAC_TABLE_ENTRY,
+			.key_len   = sizeof(struct ether_addr),
+			.hash_func = DEFAULT_HASH_FUNC,
+			.hash_func_init_val = 0,
+			.socket_id = rte_socket_id(),
+	};
+
+	/* create classifier mac table (hash table) */
+	*mac_cls_tab = rte_hash_create(&hash_params);
+	if (unlikely(*mac_cls_tab == NULL)) {
+		RTE_LOG(ERR, SPP_CLASSIFIER_MAC, "Cannot create mac classification table. "
+				"name=%s\n", hash_tab_name);
+		rte_free(mac_cls);
+		return NULL;
+	}
+
+	return mac_cls;
 }
 
 /* initialize classifier information. */
@@ -180,19 +381,15 @@ init_component_info(struct component_info *cmp_info,
 {
 	int ret = -1;
 	int i;
-	struct rte_hash **classifier_table = &cmp_info->classifier_table;
+	struct mac_classification *mac_cls;
 	struct ether_addr eth_addr;
 	char mac_addr_str[ETHER_ADDR_STR_BUF_SZ];
-	struct classified_data *clsd_data_rx =
-			&cmp_info->classified_data_rx;
-	struct classified_data *clsd_data_tx =
-			cmp_info->classified_data_tx;
+	struct classified_data *clsd_data_rx = &cmp_info->classified_data_rx;
+	struct classified_data *clsd_data_tx = cmp_info->classified_data_tx;
 	struct spp_port_info *tx_port = NULL;
+	uint16_t vid;
 
-	rte_hash_reset(*classifier_table);
-	cmp_info->num_active_classified = 0;
-	cmp_info->default_classified = -1;
-	cmp_info->n_classified_data_tx = component_info->num_tx_port;
+	/* set rx */
 	if (component_info->num_rx_port == 0) {
 		clsd_data_rx->iface_type      = UNDEF;
 		clsd_data_rx->iface_no        = 0;
@@ -210,8 +407,11 @@ init_component_info(struct component_info *cmp_info,
 		clsd_data_rx->num_pkt         = 0;
 	}
 
+	/* set tx */
+	cmp_info->n_classified_data_tx = component_info->num_tx_port;
 	for (i = 0; i < component_info->num_tx_port; i++) {
 		tx_port = component_info->tx_ports[i];
+		vid = tx_port->class_id.vlantag.vid;
 
 		/* store ports information */
 		clsd_data_tx[i].iface_type      = tx_port->iface_type;
@@ -220,19 +420,33 @@ init_component_info(struct component_info *cmp_info,
 		clsd_data_tx[i].port            = tx_port->dpdk_port;
 		clsd_data_tx[i].num_pkt         = 0;
 
-		if (component_info->tx_ports[i]->mac_addr == 0)
+		if (tx_port->class_id.mac_addr == 0)
 			continue;
 
+		/* if mac classification is NULL, make instance */
+		if (unlikely(cmp_info->mac_classifications[vid] == NULL)) {
+			RTE_LOG(DEBUG, SPP_CLASSIFIER_MAC,
+					"Mac classification is not registered. create."
+					"vid=%hu\n", vid);
+			cmp_info->mac_classifications[vid] =
+					create_mac_classification();
+			if (unlikely(cmp_info->mac_classifications[vid] ==
+					NULL))
+				return -1;
+		}
+		mac_cls = cmp_info->mac_classifications[vid];
+
 		/* store active tx_port that associate with mac address */
-		cmp_info->active_classifieds[cmp_info->
-				num_active_classified++] = i;
+		mac_cls->active_classifieds[
+				mac_cls->num_active_classified++] = i;
 
 		/* store default classified */
-		if (unlikely(tx_port->mac_addr ==
+		if (unlikely(tx_port->class_id.mac_addr ==
 				SPP_DEFAULT_CLASSIFIED_DMY_ADDR)) {
-			cmp_info->default_classified = i;
+			mac_cls->default_classified = i;
 			RTE_LOG(INFO, SPP_CLASSIFIER_MAC, "default classified. "
-					"iface_type=%d, iface_no=%d, dpdk_port=%d\n",
+					"vid=%hu, iface_type=%d, iface_no=%d, dpdk_port=%d\n",
+					vid,
 					tx_port->iface_type,
 					tx_port->iface_no,
 					tx_port->dpdk_port);
@@ -240,24 +454,24 @@ init_component_info(struct component_info *cmp_info,
 		}
 
 		/* add entry to classifier mac table */
-		rte_memcpy(&eth_addr, &tx_port->mac_addr, ETHER_ADDR_LEN);
+		rte_memcpy(&eth_addr, &tx_port->class_id.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,
+		ret = rte_hash_add_key_data(mac_cls->classification_tab,
 				(void *)&eth_addr, (void *)(long)i);
 		if (unlikely(ret < 0)) {
 			RTE_LOG(ERR, SPP_CLASSIFIER_MAC,
 					"Cannot add entry to classifier mac table. "
-					"ret=%d, mac_addr=%s\n",
-					ret, mac_addr_str);
-			rte_hash_free(*classifier_table);
-			*classifier_table = NULL;
+					"ret=%d, vid=%hu, mac_addr=%s\n",
+					ret, vid, mac_addr_str);
 			return -1;
 		}
 
 		RTE_LOG(INFO, SPP_CLASSIFIER_MAC, "Add entry to classifier mac table. "
-				"mac_addr=%s, iface_type=%d, iface_no=%d, dpdk_port=%d\n",
+				"vid=%hu, mac_addr=%s, iface_type=%d, iface_no=%d, dpdk_port=%d\n",
+				vid,
 				mac_addr_str,
 				tx_port->iface_type,
 				tx_port->iface_no,
@@ -272,10 +486,6 @@ static int
 init_classifier(struct management_info *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(mng_info, 0, sizeof(struct management_info));
@@ -295,39 +505,6 @@ init_classifier(struct management_info *mng_info)
 	RTE_LOG(DEBUG, SPP_CLASSIFIER_MAC, "Disabled SSE4.2. use Jenkins hash.\n");
 #endif
 
-	for (i = 0; i < NUM_CLASSIFIER_MAC_INFO; ++i) {
-
-		classifier_mac_table =
-				&mng_info->cmp_infos[i].classifier_table;
-
-		/* make hash table name(require uniqueness between processes) */
-		sprintf(hash_table_name, "cmtab_%07x%02hx%x",
-				getpid(),
-				rte_atomic16_add_return(&g_hash_table_count, 1),
-				i);
-
-		RTE_LOG(INFO, SPP_CLASSIFIER_MAC, "Create table. name=%s, bufsz=%lu\n",
-				hash_table_name, HASH_TABLE_NAME_BUF_SZ);
-
-		/* set hash creating parameters */
-		struct rte_hash_parameters hash_params = {
-				.name      = hash_table_name,
-				.entries   = NUM_CLASSIFIER_MAC_TABLE_ENTRY,
-				.key_len   = sizeof(struct ether_addr),
-				.hash_func = DEFAULT_HASH_FUNC,
-				.hash_func_init_val = 0,
-				.socket_id = rte_socket_id(),
-		};
-
-		/* create classifier mac table (hash table) */
-		*classifier_mac_table = rte_hash_create(&hash_params);
-		if (unlikely(*classifier_mac_table == NULL)) {
-			RTE_LOG(ERR, SPP_CLASSIFIER_MAC, "Cannot create classifier mac table. "
-					"name=%s\n", hash_table_name);
-			return -1;
-		}
-	}
-
 	/* populate the classifier information at reference */
 	ret = init_component_info(&mng_info->
 			cmp_infos[mng_info->ref_index], &component_info);
@@ -340,25 +517,48 @@ init_classifier(struct management_info *mng_info)
 
 	/* updating side can be set by completion of initialization. */
 	mng_info->upd_index = mng_info->ref_index + 1;
+	mng_info->is_used = 1;
 
 	return 0;
 }
 
+/* free mac classification instance. */
+static inline void
+free_mac_classification(struct mac_classification *mac_cls)
+{
+	if (mac_cls == NULL)
+		return;
+
+	if (mac_cls->classification_tab != NULL)
+		rte_hash_free(mac_cls->classification_tab);
+
+	rte_free(mac_cls);
+}
+
+/* uninitialize classifier information. */
+static void
+uninit_component_info(struct component_info *cmp_info)
+{
+	int i;
+
+	for (i = 0; i < SPP_NUM_VLAN_VID; ++i)
+		free_mac_classification(cmp_info->mac_classifications[i]);
+
+	memset(cmp_info, 0, sizeof(struct component_info));
+}
+
 /* uninitialize classifier. */
 static void
 uninit_classifier(struct management_info *mng_info)
 {
 	int i;
 
-	for (i = 0; i < NUM_CLASSIFIER_MAC_INFO; ++i) {
-		if (mng_info->cmp_infos[i].classifier_table != NULL) {
-			rte_hash_free(mng_info->cmp_infos[i].
-					classifier_table);
-			mng_info->cmp_infos[i].classifier_table = NULL;
-			mng_info->ref_index = 0;
-			mng_info->upd_index = 0;
-		}
-	}
+	mng_info->is_used = 0;
+
+	for (i = 0; i < NUM_CLASSIFIER_MAC_INFO; ++i)
+		uninit_component_info(mng_info->cmp_infos + (long)i);
+
+	memset(mng_info, 0, sizeof(struct management_info));
 }
 
 /* transmit packet to one destination. */
@@ -415,7 +615,8 @@ push_packet(struct rte_mbuf *pkt, struct classified_data *clsd_data)
 	if (unlikely(clsd_data->num_pkt == MAX_PKT_BURST)) {
 		RTE_LOG(DEBUG, SPP_CLASSIFIER_MAC,
 				"transmit packets (buffer is filled). "
-				"iface_type=%d, iface_no={%d,%d}, tx_port=%hu, num_pkt=%hu\n",
+				"iface_type=%d, iface_no={%d,%d}, "
+				"tx_port=%hu, num_pkt=%hu\n",
 				clsd_data->iface_type,
 				clsd_data->iface_no_global,
 				clsd_data->iface_no,
@@ -425,6 +626,22 @@ push_packet(struct rte_mbuf *pkt, struct classified_data *clsd_data)
 	}
 }
 
+/* get index of general default classified */
+static inline int
+get_general_default_classified_index(struct component_info *cmp_info)
+{
+	struct mac_classification *mac_cls;
+
+	mac_cls = cmp_info->mac_classifications[VLAN_UNTAGGED_VID];
+	if (unlikely(mac_cls == NULL)) {
+		LOG_DBG(cmp_info->name, "Untagged's default is not set. vid=%d\n",
+				(int)VLAN_UNTAGGED_VID);
+		return -1;
+	}
+
+	return mac_cls->default_classified;
+}
+
 /* handle L2 multicast(include broadcast) packet */
 static inline void
 handle_l2multicast_packet(struct rte_mbuf *pkt,
@@ -432,20 +649,103 @@ handle_l2multicast_packet(struct rte_mbuf *pkt,
 		struct classified_data *clsd_data)
 {
 	int i;
+	struct mac_classification *mac_cls;
+	uint16_t vid = get_vid(pkt);
+	int gen_def_clsd_idx = get_general_default_classified_index(cmp_info);
+	int n_act_clsd;
+
+	/* select mac address classification by vid */
+	mac_cls = cmp_info->mac_classifications[vid];
+	if (unlikely(mac_cls == NULL ||
+			mac_cls->num_active_classified == 0)) {
+		/* specific vlan is not registered
+		 * use untagged's default(as general default)
+		 */
+		if (unlikely(gen_def_clsd_idx < 0)) {
+			/* untagged's default is not registered too */
+			RTE_LOG(ERR, SPP_CLASSIFIER_MAC,
+					"No entry.(l2 multicast packet)\n");
+			rte_pktmbuf_free(pkt);
+			return;
+		}
 
-	if (unlikely(cmp_info->num_active_classified == 0)) {
-		RTE_LOG(ERR, SPP_CLASSIFIER_MAC, "No mac address.(l2 multicast packet)\n");
-		rte_pktmbuf_free(pkt);
+		/* transmit to untagged's default(as general default) */
+		LOG_CLS((long)gen_def_clsd_idx, pkt, cmp_info, clsd_data);
+		push_packet(pkt, clsd_data + (long)gen_def_clsd_idx);
 		return;
 	}
 
-	rte_mbuf_refcnt_update(pkt,
-			(cmp_info->num_active_classified - 1));
+	/* add to mbuf's refcnt */
+	n_act_clsd = mac_cls->num_active_classified;
+	if (gen_def_clsd_idx >= 0 && vid != VLAN_UNTAGGED_VID)
+		++n_act_clsd;
 
-	for (i = 0; i < cmp_info->num_active_classified; i++) {
+	rte_mbuf_refcnt_update(pkt, (int16_t)(n_act_clsd - 1));
+
+	/* transmit to specific segment & general default */
+	for (i = 0; i < mac_cls->num_active_classified; i++) {
+		LOG_CLS((long)mac_cls->active_classifieds[i],
+				pkt, cmp_info, clsd_data);
 		push_packet(pkt, clsd_data +
-				(long)cmp_info->active_classifieds[i]);
+				(long)mac_cls->active_classifieds[i]);
+	}
+
+	if (gen_def_clsd_idx >= 0 && vid != VLAN_UNTAGGED_VID) {
+		LOG_CLS((long)gen_def_clsd_idx, pkt, cmp_info, clsd_data);
+		push_packet(pkt, clsd_data + (long)gen_def_clsd_idx);
+	}
+}
+
+/* select index of classified */
+static inline int
+select_classified_index(const struct rte_mbuf *pkt,
+		struct component_info *cmp_info)
+{
+	int ret;
+	struct ether_hdr *eth;
+	void *lookup_data;
+	struct mac_classification *mac_cls;
+	uint16_t vid;
+
+	eth = rte_pktmbuf_mtod(pkt, struct ether_hdr *);
+	vid = get_vid(pkt);
+
+	/* select mac address classification by vid */
+	mac_cls = cmp_info->mac_classifications[vid];
+	if (unlikely(mac_cls == NULL)) {
+		LOG_DBG(cmp_info->name, "Mac classification is not registered. vid=%hu\n",
+				vid);
+		return get_general_default_classified_index(cmp_info);
+	}
+
+	/* find in table (by destination mac address) */
+	ret = rte_hash_lookup_data(mac_cls->classification_tab,
+			(const void *)&eth->d_addr, &lookup_data);
+	if (ret >= 0) {
+		LOG_DBG(cmp_info->name, "Mac address is registered. ret=%d, vid=%hu\n",
+				ret, vid);
+		return (int)(long)lookup_data;
+	}
+
+	LOG_DBG(cmp_info->name,
+			"Mac address is not registered. ret=%d, (EINVAL=%d, ENOENT=%d)\n",
+			ret, EINVAL, ENOENT);
+
+	/* check if packet is l2 multicast */
+	if (unlikely(is_multicast_ether_addr(&eth->d_addr)))
+		return -2;
+
+	/* if default is not set, use untagged's default */
+	if (unlikely(mac_cls->default_classified < 0 &&
+			vid != VLAN_UNTAGGED_VID)) {
+		LOG_DBG(cmp_info->name, "Vid's default is not set. use general default. vid=%hu\n",
+				vid);
+		return get_general_default_classified_index(cmp_info);
 	}
+
+	/* use default */
+	LOG_DBG(cmp_info->name, "Use vid's default. vid=%hu\n", vid);
+	return mac_cls->default_classified;
 }
 
 /*
@@ -457,55 +757,29 @@ classify_packet(struct rte_mbuf **rx_pkts, uint16_t n_rx,
 		struct component_info *cmp_info,
 		struct classified_data *clsd_data)
 {
-	int ret;
 	int i;
-	struct ether_hdr *eth;
-	void *lookup_data;
-	char mac_addr_str[ETHER_ADDR_STR_BUF_SZ];
+	long clsd_idx;
 
 	for (i = 0; i < n_rx; i++) {
-		eth = rte_pktmbuf_mtod(rx_pkts[i], struct ether_hdr *);
-
-		/* find in table (by destination mac address)*/
-		ret = rte_hash_lookup_data(cmp_info->classifier_table,
-				(const void *)&eth->d_addr, &lookup_data);
-		if (ret < 0) {
-			/* L2 multicast(include broadcast) ? */
-			if (unlikely(is_multicast_ether_addr(&eth->d_addr))) {
-				RTE_LOG(DEBUG, SPP_CLASSIFIER_MAC,
-						"multicast mac address.\n");
-				handle_l2multicast_packet(rx_pkts[i],
-						cmp_info,
-						clsd_data);
-				continue;
-			}
-
-			/* if no default, drop packet */
-			if (unlikely(cmp_info->default_classified ==
-					-1)) {
-				ether_format_addr(mac_addr_str,
-						sizeof(mac_addr_str),
-						&eth->d_addr);
-				RTE_LOG(ERR, SPP_CLASSIFIER_MAC,
-						"unknown mac address. "
-						"ret=%d, mac_addr=%s\n",
-						ret, mac_addr_str);
-				rte_pktmbuf_free(rx_pkts[i]);
-				continue;
-			}
-
-			/* to default classified */
-			RTE_LOG(DEBUG, SPP_CLASSIFIER_MAC,
-					"to default classified.\n");
-			lookup_data = (void *)(long)cmp_info->
-					default_classified;
+		LOG_PKT(cmp_info->name, rx_pkts[i]);
+
+		clsd_idx = select_classified_index(rx_pkts[i], cmp_info);
+		LOG_CLS(clsd_idx, rx_pkts[i], cmp_info, clsd_data);
+
+		if (likely(clsd_idx >= 0)) {
+			LOG_DBG(cmp_info->name, "as unicast packet. i=%d\n",
+					i);
+			push_packet(rx_pkts[i], clsd_data + clsd_idx);
+		} else if (unlikely(clsd_idx == -1)) {
+			LOG_DBG(cmp_info->name, "no destination. drop packet. i=%d\n",
+					i);
+			rte_pktmbuf_free(rx_pkts[i]);
+		} else if (unlikely(clsd_idx == -2)) {
+			LOG_DBG(cmp_info->name, "as multicast packet. i=%d\n",
+					i);
+			handle_l2multicast_packet(rx_pkts[i],
+					cmp_info, clsd_data);
 		}
-
-		/*
-		 * set mbuf pointer to tx buffer
-		 * and transmit packet, if buffer is filled
-		 */
-		push_packet(rx_pkts[i], clsd_data + (long)lookup_data);
 	}
 }
 
@@ -575,6 +849,9 @@ spp_classifier_mac_update(struct spp_component_info *component_info)
 			mng_info->upd_index))
 		rte_delay_us_block(CHANGE_UPDATE_INDEX_WAIT_INTERVAL);
 
+	/* uninitialize old */
+	uninit_component_info(mng_info->cmp_infos + mng_info->upd_index);
+
 	RTE_LOG(INFO, SPP_CLASSIFIER_MAC,
 			"Component[%u] Complete update component.\n", id);
 
@@ -602,8 +879,10 @@ spp_classifier_mac_do(int id)
 
 	/* initialize */
 	ret = init_classifier(mng_info);
-	if (unlikely(ret != 0))
+	if (unlikely(ret != 0)) {
+		uninit_classifier(mng_info);
 		return ret;
+	}
 
 	while (likely(spp_get_core_status(lcore_id) == SPP_CORE_FORWARD) &&
 			likely(spp_check_core_index(lcore_id) == 0)) {
@@ -710,20 +989,79 @@ spp_classifier_get_component_status(
 	return 0;
 }
 
+static void
+mac_classification_iterate_table(
+		struct spp_iterate_classifier_table_params *params,
+		uint16_t vid,
+		struct mac_classification *mac_cls,
+		__rte_unused struct component_info *cmp_info,
+		struct classified_data *clsd_data)
+{
+	int ret;
+	const void *key;
+	void *data;
+	uint32_t next;
+	struct spp_port_index port;
+	char mac_addr_str[ETHER_ADDR_STR_BUF_SZ];
+	enum spp_classifier_type type;
+
+	type = SPP_CLASSIFIER_TYPE_VLAN;
+	if (unlikely(vid == VLAN_UNTAGGED_VID))
+		type = SPP_CLASSIFIER_TYPE_MAC;
+
+	if (mac_cls->default_classified >= 0) {
+		port.iface_type = (clsd_data +
+				mac_cls->default_classified)->iface_type;
+		port.iface_no   = (clsd_data +
+				mac_cls->default_classified)->iface_no_global;
+
+		LOG_ENT((long)mac_cls->default_classified,
+				vid,
+				SPP_DEFAULT_CLASSIFIED_SPEC_STR,
+				cmp_info, clsd_data);
+
+		(*params->element_proc)(
+				params,
+				type,
+				vid,
+				SPP_DEFAULT_CLASSIFIED_SPEC_STR,
+				&port);
+	}
+
+	next = 0;
+	while (1) {
+		ret = rte_hash_iterate(mac_cls->classification_tab,
+				&key, &data, &next);
+
+		if (unlikely(ret < 0))
+			break;
+
+		ether_format_addr(mac_addr_str, sizeof(mac_addr_str),
+				(const struct ether_addr *)key);
+
+		port.iface_type = (clsd_data + (long)data)->iface_type;
+		port.iface_no   = (clsd_data + (long)data)->iface_no_global;
+
+		LOG_ENT((long)data, vid, mac_addr_str, cmp_info, clsd_data);
+
+		(*params->element_proc)(
+				params,
+				type,
+				vid,
+				mac_addr_str,
+				&port);
+	}
+}
+
 /* classifier(mac address) iterate classifier table. */
 int
 spp_classifier_mac_iterate_table(
 		struct spp_iterate_classifier_table_params *params)
 {
-	int ret, i;
-	const void *key;
-	void *data;
-	uint32_t next = 0;
+	int i, n;
 	struct management_info *mng_info;
 	struct component_info *cmp_info;
 	struct classified_data *clsd_data;
-	struct spp_port_index port;
-	char mac_addr_str[ETHER_ADDR_STR_BUF_SZ];
 
 	for (i = 0; i < RTE_MAX_LCORE; i++) {
 		mng_info = g_mng_infos + i;
@@ -731,49 +1069,21 @@ spp_classifier_mac_iterate_table(
 			continue;
 
 		cmp_info = mng_info->cmp_infos + mng_info->ref_index;
-
 		clsd_data = cmp_info->classified_data_tx;
 
 		RTE_LOG(DEBUG, SPP_CLASSIFIER_MAC,
 			"Core[%u] Start iterate classifier table.\n", i);
 
-		if (cmp_info->default_classified >= 0) {
-			port.iface_type = (clsd_data +
-					cmp_info->default_classified)->
-					iface_type;
-			port.iface_no   = (clsd_data +
-					cmp_info->default_classified)->
-					iface_no_global;
-
-			(*params->element_proc)(
-					params,
-					SPP_CLASSIFIER_TYPE_MAC,
-					SPP_DEFAULT_CLASSIFIED_SPEC_STR,
-					&port);
-		}
-
-		next = 0;
-		while (1) {
-			ret = rte_hash_iterate(
-					cmp_info->classifier_table,
-					&key, &data, &next);
-
-			if (unlikely(ret < 0))
-				break;
-
-			ether_format_addr(mac_addr_str, sizeof(mac_addr_str),
-					(const struct ether_addr *)key);
-
-			port.iface_type = (clsd_data + (long)data)->
-					iface_type;
-			port.iface_no   = (clsd_data + (long)data)->
-					iface_no_global;
+		for (n = 0; n < SPP_NUM_VLAN_VID; ++n) {
+			if (cmp_info->mac_classifications[n] == NULL)
+				continue;
 
-			(*params->element_proc)(
+			mac_classification_iterate_table(
 					params,
-					SPP_CLASSIFIER_TYPE_MAC,
-					mac_addr_str,
-					&port);
+					(uint16_t)n,
+					cmp_info->mac_classifications[n],
+					cmp_info,
+					clsd_data);
 		}
 	}
 
diff --git a/src/vf/command_dec.c b/src/vf/command_dec.c
index 374a105..35d421a 100644
--- a/src/vf/command_dec.c
+++ b/src/vf/command_dec.c
@@ -51,6 +51,7 @@
 const char *CLASSIFILER_TYPE_STRINGS[] = {
 	"none",
 	"mac",
+	"vlan",
 
 	/* termination */ "",
 };
@@ -535,21 +536,18 @@ decode_classifier_type_value(void *output, const char *arg_val)
 	return 0;
 }
 
-/* decoding procedure of value for classifier_table command */
+/* decoding procedure of vlan id for classifier_table command */
 static int
-decode_classifier_value_value(void *output, const char *arg_val)
+decode_classifier_vid_value(void *output, const char *arg_val)
 {
 	int ret = -1;
-	struct spp_command_classifier_table *classifier_table = output;
-	switch (classifier_table->type) {
-	case SPP_CLASSIFIER_TYPE_MAC:
-		ret = decode_mac_addr_str_value(classifier_table->value,
+	ret = get_int_value(output, arg_val, 0, ETH_VLAN_ID_MAX);
+	if (unlikely(ret < 0)) {
+		RTE_LOG(ERR, SPP_COMMAND_PROC, "Bad VLAN ID. val=%s\n",
 				arg_val);
-		break;
-	default:
-		break;
+		return -1;
 	}
-	return ret;
+	return 0;
 }
 
 /* decoding procedure of port for classifier_table command */
@@ -571,20 +569,24 @@ decode_classifier_port_value(void *output, const char *arg_val)
 		return -1;
 	}
 
+	if (classifier_table->type == SPP_CLASSIFIER_TYPE_MAC)
+		classifier_table->vid = ETH_VLAN_ID_MAX;
+
 	if (unlikely(classifier_table->action == SPP_CMD_ACTION_ADD)) {
-		if (!spp_check_mac_used_port(0, tmp_port.iface_type,
-				tmp_port.iface_no)) {
+		if (!spp_check_classid_used_port(ETH_VLAN_ID_MAX, 0,
+				tmp_port.iface_type, tmp_port.iface_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);
+		mac_addr = spp_change_mac_str_to_int64(classifier_table->mac);
 		if (mac_addr < 0)
 			return -1;
 
-		if (!spp_check_mac_used_port((uint64_t)mac_addr,
+		if (!spp_check_classid_used_port(classifier_table->vid,
+				(uint64_t)mac_addr,
 				tmp_port.iface_type, tmp_port.iface_no)) {
 			RTE_LOG(ERR, SPP_COMMAND_PROC,
 					"Port in used. (classifier_table command) val=%s\n",
@@ -610,7 +612,7 @@ struct decode_parameter_list {
 
 /* parameter list for each command */
 static struct decode_parameter_list parameter_list[][SPP_CMD_MAX_PARAMETERS] = {
-	{                                /* classifier_table */
+	{                                /* classifier_table(mac) */
 		{
 			.name = "action",
 			.offset = offsetof(struct spp_command,
@@ -624,10 +626,43 @@ static struct decode_parameter_list parameter_list[][SPP_CMD_MAX_PARAMETERS] = {
 			.func = decode_classifier_type_value
 		},
 		{
-			.name = "value",
+			.name = "mac address",
+			.offset = offsetof(struct spp_command,
+					spec.classifier_table.mac),
+			.func = decode_mac_addr_str_value
+		},
+		{
+			.name = "port",
 			.offset = offsetof(struct spp_command,
 					spec.classifier_table),
-			.func = decode_classifier_value_value
+			.func = decode_classifier_port_value
+		},
+		DECODE_PARAMETER_LIST_EMPTY,
+	},
+	{                                /* classifier_table(VLAN) */
+		{
+			.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
+		},
+		{
+			.name = "vlan id",
+			.offset = offsetof(struct spp_command,
+					spec.classifier_table.vid),
+			.func = decode_classifier_vid_value
+		},
+		{
+			.name = "mac address",
+			.offset = offsetof(struct spp_command,
+					spec.classifier_table.mac),
+			.func = decode_mac_addr_str_value
 		},
 		{
 			.name = "port",
@@ -747,7 +782,9 @@ struct decode_command_list {
 /* command list */
 static struct decode_command_list command_list[] = {
 	{ "classifier_table", 5, 5, decode_command_parameter_in_list },
-						/* classifier_table */
+						/* classifier_table(mac) */
+	{ "classifier_table", 6, 6, decode_command_parameter_in_list },
+						/* classifier_table(vlan) */
 	{ "flush",            1, 1, NULL },     /* flush            */
 	{ "_get_client_id",   1, 1, NULL },     /* _get_client_id   */
 	{ "status",           1, 1, NULL },     /* status           */
@@ -767,6 +804,7 @@ decode_command_in_list(struct spp_command_request *request,
 			struct spp_command_decode_error *error)
 {
 	int ret = 0;
+	int command_name_check = 0;
 	struct decode_command_list *list = NULL;
 	int i = 0;
 	int argc = 0;
@@ -792,11 +830,8 @@ decode_command_in_list(struct spp_command_request *request,
 
 		if (unlikely(argc < list->param_min) ||
 				unlikely(list->param_max < argc)) {
-			RTE_LOG(ERR, SPP_COMMAND_PROC,
-					"Parameter number out of range."
-					"request_str=%s\n", request_str);
-			return set_decode_error(error, SPP_CMD_DERR_BAD_FORMAT,
-					NULL);
+			command_name_check = 1;
+			continue;
 		}
 
 		request->commands[0].type = i;
@@ -806,6 +841,12 @@ decode_command_in_list(struct spp_command_request *request,
 		return 0;
 	}
 
+	if (command_name_check != 0) {
+		RTE_LOG(ERR, SPP_COMMAND_PROC, "Parameter number out of range."
+				"request_str=%s\n", request_str);
+		return set_decode_error(error, SPP_CMD_DERR_BAD_FORMAT, NULL);
+	}
+
 	RTE_LOG(ERR, SPP_COMMAND_PROC,
 			"Unknown command. command=%s, request_str=%s\n",
 			argv[0], request_str);
diff --git a/src/vf/command_dec.h b/src/vf/command_dec.h
index f919b16..9f7bada 100644
--- a/src/vf/command_dec.h
+++ b/src/vf/command_dec.h
@@ -74,14 +74,32 @@ enum spp_command_decode_error_code {
  *            defined in command_dec.c
  */
 enum spp_command_type {
-	SPP_CMDTYPE_CLASSIFIER_TABLE, /**< classifier_table command */
-	SPP_CMDTYPE_FLUSH,            /**< flush command */
-	SPP_CMDTYPE_CLIENT_ID,        /**< get_client_id command */
-	SPP_CMDTYPE_STATUS,           /**< status command */
-	SPP_CMDTYPE_EXIT,             /**< exit command */
-	SPP_CMDTYPE_COMPONENT,        /**< component command */
-	SPP_CMDTYPE_PORT,             /**< port command */
-	SPP_CMDTYPE_CANCEL,           /**< cancel command */
+	/** classifier_table command(mac) */
+	SPP_CMDTYPE_CLASSIFIER_TABLE_MAC,
+
+	/** classifier_table command(VLAN) */
+	SPP_CMDTYPE_CLASSIFIER_TABLE_VLAN,
+
+	/** flush command */
+	SPP_CMDTYPE_FLUSH,
+
+	/** get_client_id command */
+	SPP_CMDTYPE_CLIENT_ID,
+
+	/** status command */
+	SPP_CMDTYPE_STATUS,
+
+	/** exit command */
+	SPP_CMDTYPE_EXIT,
+
+	/** component command */
+	SPP_CMDTYPE_COMPONENT,
+
+	/** port command */
+	SPP_CMDTYPE_PORT,
+
+	/** cancel command */
+	SPP_CMDTYPE_CANCEL,
 };
 
 /** "classifier_table" command specific parameters */
@@ -92,8 +110,11 @@ struct spp_command_classifier_table {
 	/** Classify type (currently only for mac) */
 	enum spp_classifier_type type;
 
-	/** Value to be classified */
-	char value[SPP_CMD_VALUE_BUFSZ];
+	/** VLAN ID to be classified */
+	int vid;
+
+	/** MAC address to be classified */
+	char mac[SPP_CMD_VALUE_BUFSZ];
 
 	/** Destination port type and number */
 	struct spp_port_index port;
diff --git a/src/vf/command_proc.c b/src/vf/command_proc.c
index a00181b..11c7cc3 100644
--- a/src/vf/command_proc.c
+++ b/src/vf/command_proc.c
@@ -102,6 +102,18 @@ const char *PORT_ABILITY_STATUS_STRINGS[] = {
 	/* termination */ "",
 };
 
+/*
+ * classifier type string list
+ * do it same as the order of enum spp_classifier_type (spp_vf.h)
+ */
+const char *CLASSIFILER_TYPE_STATUS_STRINGS[] = {
+	"none",
+	"mac",
+	"vlan",
+
+	/* termination */ "",
+};
+
 /* append a comma for JSON format */
 static int
 append_json_comma(char **output)
@@ -226,13 +238,15 @@ execute_command(const struct spp_command *command)
 	int ret = 0;
 
 	switch (command->type) {
-	case SPP_CMDTYPE_CLASSIFIER_TABLE:
+	case SPP_CMDTYPE_CLASSIFIER_TABLE_MAC:
+	case SPP_CMDTYPE_CLASSIFIER_TABLE_VLAN:
 		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.vid,
+				command->spec.classifier_table.mac,
 				&command->spec.classifier_table.port);
 		break;
 
@@ -688,13 +702,14 @@ append_core_value(const char *name, char **output,
 static int
 append_classifier_element_value(
 		struct spp_iterate_classifier_table_params *params,
-		__rte_unused enum spp_classifier_type type,
-		const char *data,
+		enum spp_classifier_type type,
+		int vid, const char *mac,
 		const struct spp_port_index *port)
 {
 	int ret = -1;
 	char *buff, *tmp_buff;
 	char port_str[CMD_TAG_APPEND_SIZE];
+	char value_str[SPP_MIN_STR_LEN];
 	buff = params->output;
 	tmp_buff = spp_strbuf_allocate(CMD_RES_BUF_INIT_SIZE);
 	if (unlikely(tmp_buff == NULL)) {
@@ -705,11 +720,25 @@ append_classifier_element_value(
 
 	spp_format_port_string(port_str, port->iface_type, port->iface_no);
 
-	ret = append_json_str_value("type", &tmp_buff, "mac");
+	ret = append_json_str_value("type", &tmp_buff,
+			CLASSIFILER_TYPE_STATUS_STRINGS[type]);
 	if (unlikely(ret < 0))
 		return ret;
 
-	ret = append_json_str_value("value", &tmp_buff, data);
+	memset(value_str, 0x00, SPP_MIN_STR_LEN);
+	switch (type) {
+	case SPP_CLASSIFIER_TYPE_MAC:
+		sprintf(value_str, "%s", mac);
+		break;
+	case SPP_CLASSIFIER_TYPE_VLAN:
+		sprintf(value_str, "%d/%s", vid, mac);
+		break;
+	default:
+		/* not used */
+		break;
+	}
+
+	ret = append_json_str_value("value", &tmp_buff, value_str);
 	if (unlikely(ret < 0))
 		return ret;
 
diff --git a/src/vf/spp_vf.c b/src/vf/spp_vf.c
index 4463d41..ef75159 100644
--- a/src/vf/spp_vf.c
+++ b/src/vf/spp_vf.c
@@ -591,10 +591,12 @@ dump_interface_info(const struct iface_info *iface_info)
 			continue;
 
 		RTE_LOG(DEBUG, APP, "phy  [%d] type=%d, no=%d, port=%d, "
-				"mac=%08lx(%s)\n",
+				"vid = %u, mac=%08lx(%s)\n",
 				cnt, port->iface_type, port->iface_no,
 				port->dpdk_port,
-				port->mac_addr, port->mac_addr_str);
+				port->class_id.vlantag.vid,
+				port->class_id.mac_addr,
+				port->class_id.mac_addr_str);
 	}
 	for (cnt = 0; cnt < RTE_MAX_ETHPORTS; cnt++) {
 		port = &iface_info->vhost[cnt];
@@ -602,10 +604,12 @@ dump_interface_info(const struct iface_info *iface_info)
 			continue;
 
 		RTE_LOG(DEBUG, APP, "vhost[%d] type=%d, no=%d, port=%d, "
-				"mac=%08lx(%s)\n",
+				"vid = %u, mac=%08lx(%s)\n",
 				cnt, port->iface_type, port->iface_no,
 				port->dpdk_port,
-				port->mac_addr, port->mac_addr_str);
+				port->class_id.vlantag.vid,
+				port->class_id.mac_addr,
+				port->class_id.mac_addr_str);
 	}
 	for (cnt = 0; cnt < RTE_MAX_ETHPORTS; cnt++) {
 		port = &iface_info->ring[cnt];
@@ -613,10 +617,12 @@ dump_interface_info(const struct iface_info *iface_info)
 			continue;
 
 		RTE_LOG(DEBUG, APP, "ring [%d] type=%d, no=%d, port=%d, "
-				"mac=%08lx(%s)\n",
+				"vid = %u, mac=%08lx(%s)\n",
 				cnt, port->iface_type, port->iface_no,
 				port->dpdk_port,
-				port->mac_addr, port->mac_addr_str);
+				port->class_id.vlantag.vid,
+				port->class_id.mac_addr,
+				port->class_id.mac_addr_str);
 	}
 }
 
@@ -712,15 +718,21 @@ init_iface_info(void)
 	int port_cnt;  /* increment ether ports */
 	memset(&g_iface_info, 0x00, sizeof(g_iface_info));
 	for (port_cnt = 0; port_cnt < RTE_MAX_ETHPORTS; port_cnt++) {
-		g_iface_info.nic[port_cnt].iface_type   = UNDEF;
-		g_iface_info.nic[port_cnt].iface_no     = port_cnt;
-		g_iface_info.nic[port_cnt].dpdk_port = -1;
-		g_iface_info.vhost[port_cnt].iface_type   = UNDEF;
-		g_iface_info.vhost[port_cnt].iface_no     = port_cnt;
-		g_iface_info.vhost[port_cnt].dpdk_port = -1;
-		g_iface_info.ring[port_cnt].iface_type   = UNDEF;
-		g_iface_info.ring[port_cnt].iface_no     = port_cnt;
-		g_iface_info.ring[port_cnt].dpdk_port = -1;
+		g_iface_info.nic[port_cnt].iface_type = UNDEF;
+		g_iface_info.nic[port_cnt].iface_no   = port_cnt;
+		g_iface_info.nic[port_cnt].dpdk_port  = -1;
+		g_iface_info.nic[port_cnt].class_id.vlantag.vid =
+				ETH_VLAN_ID_MAX;
+		g_iface_info.vhost[port_cnt].iface_type = UNDEF;
+		g_iface_info.vhost[port_cnt].iface_no   = port_cnt;
+		g_iface_info.vhost[port_cnt].dpdk_port  = -1;
+		g_iface_info.vhost[port_cnt].class_id.vlantag.vid =
+				ETH_VLAN_ID_MAX;
+		g_iface_info.ring[port_cnt].iface_type = UNDEF;
+		g_iface_info.ring[port_cnt].iface_no   = port_cnt;
+		g_iface_info.ring[port_cnt].dpdk_port  = -1;
+		g_iface_info.ring[port_cnt].class_id.vlantag.vid =
+				ETH_VLAN_ID_MAX;
 	}
 }
 
@@ -1098,13 +1110,13 @@ spp_get_client_id(void)
  * Check mac address used on the port for registering or removing
  */
 int
-spp_check_mac_used_port(
-		uint64_t mac_addr,
-		enum port_type iface_type,
-		int iface_no)
+spp_check_classid_used_port(
+		int vid, uint64_t mac_addr,
+		enum port_type iface_type, int iface_no)
 {
 	struct spp_port_info *port_info = get_iface_info(iface_type, iface_no);
-	return (mac_addr == port_info->mac_addr);
+	return ((mac_addr == port_info->class_id.mac_addr) &&
+			(vid == port_info->class_id.vlantag.vid));
 }
 
 /*
@@ -1190,62 +1202,78 @@ set_component_change_port(struct spp_port_info *port, enum spp_port_rxtx rxtx)
 int
 spp_update_classifier_table(
 		enum spp_command_action action,
-		enum spp_classifier_type type,
-		const char *data,
+		enum spp_classifier_type type __attribute__ ((unused)),
+		int vid,
+		const char *mac_addr_str,
 		const struct spp_port_index *port)
 {
 	struct spp_port_info *port_info = NULL;
 	int64_t ret_mac = 0;
 	uint64_t mac_addr = 0;
 
-	if (type == SPP_CLASSIFIER_TYPE_MAC) {
-		RTE_LOG(DEBUG, APP, "update_classifier_table ( type = mac, data = %s, port = %d:%d )\n",
-				data, port->iface_type, port->iface_no);
+	RTE_LOG(DEBUG, APP, "update_classifier_table ( type = mac, mac addr = %s, port = %d:%d )\n",
+			mac_addr_str, port->iface_type, port->iface_no);
+
+	ret_mac = spp_change_mac_str_to_int64(mac_addr_str);
+	if (unlikely(ret_mac == -1)) {
+		RTE_LOG(ERR, APP, "MAC address format error. ( mac = %s )\n",
+				mac_addr_str);
+		return SPP_RET_NG;
+	}
+	mac_addr = (uint64_t)ret_mac;
+
+	port_info = get_iface_info(port->iface_type, port->iface_no);
+	if (unlikely(port_info == NULL)) {
+		RTE_LOG(ERR, APP, "No port. ( port = %d:%d )\n",
+				port->iface_type, port->iface_no);
+		return SPP_RET_NG;
+	}
+	if (unlikely(port_info->iface_type == UNDEF)) {
+		RTE_LOG(ERR, APP, "Port not added. ( port = %d:%d )\n",
+				port->iface_type, port->iface_no);
+		return SPP_RET_NG;
+	}
 
-		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);
+	if (action == SPP_CMD_ACTION_DEL) {
+		/* Delete */
+		if ((port_info->class_id.vlantag.vid != 0) &&
+				unlikely(port_info->class_id.vlantag.vid !=
+				vid)) {
+			RTE_LOG(ERR, APP, "VLAN ID is different. ( vid = %d )\n",
+					vid);
+			return SPP_RET_NG;
+		}
+		if ((port_info->class_id.mac_addr != 0) &&
+				unlikely(port_info->class_id.mac_addr !=
+						mac_addr)) {
+			RTE_LOG(ERR, APP, "MAC address is different. ( mac = %s )\n",
+					mac_addr_str);
 			return SPP_RET_NG;
 		}
-		mac_addr = (uint64_t)ret_mac;
 
-		port_info = get_iface_info(port->iface_type, port->iface_no);
-		if (unlikely(port_info == NULL)) {
-			RTE_LOG(ERR, APP, "No port. ( port = %d:%d )\n",
-					port->iface_type, port->iface_no);
+		port_info->class_id.vlantag.vid = ETH_VLAN_ID_MAX;
+		port_info->class_id.mac_addr    = 0;
+		memset(port_info->class_id.mac_addr_str, 0x00, SPP_MIN_STR_LEN);
+	} else if (action == SPP_CMD_ACTION_ADD) {
+		/* Setting */
+		if (unlikely(port_info->class_id.vlantag.vid !=
+				ETH_VLAN_ID_MAX)) {
+			RTE_LOG(ERR, APP, "Port in used. ( port = %d:%d, vlan = %d != %d )\n",
+					port->iface_type, port->iface_no,
+					port_info->class_id.vlantag.vid, vid);
 			return SPP_RET_NG;
 		}
-		if (unlikely(port_info->iface_type == UNDEF)) {
-			RTE_LOG(ERR, APP, "Port not added. ( port = %d:%d )\n",
-					port->iface_type, port->iface_no);
+		if (unlikely(port_info->class_id.mac_addr != 0)) {
+			RTE_LOG(ERR, APP, "Port in used. ( port = %d:%d, mac = %s != %s )\n",
+					port->iface_type, port->iface_no,
+					port_info->class_id.mac_addr_str,
+					mac_addr_str);
 			return SPP_RET_NG;
 		}
 
-		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;
-			}
-
-			port_info->mac_addr = 0;
-			memset(port_info->mac_addr_str, 0x00, SPP_MIN_STR_LEN);
-		} else if (action == SPP_CMD_ACTION_ADD) {
-			/* Setting */
-			if (unlikely(port_info->mac_addr != 0)) {
-				RTE_LOG(ERR, APP, "Port in used. ( port = %d:%d )\n",
-						port->iface_type,
-						port->iface_no);
-				return SPP_RET_NG;
-			}
-
-			port_info->mac_addr = mac_addr;
-			strcpy(port_info->mac_addr_str, data);
-		}
+		port_info->class_id.vlantag.vid = vid;
+		port_info->class_id.mac_addr    = mac_addr;
+		strcpy(port_info->class_id.mac_addr_str, mac_addr_str);
 	}
 
 	set_component_change_port(port_info, SPP_PORT_RXTX_TX);
diff --git a/src/vf/spp_vf.h b/src/vf/spp_vf.h
index e51cd1a..fa01b85 100644
--- a/src/vf/spp_vf.h
+++ b/src/vf/spp_vf.h
@@ -85,8 +85,8 @@
 /** Maximum number of port abilities available */
 #define SPP_PORT_ABILITY_MAX 4
 
-/** Maximum VLAN ID */
-#define SPP_VLAN_VID_MAX 4096
+/** Number of VLAN ID */
+#define SPP_NUM_VLAN_VID 4096
 
 /** Maximum VLAN PCP */
 #define SPP_VLAN_PCP_MAX 7
@@ -118,7 +118,8 @@ enum spp_component_type {
  */
 enum spp_classifier_type {
 	SPP_CLASSIFIER_TYPE_NONE, /**< Type none */
-	SPP_CLASSIFIER_TYPE_MAC   /**< MAC address */
+	SPP_CLASSIFIER_TYPE_MAC,  /**< MAC address */
+	SPP_CLASSIFIER_TYPE_VLAN  /**< VLAN ID */
 };
 
 /**
@@ -181,15 +182,22 @@ struct spp_port_ability {
 	union spp_ability_data data;   /**< Port ability data */
 };
 
+/** Port class identifier for classifying */
+struct spp_port_class_identifier {
+	uint64_t mac_addr;                      /**< Mac address (binary) */
+	char     mac_addr_str[SPP_MIN_STR_LEN]; /**< Mac address (text) */
+	struct spp_vlantag_info vlantag;        /**< VLAN tag information */
+};
+
 /**
  * Port info
  */
 struct spp_port_info {
-	enum port_type iface_type; /**< Interface type (phy/vhost/ring) */
-	int            iface_no;   /**< Interface number */
-	int            dpdk_port;  /**< DPDK port number */
-	uint64_t       mac_addr;   /**< Mac address for classifying */
-	char           mac_addr_str[SPP_MIN_STR_LEN]; /**< Mac address */
+	enum port_type iface_type;      /**< Interface type (phy/vhost/ring) */
+	int            iface_no;        /**< Interface number */
+	int            dpdk_port;       /**< DPDK port number */
+	struct spp_port_class_identifier class_id;
+					/**< Port class identifier */
 	struct spp_port_ability ability[SPP_PORT_ABILITY_MAX];
 					/**< Port ability */
 };
@@ -235,7 +243,8 @@ int spp_get_client_id(void);
 int spp_update_classifier_table(
 		enum spp_command_action action,
 		enum spp_classifier_type type,
-		const char *data,
+		int vid,
+		const char *mac,
 		const struct spp_port_index *port);
 
 /**
@@ -331,7 +340,7 @@ struct spp_iterate_classifier_table_params;
 typedef int (*spp_iterate_classifier_element_proc)(
 		struct spp_iterate_classifier_table_params *params,
 		enum spp_classifier_type type,
-		const char *data,
+		int vid, const char *mac,
 		const struct spp_port_index *port);
 
 /** iterate classifier table parameters */
@@ -423,6 +432,8 @@ int spp_get_component_id(const char *name);
 /**
  * Check mac address used on the port for registering or removing
  *
+ * @param vid
+ *  VLAN ID to be validated.
  * @param mac_addr
  *  Mac address to be validated.
  * @param iface_type
@@ -431,12 +442,12 @@ int spp_get_component_id(const char *name);
  *  Interface number to be validated.
  *
  * @return
- *  True if target MAC address matches MAC address of port.
+ *  True if target identifier(VLAN ID, MAC address)
+ *  matches identifier(VLAN ID, MAC address) of port.
  */
-int spp_check_mac_used_port(
-		uint64_t mac_addr,
-		enum port_type iface_type,
-		int iface_no);
+int spp_check_classid_used_port(
+		int vid, uint64_t mac_addr,
+		enum port_type iface_type, int iface_no);
 
 /**
  * Check if port has been added.
-- 
2.7.4



More information about the spp mailing list