From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: Received: from mogw0827.ocn.ad.jp (mogw0827.ocn.ad.jp [153.149.234.28]) by dpdk.org (Postfix) with ESMTP id 8D9D54CBD for ; Tue, 27 Feb 2018 13:34:49 +0100 (CET) Received: from mf-smf-ucb019c3 (mf-smf-ucb019c3.ocn.ad.jp [153.153.66.132]) by mogw0827.ocn.ad.jp (Postfix) with ESMTP id 004331280245; Tue, 27 Feb 2018 21:34:48 +0900 (JST) Received: from ntt.pod01.mv-mta-ucb024 ([153.149.142.98]) by mf-smf-ucb019c3 with ESMTP id qeSzeXUp5DyE1qeT1e9wXJ; Tue, 27 Feb 2018 21:34:47 +0900 Received: from smtp.ocn.ne.jp ([153.149.227.135]) by ntt.pod01.mv-mta-ucb024 with id Foan1x00A2vuoep01oanD3; Tue, 27 Feb 2018 12:34:47 +0000 Received: from localhost.localdomain (p5157022-ipngn2402marunouchi.tokyo.ocn.ne.jp [180.35.69.22]) by smtp.ocn.ne.jp (Postfix) with ESMTPA; Tue, 27 Feb 2018 21:34:47 +0900 (JST) From: ogawa.yasufumi@lab.ntt.co.jp To: spp@dpdk.org, ferruh.yigit@intel.com, x-fn-spp@sl.ntt-tx.co.jp Cc: Hiroyuki Nakamura , Kentaro Watanabe , Naoki Takada Date: Tue, 27 Feb 2018 21:34:25 +0900 Message-Id: <1519734869-21582-6-git-send-email-ogawa.yasufumi@lab.ntt.co.jp> X-Mailer: git-send-email 2.7.4 In-Reply-To: <1519734869-21582-1-git-send-email-ogawa.yasufumi@lab.ntt.co.jp> References: <201802080551.w185pkLL010335@imss03.silk.ntt-tx.co.jp> <1519734869-21582-1-git-send-email-ogawa.yasufumi@lab.ntt.co.jp> Subject: [spp] [PATCH v2 5/9] spp_vf: add VLAN tag operate function to port X-BeenThere: spp@dpdk.org X-Mailman-Version: 2.1.15 Precedence: list List-Id: Soft Patch Panel List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , X-List-Received-Date: Tue, 27 Feb 2018 12:34:50 -0000 From: Hiroyuki Nakamura * 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 Signed-off-by: Naoki Takada --- 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 #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 #include +#include #include #include @@ -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 #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 #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 +#include +#include +#include +#include + +#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.@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