[spp] [PATCH v2 5/9] spp_vf: add VLAN tag operate function to port
ogawa.yasufumi at lab.ntt.co.jp
ogawa.yasufumi at lab.ntt.co.jp
Tue Feb 27 13:34:25 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 | 436 ++++++++++++++++++++++++++++++++++++++++++++++++
src/vf/spp_port.h | 141 ++++++++++++++++
src/vf/spp_vf.c | 49 +++++-
src/vf/spp_vf.h | 58 ++++++-
10 files changed, 941 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 4a34ac0..f1a1325 100644
--- a/src/vf/Makefile
+++ b/src/vf/Makefile
@@ -41,7 +41,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 7bb7c70..57262a9 100644
--- a/src/vf/classifier_mac.c
+++ b/src/vf/classifier_mac.c
@@ -53,7 +53,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
@@ -367,16 +367,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 */
@@ -523,6 +515,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 +
@@ -652,18 +646,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 23e818e..374a105 100644
--- a/src/vf/command_dec.c
+++ b/src/vf/command_dec.c
@@ -35,6 +35,7 @@
#include <unistd.h>
#include <string.h>
+#include <rte_ether.h>
#include <rte_log.h>
#include <rte_branch_prediction.h>
@@ -80,6 +81,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,
@@ -136,6 +149,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(
@@ -386,6 +420,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)
@@ -600,6 +687,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 */
@@ -652,7 +754,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 a6130bc..f919b16 100644
--- a/src/vf/command_dec.h
+++ b/src/vf/command_dec.h
@@ -106,25 +106,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 76fb3ec..a00181b 100644
--- a/src/vf/command_proc.c
+++ b/src/vf/command_proc.c
@@ -39,6 +39,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"
@@ -89,6 +90,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)
@@ -245,7 +258,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:
@@ -456,15 +470,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
-apeend_port_array(const char *name, char **output,
- const int num, const struct spp_port_index *ports)
+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
+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,
@@ -473,15 +507,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;
}
@@ -529,13 +638,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 1ada73e..bad965e 100644
--- a/src/vf/spp_forward.c
+++ b/src/vf/spp_forward.c
@@ -35,7 +35,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
@@ -151,8 +151,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
@@ -181,23 +185,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..3c6a87c
--- /dev/null
+++ b/src/vf/spp_port.c
@@ -0,0 +1,436 @@
+/*-
+ * BSD LICENSE
+ *
+ * Copyright(c) 2015-2016 Intel Corporation. All rights reserved.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in
+ * the documentation and/or other materials provided with the
+ * distribution.
+ * * Neither the name of Intel Corporation nor the names of its
+ * contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#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..85ba5f3
--- /dev/null
+++ b/src/vf/spp_port.h
@@ -0,0 +1,141 @@
+/*-
+ * BSD LICENSE
+ *
+ * Copyright(c) 2015-2016 Intel Corporation. All rights reserved.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in
+ * the documentation and/or other materials provided with the
+ * distribution.
+ * * Neither the name of Intel Corporation nor the names of its
+ * contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+#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 6d69e3d..4463d41 100644
--- a/src/vf/spp_vf.c
+++ b/src/vf/spp_vf.c
@@ -46,6 +46,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
@@ -999,6 +1000,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(
@@ -1438,12 +1440,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;
@@ -1477,6 +1481,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)++;
@@ -1485,9 +1503,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:
@@ -1573,6 +1602,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
@@ -1683,6 +1714,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 10742bc..e51cd1a 100644
--- a/src/vf/spp_vf.h
+++ b/src/vf/spp_vf.h
@@ -82,6 +82,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
*/
@@ -137,6 +146,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
*/
@@ -145,6 +161,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
*/
@@ -154,6 +190,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 */
};
/**
@@ -239,7 +277,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
@@ -254,8 +293,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,
@@ -287,8 +326,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,
@@ -455,6 +494,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
--
2.7.4
More information about the spp
mailing list