[spp] [PATCH 4/7] spp_vf: add VLAN tag operate function to port

x-fn-spp at sl.ntt-tx.co.jp x-fn-spp at sl.ntt-tx.co.jp
Fri Feb 9 04:40:01 CET 2018


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

* Add VLAN tag operate function to port.
* Support set operation type of VLAN tag at port command.
* Support display information of VLAN tag at status command.

Signed-off-by: Kentaro Watanabe <watanabe.kentaro.z01 at as.ntt-tx.co.jp>
Signed-off-by: Naoki Takada <takada.naoki at lab.ntt.co.jp>
---
 src/vf/Makefile         |   2 +-
 src/vf/classifier_mac.c |  23 +--
 src/vf/command_dec.c    | 104 ++++++++++++-
 src/vf/command_dec.h    |  26 +++-
 src/vf/command_proc.c   | 143 +++++++++++++++--
 src/vf/spp_forward.c    |  22 +--
 src/vf/spp_port.c       | 403 ++++++++++++++++++++++++++++++++++++++++++++++++
 src/vf/spp_port.h       | 109 +++++++++++++
 src/vf/spp_vf.c         |  49 +++++-
 src/vf/spp_vf.h         |  58 ++++++-
 10 files changed, 876 insertions(+), 63 deletions(-)
 create mode 100644 src/vf/spp_port.c
 create mode 100644 src/vf/spp_port.h

diff --git a/src/vf/Makefile b/src/vf/Makefile
index d54af25..fe2ef2d 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 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 spp_port.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 cd186a2..93cec8f 100644
--- a/src/vf/classifier_mac.c
+++ b/src/vf/classifier_mac.c
@@ -19,7 +19,7 @@
 #include <rte_hash.h>
 
 #include "spp_vf.h"
-#include "ringlatencystats.h"
+#include "spp_port.h"
 #include "classifier_mac.h"
 
 #define RTE_LOGTYPE_SPP_CLASSIFIER_MAC RTE_LOGTYPE_USER1
@@ -333,16 +333,8 @@ transmit_packet(struct classified_data *classified_data)
 	int i;
 	uint16_t n_tx;
 
-#ifdef SPP_RINGLATENCYSTATS_ENABLE
-	if (classified_data->iface_type == RING)
-		/* if tx-if is ring, set ringlatencystats */
-		spp_ringlatencystats_add_time_stamp(classified_data->iface_no,
-				classified_data->pkts,
-				classified_data->num_pkt);
-#endif
-
 	/* transmit packets */
-	n_tx = rte_eth_tx_burst(classified_data->port, 0,
+	n_tx = spp_eth_tx_burst(classified_data->port, 0,
 			classified_data->pkts, classified_data->num_pkt);
 
 	/* free cannot transmit packets */
@@ -489,6 +481,8 @@ 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)) {
+		/* Change reference index of port ability. */
+		spp_port_ability_change_index(PORT_ABILITY_CHG_INDEX_REF, 0, 0);
 
 		/* Transmit all packets for switching the using data. */
 		transmit_all_packet(classifier_mng_info->info +
@@ -618,18 +612,11 @@ spp_classifier_mac_do(int id)
 			continue;
 
 		/* retrieve packets */
-		n_rx = rte_eth_rx_burst(classified_data_rx->port, 0,
+		n_rx = spp_eth_rx_burst(classified_data_rx->port, 0,
 				rx_pkts, MAX_PKT_BURST);
 		if (unlikely(n_rx == 0))
 			continue;
 
-#ifdef SPP_RINGLATENCYSTATS_ENABLE
-		if (classified_data_rx->iface_type == RING)
-			spp_ringlatencystats_calculate_latency(
-					classified_data_rx->iface_no,
-					rx_pkts, n_rx);
-#endif
-
 		/* classify and transmit (filled) */
 		classify_packet(rx_pkts, n_rx, classifier_info,
 				classified_data_tx);
diff --git a/src/vf/command_dec.c b/src/vf/command_dec.c
index 59e825c..9a4496f 100644
--- a/src/vf/command_dec.c
+++ b/src/vf/command_dec.c
@@ -1,6 +1,7 @@
 #include <unistd.h>
 #include <string.h>
 
+#include <rte_ether.h>
 #include <rte_log.h>
 #include <rte_branch_prediction.h>
 
@@ -46,6 +47,18 @@ const char *PORT_RXTX_STRINGS[] = {
 	/* termination */ "",
 };
 
+/*
+ * port ability string list
+ * do it same as the order of enum spp_port_ability_type (spp_vf.h)
+ */
+const char *PORT_ABILITY_STRINGS[] = {
+	"none",
+	"add_vlantag",
+	"del_vlantag",
+
+	/* termination */ "",
+};
+
 /* set decode error */
 inline int
 set_decode_error(struct spp_command_decode_error *error,
@@ -102,6 +115,27 @@ get_arrary_index(const char *match, const char *list[])
 	return -1;
 }
 
+/* Get int type value */
+static int
+get_int_value(
+		int *output,
+		const char *arg_val,
+		int min,
+		int max)
+{
+	int ret = 0;
+	char *endptr = NULL;
+	ret = strtol(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;
+}
+
 /* Get unsigned int type value */
 static int
 get_uint_value(
@@ -352,6 +386,59 @@ decode_port_name_value(void *output, const char *arg_val)
 	return decode_str_value(output, arg_val);
 }
 
+#/* decoding procedure of port ability for port command */
+static int
+decode_port_ability_value(void *output, const char *arg_val)
+{
+	int ret = 0;
+	struct spp_command_port *port = output;
+	struct spp_port_ability *ability = &port->ability;
+
+	switch (ability->ope) {
+	case SPP_PORT_ABILITY_OPE_NONE:
+		ret = get_arrary_index(arg_val, PORT_ABILITY_STRINGS);
+		if (unlikely(ret <= 0)) {
+			RTE_LOG(ERR, SPP_COMMAND_PROC,
+					"Unknown port ability. val=%s\n",
+					arg_val);
+			return -1;
+		}
+		ability->ope  = ret;
+		ability->rxtx = port->rxtx;
+		break;
+	case SPP_PORT_ABILITY_OPE_ADD_VLANTAG:
+		if (ability->data.vlantag.pcp == 0) {
+			ret = get_int_value(&ability->data.vlantag.vid,
+					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);
+				return -1;
+			}
+			ability->data.vlantag.pcp = -1;
+		} else {
+			ret = get_int_value(&ability->data.vlantag.pcp,
+					arg_val, 0, SPP_VLAN_PCP_MAX);
+			if (unlikely(ret < 0)) {
+				RTE_LOG(ERR, SPP_COMMAND_PROC,
+						"Bad VLAN PCP. val=%s\n",
+						arg_val);
+				return -1;
+			}
+		}
+		break;
+	case SPP_PORT_ABILITY_OPE_DEL_VLANTAG:
+		/* Nothing to do. */
+		break;
+	default:
+		/* Not used. */
+		break;
+	}
+
+	return 0;
+}
+
 /* decoding procedure of mac address string */
 static int
 decode_mac_addr_str_value(void *output, const char *arg_val)
@@ -566,6 +653,21 @@ static struct decode_parameter_list parameter_list[][SPP_CMD_MAX_PARAMETERS] = {
 			.offset = offsetof(struct spp_command, spec.port.name),
 			.func = decode_port_name_value
 		},
+		{
+			.name = "port ability 1",
+			.offset = offsetof(struct spp_command, spec.port),
+			.func = decode_port_ability_value
+		},
+		{
+			.name = "port ability 2",
+			.offset = offsetof(struct spp_command, spec.port),
+			.func = decode_port_ability_value
+		},
+		{
+			.name = "port ability 3",
+			.offset = offsetof(struct spp_command, spec.port),
+			.func = decode_port_ability_value
+		},
 		DECODE_PARAMETER_LIST_EMPTY,
 	},
 	{ DECODE_PARAMETER_LIST_EMPTY }, /* cancel           */
@@ -618,7 +720,7 @@ static struct decode_command_list command_list[] = {
 	{ "exit",             1, 1, NULL },     /* exit             */
 	{ "component",        3, 5, decode_command_parameter_in_list },
 						/* component        */
-	{ "port",             5, 5, decode_command_parameter_in_list },
+	{ "port",             5, 8, decode_command_parameter_in_list },
 						/* port             */
 	{ "cancel",           1, 1, NULL },     /* cancel           */
 	{ "",                 0, 0, NULL }      /* termination      */
diff --git a/src/vf/command_dec.h b/src/vf/command_dec.h
index 3eb4bc4..fc807f8 100644
--- a/src/vf/command_dec.h
+++ b/src/vf/command_dec.h
@@ -72,25 +72,35 @@ struct spp_command_flush {
 
 /** "component" command parameters */
 struct spp_command_component {
-	/**< Action identifier (start or stop) */
+	/** Action identifier (start or stop) */
 	enum spp_command_action action;
 
-	/**< Component name */
+	/** Component name */
 	char name[SPP_CMD_NAME_BUFSZ];
 
-	/**< Logical core number */
+	/** Logical core number */
 	unsigned int core;
 
-	/**< Component type */
+	/** Component type */
 	enum spp_component_type type;
 };
 
 /** "port" command parameters */
 struct spp_command_port {
-	enum spp_command_action action; /**< Action identifier (add or del) */
-	struct spp_port_index port;     /**< Port type and number */
-	enum spp_port_rxtx rxtx;        /**< rx/tx identifier */
-	char name[SPP_CMD_NAME_BUFSZ];  /**< Attached component name */
+	/** Action identifier (add or del) */
+	enum spp_command_action action;
+
+	/** Port type and number */
+	struct spp_port_index port;
+
+	/** rx/tx identifier */
+	enum spp_port_rxtx rxtx;
+
+	/** Attached component name */
+	char name[SPP_CMD_NAME_BUFSZ];
+
+	/** Port ability */
+	struct spp_port_ability ability;
 };
 
 /** command parameters */
diff --git a/src/vf/command_proc.c b/src/vf/command_proc.c
index f51c800..b76c586 100644
--- a/src/vf/command_proc.c
+++ b/src/vf/command_proc.c
@@ -5,6 +5,7 @@
 #include <rte_branch_prediction.h>
 
 #include "spp_vf.h"
+#include "spp_port.h"
 #include "string_buffer.h"
 #include "command_conn.h"
 #include "command_dec.h"
@@ -55,6 +56,18 @@ struct command_response_list {
 	int (*func)(const char *name, char **output, void *tmp);
 };
 
+/*
+ * port ability string list
+ * do it same as the order of enum spp_port_ability_type (spp_vf.h)
+ */
+const char *PORT_ABILITY_STATUS_STRINGS[] = {
+	"none",
+	"add",
+	"del",
+
+	/* termination */ "",
+};
+
 /* append a comma for JSON format */
 static int
 append_json_comma(char **output)
@@ -211,7 +224,8 @@ execute_command(const struct spp_command *command)
 				command->spec.port.action,
 				&command->spec.port.port,
 				command->spec.port.rxtx,
-				command->spec.port.name);
+				command->spec.port.name,
+				&command->spec.port.ability);
 		break;
 
 	case SPP_CMDTYPE_CANCEL:
@@ -422,15 +436,35 @@ append_interface_value(const char *name, char **output,
 	return ret;
 }
 
-/* append a list of port numbers for JSON format */
+/* append a value of vlan for JSON format */
+static int
+append_vlan_value(char **output, const int ope, const int vid, const int pcp)
+{
+	int ret = 0;
+	ret = append_json_str_value("operation", output,
+			PORT_ABILITY_STATUS_STRINGS[ope]);
+	if (unlikely(ret < 0))
+		return -1;
+
+	ret = append_json_int_value("id", output, vid);
+	if (unlikely(ret < 0))
+		return -1;
+
+	ret = append_json_int_value("pcp", output, pcp);
+	if (unlikely(ret < 0))
+		return -1;
+
+	return 0;
+}
+
+/* append a block of vlan for JSON format */
 static int
-apeend_port_array(const char *name, char **output,
-		const int num, const struct spp_port_index *ports)
+append_vlan_block(const char *name, char **output,
+		const int port_id, const enum spp_port_rxtx rxtx)
 {
 	int ret = -1;
 	int i = 0;
-	char port_str[CMD_TAG_APPEND_SIZE];
-	char append_str[CMD_TAG_APPEND_SIZE];
+	struct spp_port_ability *info = NULL;
 	char *tmp_buff = spp_strbuf_allocate(CMD_RES_BUF_INIT_SIZE);
 	if (unlikely(tmp_buff == NULL)) {
 		RTE_LOG(ERR, SPP_COMMAND_PROC,
@@ -439,15 +473,90 @@ apeend_port_array(const char *name, char **output,
 		return -1;
 	}
 
-	for (i = 0; i < num; i++) {
-		spp_format_port_string(port_str, ports[i].iface_type,
-				ports[i].iface_no);
+	spp_port_ability_get_info(port_id, rxtx, &info);
+	for (i = 0; i < SPP_PORT_ABILITY_MAX; i++) {
+		switch (info[i].ope) {
+		case SPP_PORT_ABILITY_OPE_ADD_VLANTAG:
+		case SPP_PORT_ABILITY_OPE_DEL_VLANTAG:
+			ret = append_vlan_value(&tmp_buff, info[i].ope,
+					info[i].data.vlantag.vid,
+					info[i].data.vlantag.pcp);
+			if (unlikely(ret < 0))
+				return -1;
+
+			/*
+			 * Change counter to "maximum+1" for exit the loop.
+			 * An if statement after loop termination is false
+			 * by "maximum+1 ".
+			 */
+			i = SPP_PORT_ABILITY_MAX + 1;
+			break;
+		default:
+			/* not used */
+			break;
+		}
+	}
+	if (i == SPP_PORT_ABILITY_MAX) {
+		ret = append_vlan_value(&tmp_buff, SPP_PORT_ABILITY_OPE_NONE,
+				0, 0);
+		if (unlikely(ret < 0))
+			return -1;
+	}
 
-		sprintf(append_str, "%s\"%s\"", JSON_APPEND_COMMA(i), port_str);
+	ret = append_json_block_brackets(name, output, tmp_buff);
+	spp_strbuf_free(tmp_buff);
+	return ret;
+}
 
-		tmp_buff = spp_strbuf_append(tmp_buff, append_str,
-				strlen(append_str));
-		if (unlikely(tmp_buff == NULL))
+/* append a block of port numbers for JSON format */
+static int
+append_port_block(char **output, const struct spp_port_index *port,
+		const enum spp_port_rxtx rxtx)
+{
+	int ret = -1;
+	char port_str[CMD_TAG_APPEND_SIZE];
+	char *tmp_buff = spp_strbuf_allocate(CMD_RES_BUF_INIT_SIZE);
+	if (unlikely(tmp_buff == NULL)) {
+		RTE_LOG(ERR, SPP_COMMAND_PROC,
+				"allocate error. (name = port_block)\n");
+		return -1;
+	}
+
+	spp_format_port_string(port_str, port->iface_type, port->iface_no);
+	ret = append_json_str_value("port", &tmp_buff, port_str);
+	if (unlikely(ret < 0))
+		return -1;
+
+	ret = append_vlan_block("vlan", &tmp_buff,
+			spp_get_dpdk_port(port->iface_type, port->iface_no),
+			rxtx);
+	if (unlikely(ret < 0))
+		return -1;
+
+	ret = append_json_block_brackets("", output, tmp_buff);
+	spp_strbuf_free(tmp_buff);
+	return ret;
+}
+
+/* append a list of port numbers for JSON format */
+static int
+append_port_array(const char *name, char **output, const int num,
+		const struct spp_port_index *ports,
+		const enum spp_port_rxtx rxtx)
+{
+	int ret = -1;
+	int i = 0;
+	char *tmp_buff = spp_strbuf_allocate(CMD_RES_BUF_INIT_SIZE);
+	if (unlikely(tmp_buff == NULL)) {
+		RTE_LOG(ERR, SPP_COMMAND_PROC,
+				"allocate error. (name = %s)\n",
+				name);
+		return -1;
+	}
+
+	for (i = 0; i < num; i++) {
+		ret = append_port_block(&tmp_buff, &ports[i], rxtx);
+		if (unlikely(ret < 0))
 			return -1;
 	}
 
@@ -495,13 +604,13 @@ append_core_element_value(
 		return ret;
 
 	if (unuse_flg) {
-		ret = apeend_port_array("rx_port", &tmp_buff,
-				num_rx, rx_ports);
+		ret = append_port_array("rx_port", &tmp_buff,
+				num_rx, rx_ports, SPP_PORT_RXTX_RX);
 		if (unlikely(ret < 0))
 			return ret;
 
-		ret = apeend_port_array("tx_port", &tmp_buff,
-				num_tx, tx_ports);
+		ret = append_port_array("tx_port", &tmp_buff,
+				num_tx, tx_ports, SPP_PORT_RXTX_TX);
 		if (unlikely(ret < 0))
 			return ret;
 	}
diff --git a/src/vf/spp_forward.c b/src/vf/spp_forward.c
index c5c0e3c..2aebfd9 100644
--- a/src/vf/spp_forward.c
+++ b/src/vf/spp_forward.c
@@ -1,7 +1,7 @@
 #include <rte_cycles.h>
 
 #include "spp_vf.h"
-#include "ringlatencystats.h"
+#include "spp_port.h"
 #include "spp_forward.h"
 
 #define RTE_LOGTYPE_FORWARD RTE_LOGTYPE_USER1
@@ -117,8 +117,12 @@ static inline void
 change_forward_index(int id)
 {
 	struct forward_info *info = &g_forward_info[id];
-	if (info->ref_index == info->upd_index)
+	if (info->ref_index == info->upd_index) {
+		/* Change reference index of port ability. */
+		spp_port_ability_change_index(PORT_ABILITY_CHG_INDEX_REF, 0, 0);
+
 		info->ref_index = (info->upd_index+1)%SPP_INFO_AREA_MAX;
+	}
 }
 /**
  * Forwarding packets as forwarder or merger
@@ -147,23 +151,13 @@ spp_forward(int id)
 		tx = &path->ports[cnt].tx;
 
 		/* Receive packets */
-		nb_rx = rte_eth_rx_burst(rx->dpdk_port, 0, bufs, MAX_PKT_BURST);
+		nb_rx = spp_eth_rx_burst(rx->dpdk_port, 0, bufs, MAX_PKT_BURST);
 		if (unlikely(nb_rx == 0))
 			continue;
 
-#ifdef SPP_RINGLATENCYSTATS_ENABLE
-		if (rx->iface_type == RING)
-			spp_ringlatencystats_calculate_latency(rx->iface_no,
-					bufs, nb_rx);
-
-		if (tx->iface_type == RING)
-			spp_ringlatencystats_add_time_stamp(tx->iface_no,
-					bufs, nb_rx);
-#endif /* SPP_RINGLATENCYSTATS_ENABLE */
-
 		/* Send packets */
 		if (tx->dpdk_port >= 0)
-			nb_tx = rte_eth_tx_burst(tx->dpdk_port, 0, bufs, nb_rx);
+			nb_tx = spp_eth_tx_burst(tx->dpdk_port, 0, bufs, nb_rx);
 
 		/* Discard remained packets to release mbuf */
 		if (unlikely(nb_tx < nb_rx)) {
diff --git a/src/vf/spp_port.c b/src/vf/spp_port.c
new file mode 100644
index 0000000..a968459
--- /dev/null
+++ b/src/vf/spp_port.c
@@ -0,0 +1,403 @@
+#include <rte_ether.h>
+#include <rte_ip.h>
+#include <rte_udp.h>
+#include <rte_tcp.h>
+#include <rte_net_crc.h>
+
+#include "spp_vf.h"
+#include "spp_port.h"
+#include "ringlatencystats.h"
+
+/* Port ability management information */
+struct port_ability_mng_info {
+	volatile int ref_index; /* Index to reference area */
+	volatile int upd_index; /* Index to update area    */
+	struct spp_port_ability ability[SPP_INFO_AREA_MAX]
+				[SPP_PORT_ABILITY_MAX];
+				/* Port ability information */
+};
+
+/* Port ability port information */
+struct port_ability_port_mng_info {
+	/* Interface type (phy/vhost/ring) */
+	enum port_type iface_type;
+
+	/* Interface number */
+	int            iface_no;
+
+	/* Management data of port ability for receiving */
+	struct port_ability_mng_info rx;
+
+	/* Management data of port ability for sending */
+	struct port_ability_mng_info tx;
+};
+
+/* Information for VLAN tag management. */
+struct port_ability_port_mng_info g_port_mng_info[RTE_MAX_ETHPORTS];
+
+/* TPID of VLAN. */
+static uint16_t g_vlan_tpid;
+
+/* Initialize port ability. */
+void
+spp_port_ability_init(void)
+{
+	int cnt = 0;
+	g_vlan_tpid = rte_cpu_to_be_16(ETHER_TYPE_VLAN);
+	memset(g_port_mng_info, 0x00, sizeof(g_port_mng_info));
+	for (cnt = 0; cnt < RTE_MAX_ETHPORTS; cnt++) {
+		g_port_mng_info[cnt].rx.ref_index = 0;
+		g_port_mng_info[cnt].rx.upd_index = 1;
+		g_port_mng_info[cnt].tx.ref_index = 0;
+		g_port_mng_info[cnt].tx.upd_index = 1;
+	}
+}
+
+/* Get information of port ability. */
+inline void
+spp_port_ability_get_info(
+		int port_id, enum spp_port_rxtx rxtx,
+		struct spp_port_ability **info)
+{
+	struct port_ability_mng_info *mng = NULL;
+
+	switch (rxtx) {
+	case SPP_PORT_RXTX_RX:
+		mng = &g_port_mng_info[port_id].rx;
+		break;
+	case SPP_PORT_RXTX_TX:
+		mng = &g_port_mng_info[port_id].tx;
+		break;
+	default:
+		/* Not used. */
+		break;
+	}
+	*info = mng->ability[mng->ref_index];
+}
+
+/* Calculation and Setting of FCS. */
+static inline void
+set_fcs_packet(struct rte_mbuf *pkt)
+{
+	uint32_t *fcs = NULL;
+	fcs = rte_pktmbuf_mtod_offset(pkt, uint32_t *, pkt->data_len);
+	*fcs = rte_net_crc_calc(rte_pktmbuf_mtod(pkt, void *),
+			pkt->data_len, RTE_NET_CRC32_ETH);
+}
+
+/* Add VLAN tag to packet. */
+static inline int
+add_vlantag_packet(
+		struct rte_mbuf *pkt,
+		const union spp_ability_data *data)
+{
+	struct ether_hdr *old_ether = NULL;
+	struct ether_hdr *new_ether = NULL;
+	struct vlan_hdr  *vlan      = NULL;
+	const struct spp_vlantag_info *vlantag = &data->vlantag;
+
+	old_ether = rte_pktmbuf_mtod(pkt, struct ether_hdr *);
+	if (old_ether->ether_type == g_vlan_tpid) {
+		/* For packets with VLAN tags, only VLAN ID is updated */
+		new_ether = old_ether;
+		vlan = (struct vlan_hdr *)&new_ether[1];
+	} else {
+		/* For packets without VLAN tag, add VLAN tag. */
+		new_ether = (struct ether_hdr *)rte_pktmbuf_prepend(pkt,
+				sizeof(struct vlan_hdr));
+		if (unlikely(new_ether == NULL)) {
+			RTE_LOG(ERR, PORT, "Failed to get additional header area.\n");
+			return -1;
+		}
+
+		rte_memcpy(new_ether, old_ether, sizeof(struct ether_hdr));
+		vlan = (struct vlan_hdr *)&new_ether[1];
+		vlan->eth_proto = new_ether->ether_type;
+		new_ether->ether_type = g_vlan_tpid;
+	}
+
+	vlan->vlan_tci = vlantag->tci;
+	set_fcs_packet(pkt);
+	return 0;
+}
+
+/* Add VLAN tag to all packets. */
+static inline int
+add_vlantag_all_packets(
+		struct rte_mbuf **pkts, int nb_pkts,
+		const union spp_ability_data *data)
+{
+	int ret = 0;
+	int cnt = 0;
+	for (cnt = 0; cnt < nb_pkts; cnt++) {
+		ret = add_vlantag_packet(pkts[cnt], data);
+		if (unlikely(ret < 0)) {
+			RTE_LOG(ERR, PORT,
+					"Failed to add VLAN tag.(pkts %d/%d)\n",
+					cnt, nb_pkts);
+			break;
+		}
+	}
+	return cnt;
+}
+
+/* Delete VLAN tag to packet. */
+static inline int
+del_vlantag_packet(
+		struct rte_mbuf *pkt,
+		const union spp_ability_data *data __attribute__ ((unused)))
+{
+	struct ether_hdr *old_ether = NULL;
+	struct ether_hdr *new_ether = NULL;
+	uint32_t *old, *new;
+
+	old_ether = rte_pktmbuf_mtod(pkt, struct ether_hdr *);
+	if (old_ether->ether_type == g_vlan_tpid) {
+		/* For packets without VLAN tag, delete VLAN tag. */
+		new_ether = (struct ether_hdr *)rte_pktmbuf_adj(pkt,
+				sizeof(struct vlan_hdr));
+		if (unlikely(new_ether == NULL)) {
+			RTE_LOG(ERR, PORT, "Failed to delete unnecessary header area.\n");
+			return -1;
+		}
+
+		old = (uint32_t *)old_ether;
+		new = (uint32_t *)new_ether;
+		new[2] = old[2];
+		new[1] = old[1];
+		new[0] = old[0];
+		old[0] = 0;
+		set_fcs_packet(pkt);
+	}
+	return 0;
+}
+
+/* Delete VLAN tag to all packets. */
+static inline int
+del_vlantag_all_packets(
+		struct rte_mbuf **pkts, int nb_pkts,
+		const union spp_ability_data *data)
+{
+	int ret = 0;
+	int cnt = 0;
+	for (cnt = 0; cnt < nb_pkts; cnt++) {
+		ret = del_vlantag_packet(pkts[cnt], data);
+		if (unlikely(ret < 0)) {
+			RTE_LOG(ERR, PORT,
+					"Failed to del VLAN tag.(pkts %d/%d)\n",
+					cnt, nb_pkts);
+			break;
+		}
+	}
+	return cnt;
+}
+
+/* Change index of management information. */
+void
+spp_port_ability_change_index(
+		enum port_ability_chg_index_type type,
+		int port_id, enum spp_port_rxtx rxtx)
+{
+	int cnt;
+	static int num_rx;
+	static int rx_list[RTE_MAX_ETHPORTS];
+	static int num_tx;
+	static int tx_list[RTE_MAX_ETHPORTS];
+	struct port_ability_mng_info *mng = NULL;
+
+	if (type == PORT_ABILITY_CHG_INDEX_UPD) {
+		switch (rxtx) {
+		case SPP_PORT_RXTX_RX:
+			mng = &g_port_mng_info[port_id].rx;
+			mng->upd_index = mng->ref_index;
+			rx_list[num_rx++] = port_id;
+			break;
+		case SPP_PORT_RXTX_TX:
+			mng = &g_port_mng_info[port_id].tx;
+			mng->upd_index = mng->ref_index;
+			tx_list[num_tx++] = port_id;
+			break;
+		default:
+			/* Not used. */
+			break;
+		}
+		return;
+	}
+
+	for (cnt = 0; cnt < num_rx; cnt++) {
+		mng = &g_port_mng_info[rx_list[cnt]].rx;
+		mng->ref_index = (mng->upd_index+1)%SPP_INFO_AREA_MAX;
+		rx_list[cnt] = 0;
+	}
+	for (cnt = 0; cnt < num_tx; cnt++) {
+		mng = &g_port_mng_info[tx_list[cnt]].tx;
+		mng->ref_index = (mng->upd_index+1)%SPP_INFO_AREA_MAX;
+		tx_list[cnt] = 0;
+	}
+
+	num_rx = 0;
+	num_tx = 0;
+}
+
+/* Set ability data of port ability. */
+static void
+port_ability_set_ability(
+		struct spp_port_info *port,
+		enum spp_port_rxtx rxtx)
+{
+	int in_cnt, out_cnt = 0;
+	int port_id = port->dpdk_port;
+	struct port_ability_port_mng_info *port_mng = &g_port_mng_info[port_id];
+	struct port_ability_mng_info *mng         = NULL;
+	struct spp_port_ability      *in_ability  = port->ability;
+	struct spp_port_ability      *out_ability = NULL;
+	struct spp_vlantag_info      *tag         = NULL;
+
+	port_mng->iface_type = port->iface_type;
+	port_mng->iface_no   = port->iface_no;
+
+	switch (rxtx) {
+	case SPP_PORT_RXTX_RX:
+		mng = &port_mng->rx;
+		break;
+	case SPP_PORT_RXTX_TX:
+		mng = &port_mng->tx;
+		break;
+	default:
+		/* Not used. */
+		break;
+	}
+
+	out_ability = mng->ability[mng->upd_index];
+	memset(out_ability, 0x00, sizeof(struct spp_port_ability)
+			* SPP_PORT_ABILITY_MAX);
+	for (in_cnt = 0; in_cnt < SPP_PORT_ABILITY_MAX; in_cnt++) {
+		if (in_ability[in_cnt].rxtx != rxtx)
+			continue;
+
+		memcpy(&out_ability[out_cnt], &in_ability[in_cnt],
+				sizeof(struct spp_port_ability));
+
+		switch (out_ability[out_cnt].ope) {
+		case SPP_PORT_ABILITY_OPE_ADD_VLANTAG:
+			tag = &out_ability[out_cnt].data.vlantag;
+			tag->tci = rte_cpu_to_be_16(SPP_VLANTAG_CALC_TCI(
+					tag->vid, tag->pcp));
+			break;
+		case SPP_PORT_ABILITY_OPE_DEL_VLANTAG:
+		default:
+			/* Nothing to do. */
+			break;
+		}
+
+		out_cnt++;
+	}
+
+	spp_port_ability_change_index(PORT_ABILITY_CHG_INDEX_UPD,
+			port_id, rxtx);
+}
+
+/* Update port capability. */
+void
+spp_port_ability_update(const struct spp_component_info *component)
+{
+	int cnt;
+	struct spp_port_info *port = NULL;
+	for (cnt = 0; cnt < component->num_rx_port; cnt++) {
+		port = component->rx_ports[cnt];
+		port_ability_set_ability(port, SPP_PORT_RXTX_RX);
+	}
+
+	for (cnt = 0; cnt < component->num_tx_port; cnt++) {
+		port = component->tx_ports[cnt];
+		port_ability_set_ability(port, SPP_PORT_RXTX_TX);
+	}
+}
+
+/* Definition of functions that operate port abilities. */
+typedef int (*port_ability_func)(
+		struct rte_mbuf **pkts, int nb_pkts,
+		const union spp_ability_data *data);
+
+/* List of functions per port ability. */
+port_ability_func port_ability_function_list[] = {
+	NULL,                    /* None */
+	add_vlantag_all_packets, /* Add VLAN tag */
+	del_vlantag_all_packets, /* Del VLAN tag */
+	NULL                     /* Termination */
+};
+
+/* Each packet operation of port capability. */
+static inline int
+port_ability_each_operation(uint16_t port_id,
+		struct rte_mbuf **pkts, const uint16_t nb_pkts,
+		enum spp_port_rxtx rxtx)
+{
+	int cnt, buf;
+	int ok_pkts = nb_pkts;
+	struct spp_port_ability *info = NULL;
+
+	spp_port_ability_get_info(port_id, rxtx, &info);
+	if (unlikely(info[0].ope == SPP_PORT_ABILITY_OPE_NONE))
+		return nb_pkts;
+
+	for (cnt = 0; cnt < SPP_PORT_ABILITY_MAX; cnt++) {
+		if (info[cnt].ope == SPP_PORT_ABILITY_OPE_NONE)
+			break;
+
+		ok_pkts = port_ability_function_list[info[cnt].ope](
+				pkts, ok_pkts, &info->data);
+	}
+
+	/* Discard remained packets to release mbuf. */
+	if (unlikely(ok_pkts < nb_pkts)) {
+		for (buf = ok_pkts; buf < nb_pkts; buf++)
+			rte_pktmbuf_free(pkts[buf]);
+	}
+
+	return ok_pkts;
+}
+
+/* Wrapper function for rte_eth_rx_burst(). */
+inline uint16_t
+spp_eth_rx_burst(
+		uint16_t port_id, uint16_t queue_id  __attribute__ ((unused)),
+		struct rte_mbuf **rx_pkts, const uint16_t nb_pkts)
+{
+	uint16_t nb_rx = 0;
+	nb_rx = rte_eth_rx_burst(port_id, 0, rx_pkts, nb_pkts);
+	if (unlikely(nb_rx == 0))
+		return 0;
+
+#ifdef SPP_RINGLATENCYSTATS_ENABLE
+	if (g_port_mng_info[port_id].iface_type == RING)
+		spp_ringlatencystats_calculate_latency(
+				g_port_mng_info[port_id].iface_no,
+				rx_pkts, nb_pkts);
+#endif /* SPP_RINGLATENCYSTATS_ENABLE */
+
+	return port_ability_each_operation(port_id, rx_pkts, nb_rx,
+			SPP_PORT_RXTX_RX);
+}
+
+/* Wrapper function for rte_eth_tx_burst(). */
+inline uint16_t
+spp_eth_tx_burst(
+		uint16_t port_id, uint16_t queue_id  __attribute__ ((unused)),
+		struct rte_mbuf **tx_pkts, uint16_t nb_pkts)
+{
+	uint16_t nb_tx = 0;
+	nb_tx = port_ability_each_operation(port_id, tx_pkts, nb_pkts,
+			SPP_PORT_RXTX_TX);
+	if (unlikely(nb_tx == 0))
+		return 0;
+
+#ifdef SPP_RINGLATENCYSTATS_ENABLE
+	if (g_port_mng_info[port_id].iface_type == RING)
+		spp_ringlatencystats_add_time_stamp(
+				g_port_mng_info[port_id].iface_no,
+				tx_pkts, nb_pkts);
+#endif /* SPP_RINGLATENCYSTATS_ENABLE */
+
+	return rte_eth_tx_burst(port_id, 0, tx_pkts, nb_tx);
+}
diff --git a/src/vf/spp_port.h b/src/vf/spp_port.h
new file mode 100644
index 0000000..bb1a39a
--- /dev/null
+++ b/src/vf/spp_port.h
@@ -0,0 +1,109 @@
+#ifndef __SPP_PORT_H__
+#define __SPP_PORT_H__
+
+/**
+ * @file
+ * SPP Port ability
+ *
+ * Provide about the ability per port.
+ */
+
+#include "spp_vf.h"
+
+/** Calculate TCI of VLAN tag. */
+#define SPP_VLANTAG_CALC_TCI(id, pcp) (((pcp & 0x07) << 13) | (id & 0x0fff))
+
+/** Type for changing index. */
+enum port_ability_chg_index_type {
+	/** Type for changing index to reference area. */
+	PORT_ABILITY_CHG_INDEX_REF,
+
+	/** Type for changing index to update area. */
+	PORT_ABILITY_CHG_INDEX_UPD,
+};
+
+/** Initialize port ability. */
+void spp_port_ability_init(void);
+
+/**
+ * Get information of port ability.
+ *
+ * @param port_id
+ *  The port identifier of the Ethernet device.
+ * @param rxtx
+ *  rx/tx identifier of port_id.
+ * @param info
+ *  Port ability information.
+ */
+void spp_port_ability_get_info(
+		int port_id, enum spp_port_rxtx rxtx,
+		struct spp_port_ability **info);
+
+/**
+ * Change index of management information.
+ *
+ * @param port_id
+ *  The port identifier of the Ethernet device.
+ * @param rxtx
+ *  rx/tx identifier of port_id.
+ * @param type
+ *  Type for changing index.
+ */
+void spp_port_ability_change_index(
+		enum port_ability_chg_index_type type,
+		int port_id, enum spp_port_rxtx rxtx);
+
+/**
+ * Update port capability.
+ *
+ * @param component_info
+ *  The pointer to struct spp_component_info. at n
+ *  The data for updating the internal data of port ability.
+ */
+void spp_port_ability_update(const struct spp_component_info *component);
+
+/**
+ * Wrapper function for rte_eth_rx_burst().
+ *
+ * @param port_id
+ *  The port identifier of the Ethernet device.
+ * @param queue_id
+ *  The index of the receive queue from which to retrieve input packets.
+ *  SPP is fixed at 0.
+ * @param rx_pkts
+ *  The address of an array of pointers to *rte_mbuf* structures that
+ *  must be large enough to store *nb_pkts* pointers in it.
+ * @param nb_pkts
+ *  The maximum number of packets to retrieve.
+ *
+ * @return
+ *  The number of packets actually retrieved, which is the number
+ *  of pointers to *rte_mbuf* structures effectively supplied to the
+ *  *rx_pkts* array.
+ */
+uint16_t spp_eth_rx_burst(uint16_t port_id, uint16_t queue_id,
+		struct rte_mbuf **rx_pkts, const uint16_t nb_pkts);
+
+/**
+ * Wrapper function for rte_eth_tx_burst().
+ *
+ * @param port_id
+ *  The port identifier of the Ethernet device.
+ * @param queue_id
+ *  The index of the transmit queue through which output packets must be sent.
+ *  SPP is fixed at 0.
+ * @param tx_pkts
+ *  The address of an array of *nb_pkts* pointers to *rte_mbuf* structures
+ *  which contain the output packets.
+ * @param nb_pkts
+ *  The maximum number of packets to transmit.
+ *
+ * @return
+ *  The number of output packets actually stored in transmit descriptors of
+ *  the transmit ring. The return value can be less than the value of the
+ *  *tx_pkts* parameter when the transmit ring is full or has been filled up.
+ */
+uint16_t spp_eth_tx_burst(uint16_t port_id, uint16_t queue_id,
+		struct rte_mbuf **tx_pkts, uint16_t nb_pkts);
+
+#endif /*  __SPP_PORT_H__ */
diff --git a/src/vf/spp_vf.c b/src/vf/spp_vf.c
index 49c56e3..6fa0c22 100644
--- a/src/vf/spp_vf.c
+++ b/src/vf/spp_vf.c
@@ -12,6 +12,7 @@
 #include "classifier_mac.h"
 #include "spp_forward.h"
 #include "command_proc.h"
+#include "spp_port.h"
 
 /* Max number of core status check */
 #define SPP_CORE_STATUS_CHECK_MAX 5
@@ -965,6 +966,7 @@ main(int argc, char *argv[])
 			break;
 
 		spp_forward_init();
+		spp_port_ability_init();
 
 		/* Setup connection for accepting commands from controller */
 		int ret_command_init = spp_command_proc_init(
@@ -1404,12 +1406,14 @@ int
 spp_update_port(enum spp_command_action action,
 		const struct spp_port_index *port,
 		enum spp_port_rxtx rxtx,
-		const char *name)
+		const char *name,
+		const struct spp_port_ability *ability)
 {
 	int ret = SPP_RET_NG;
 	int ret_check = -1;
 	int ret_del = -1;
 	int component_id = 0;
+	int cnt = 0;
 	struct spp_component_info *component = NULL;
 	struct spp_port_info *port_info = NULL;
 	int *num = NULL;
@@ -1443,6 +1447,20 @@ spp_update_port(enum spp_command_action action,
 			break;
 		}
 
+		if (ability->ope != SPP_PORT_ABILITY_OPE_NONE) {
+			while ((cnt < SPP_PORT_ABILITY_MAX) &&
+					(port_info->ability[cnt].ope !=
+					SPP_PORT_ABILITY_OPE_NONE)) {
+				cnt++;
+			}
+			if (cnt >= SPP_PORT_ABILITY_MAX) {
+				RTE_LOG(ERR, APP, "No space of port ability.\n");
+				return SPP_RET_NG;
+			}
+			memcpy(&port_info->ability[cnt], ability,
+					sizeof(struct spp_port_ability));
+		}
+
 		port_info->iface_type = port->iface_type;
 		ports[*num] = port_info;
 		(*num)++;
@@ -1451,9 +1469,20 @@ spp_update_port(enum spp_command_action action,
 		break;
 
 	case SPP_CMD_ACTION_DEL:
+		for (cnt = 0; cnt < SPP_PORT_ABILITY_MAX; cnt++) {
+			if (port_info->ability[cnt].ope ==
+					SPP_PORT_ABILITY_OPE_NONE)
+				continue;
+
+			if (port_info->ability[cnt].rxtx == rxtx)
+				memset(&port_info->ability[cnt], 0x00,
+					sizeof(struct spp_port_ability));
+		}
+
 		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:
@@ -1539,6 +1568,8 @@ flush_component(void)
 			continue;
 
 		component_info = &g_component_info[cnt];
+		spp_port_ability_update(component_info);
+
 		if (component_info->type == SPP_COMPONENT_CLASSIFIER_MAC)
 			ret = spp_classifier_mac_update(component_info);
 		else
@@ -1649,6 +1680,22 @@ spp_iterate_classifier_table(
 	return SPP_RET_OK;
 }
 
+/* Get the port number of DPDK. */
+int
+spp_get_dpdk_port(enum port_type iface_type, int iface_no)
+{
+	switch (iface_type) {
+	case PHY:
+		return g_iface_info.nic[iface_no].dpdk_port;
+	case RING:
+		return g_iface_info.ring[iface_no].dpdk_port;
+	case VHOST:
+		return g_iface_info.vhost[iface_no].dpdk_port;
+	default:
+		return -1;
+	}
+}
+
 /**
  * Separate port id of combination of iface type and number and
  * assign to given argument, iface_type and iface_no.
diff --git a/src/vf/spp_vf.h b/src/vf/spp_vf.h
index 70e105b..539931c 100644
--- a/src/vf/spp_vf.h
+++ b/src/vf/spp_vf.h
@@ -48,6 +48,15 @@
 /** Value for default MAC address of classifier */
 #define SPP_DEFAULT_CLASSIFIED_DMY_ADDR     0x010000000000
 
+/** Maximum number of port abilities available */
+#define SPP_PORT_ABILITY_MAX 4
+
+/** Maximum VLAN ID */
+#define SPP_VLAN_VID_MAX 4096
+
+/** Maximum VLAN PCP */
+#define SPP_VLAN_PCP_MAX 7
+
 /**
  * State on component
  */
@@ -103,6 +112,13 @@ enum spp_command_action {
 	SPP_CMD_ACTION_DEL,   /**< delete */
 };
 
+/** Port ability operation */
+enum spp_port_ability_ope {
+	SPP_PORT_ABILITY_OPE_NONE,        /**< none */
+	SPP_PORT_ABILITY_OPE_ADD_VLANTAG, /**< add VLAN tag */
+	SPP_PORT_ABILITY_OPE_DEL_VLANTAG, /**< delete VLAN tag */
+};
+
 /**
  * Interface information structure
  */
@@ -111,6 +127,26 @@ struct spp_port_index {
 	int             iface_no;   /**< Interface number */
 };
 
+/** VLAN tag information */
+struct spp_vlantag_info {
+	int vid; /**< VLAN ID */
+	int pcp; /**< Priority Code Point */
+	int tci; /**< Tag Control Information */
+};
+
+/** Data for each port ability */
+union spp_ability_data {
+	/** VLAN tag information */
+	struct spp_vlantag_info vlantag;
+};
+
+/** Port ability information */
+struct spp_port_ability {
+	enum spp_port_ability_ope ope; /**< Operation */
+	enum spp_port_rxtx rxtx;       /**< rx/tx identifier */
+	union spp_ability_data data;   /**< Port ability data */
+};
+
 /**
  * Port info
  */
@@ -120,6 +156,8 @@ struct spp_port_info {
 	int            dpdk_port;  /**< DPDK port number */
 	uint64_t       mac_addr;   /**< Mac address for classifying */
 	char           mac_addr_str[SPP_MIN_STR_LEN]; /**< Mac address */
+	struct spp_port_ability ability[SPP_PORT_ABILITY_MAX];
+					/**< Port ability */
 };
 
 /**
@@ -205,7 +243,8 @@ int spp_update_port(
 		enum spp_command_action action,
 		const struct spp_port_index *port,
 		enum spp_port_rxtx rxtx,
-		const char *name);
+		const char *name,
+		const struct spp_port_ability *ability);
 
 /**
  * Flush SPP component
@@ -220,8 +259,8 @@ int spp_flush(void);
  */
 void spp_cancel(void);
 
-/** definition of iterated core element procedure function */
 struct spp_iterate_core_params;
+/** definition of iterated core element procedure function */
 typedef int (*spp_iterate_core_element_proc)(
 		struct spp_iterate_core_params *params,
 		const unsigned int lcore_id,
@@ -253,8 +292,8 @@ struct spp_iterate_core_params {
  */
 int spp_iterate_core_info(struct spp_iterate_core_params *params);
 
-/** definition of iterated classifier element procedure function */
 struct spp_iterate_classifier_table_params;
+/** definition of iterated classifier element procedure function */
 typedef int (*spp_iterate_classifier_element_proc)(
 		struct spp_iterate_classifier_table_params *params,
 		enum spp_classifier_type type,
@@ -421,6 +460,19 @@ int spp_check_used_port(
 int64_t spp_change_mac_str_to_int64(const char *mac);
 
 /**
+ * Get the port number of DPDK.
+ *
+ * @param iface_type
+ *  Interface type obtained from port.
+ * @param iface_no
+ *  Interface number obtained from port.
+ *
+ * @return
+ *  Port id generated by DPDK.
+ */
+int spp_get_dpdk_port(enum port_type iface_type, int iface_no);
+
+/**
  * Extract if-type/if-number from port string
  *
  * @param port
-- 
1.9.1



More information about the spp mailing list