From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: Received: from tama50.ecl.ntt.co.jp (tama50.ecl.ntt.co.jp [129.60.39.147]) by dpdk.org (Postfix) with ESMTP id DE7051DBF for ; Thu, 28 Dec 2017 09:51:20 +0100 (CET) Received: from vc1.ecl.ntt.co.jp (vc1.ecl.ntt.co.jp [129.60.86.153]) by tama50.ecl.ntt.co.jp (8.13.8/8.13.8) with ESMTP id vBS8pJUP004268; Thu, 28 Dec 2017 17:51:19 +0900 Received: from vc1.ecl.ntt.co.jp (localhost [127.0.0.1]) by vc1.ecl.ntt.co.jp (Postfix) with ESMTP id 300B160296; Thu, 28 Dec 2017 17:51:19 +0900 (JST) Received: from jcms-pop21.ecl.ntt.co.jp (jcms-pop21.ecl.ntt.co.jp [129.60.87.134]) by vc1.ecl.ntt.co.jp (Postfix) with ESMTP id 234D260295; Thu, 28 Dec 2017 17:51:19 +0900 (JST) Received: from [IPv6:::1] (watercress.nslab.ecl.ntt.co.jp [129.60.13.73]) by jcms-pop21.ecl.ntt.co.jp (Postfix) with ESMTPSA id 1D583400BDD; Thu, 28 Dec 2017 17:51:19 +0900 (JST) References: <4aae78ff-3b6c-cdfe-a8b7-24ec08b73935@lab.ntt.co.jp> <201712280456.vBS4u4w6010902@imss03.silk.ntt-tx.co.jp> From: Yasufumi Ogawa Message-ID: <94b0a08e-3d1a-db01-8188-91236d23596a@lab.ntt.co.jp> Date: Thu, 28 Dec 2017 17:49:59 +0900 User-Agent: Mozilla/5.0 (Windows NT 6.1; WOW64; rv:52.0) Gecko/20100101 Thunderbird/52.4.0 MIME-Version: 1.0 In-Reply-To: <201712280456.vBS4u4w6010902@imss03.silk.ntt-tx.co.jp> Content-Type: text/plain; charset=utf-8; format=flowed Content-Language: en-US Content-Transfer-Encoding: 8bit To: x-fn-spp@sl.ntt-tx.co.jp, spp@dpdk.org X-TM-AS-MML: disable Subject: Re: [spp] [PATCH 01/57] spp_vf: add vf functions 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: Thu, 28 Dec 2017 08:51:22 -0000 Hi Hiroyuki, Thank you for your contribution! I would like to review your patches for merging. Thanks, Yasufumi On 2017/12/28 13:55, x-fn-spp@sl.ntt-tx.co.jp wrote: > From: Hiroyuki Nakamura > > Hi everyone, > > This the first patch of series for spp_vf. Some of them might not comply > with coding style for whitespace or indenting and I would like to send > patches to fix it later. > > I also would like to send another series of patches for documentation after > you accept first series. > > Thanks, > > * Classifier by MAC address > * Forwarder > * Merger > > Signed-off-by: Tomoyuki Mizuguchi > Signed-off-by: Yasufum Ogawa > --- > src/Makefile | 1 + > src/vf/Makefile | 56 ++++ > src/vf/classifier_mac.c | 233 ++++++++++++++ > src/vf/classifier_mac.h | 12 + > src/vf/ringlatencystats.c | 147 +++++++++ > src/vf/ringlatencystats.h | 69 ++++ > src/vf/spp_config.c | 669 ++++++++++++++++++++++++++++++++++++++ > src/vf/spp_config.h | 90 ++++++ > src/vf/spp_forward.c | 106 +++++++ > src/vf/spp_forward.h | 9 + > src/vf/spp_vf.c | 794 ++++++++++++++++++++++++++++++++++++++++++++++ > src/vf/spp_vf.h | 40 +++ > 12 files changed, 2226 insertions(+) > create mode 100644 src/vf/Makefile > create mode 100644 src/vf/classifier_mac.c > create mode 100644 src/vf/classifier_mac.h > create mode 100644 src/vf/ringlatencystats.c > create mode 100644 src/vf/ringlatencystats.h > create mode 100644 src/vf/spp_config.c > create mode 100644 src/vf/spp_config.h > create mode 100644 src/vf/spp_forward.c > create mode 100644 src/vf/spp_forward.h > create mode 100644 src/vf/spp_vf.c > create mode 100644 src/vf/spp_vf.h > > diff --git a/src/Makefile b/src/Makefile > index 6fd24b8..d2eb9b6 100644 > --- a/src/Makefile > +++ b/src/Makefile > @@ -41,5 +41,6 @@ include $(RTE_SDK)/mk/rte.vars.mk > DIRS-$(CONFIG_RTE_EXEC_ENV_LINUXAPP) += nfv > DIRS-$(CONFIG_RTE_EXEC_ENV_LINUXAPP) += primary > DIRS-$(CONFIG_RTE_EXEC_ENV_LINUXAPP) += vm > +DIRS-$(CONFIG_RTE_EXEC_ENV_LINUXAPP) += vf > > include $(RTE_SDK)/mk/rte.extsubdir.mk > diff --git a/src/vf/Makefile b/src/vf/Makefile > new file mode 100644 > index 0000000..4961d2e > --- /dev/null > +++ b/src/vf/Makefile > @@ -0,0 +1,56 @@ > +# 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. > + > +ifeq ($(RTE_SDK),) > +$(error "Please define RTE_SDK environment variable") > +endif > + > +# Default target, can be overriden by command line or environment > +include $(RTE_SDK)/mk/rte.vars.mk > + > +# binary name > +APP = spp_vf > + > +# all source are stored in SRCS-y > +SRCS-y := spp_vf.c spp_config.c classifier_mac.c spp_forward.c ringlatencystats.c ../shared/common.c > + > +CFLAGS += $(WERROR_FLAGS) -O3 > +CFLAGS += -I$(SRCDIR)/../shared > +#CFLAGS += -DSPP_DEMONIZE > +#CFLAGS += -DSPP_RINGLATENCYSTATS_ENABLE > + > +LDLIBS += -ljansson > +ifeq ($(CONFIG_RTE_BUILD_SHARED_LIB),y) > +LDLIBS += -lrte_pmd_ring > +LDLIBS += -lrte_pmd_vhost > +endif > + > +include $(RTE_SDK)/mk/rte.extapp.mk > diff --git a/src/vf/classifier_mac.c b/src/vf/classifier_mac.c > new file mode 100644 > index 0000000..da03905 > --- /dev/null > +++ b/src/vf/classifier_mac.c > @@ -0,0 +1,233 @@ > +#include > +#include > +#include > +#include > +#include > +#include > + > +#include > +#include > +#include > +#include > +#include > +#include > +#include > +#include > +#include > +#include > +#include > + > +#include "spp_vf.h" > +#include "ringlatencystats.h" > +#include "classifier_mac.h" > + > +#define RTE_LOGTYPE_SPP_CLASSIFIER_MAC RTE_LOGTYPE_USER1 > + > +#ifdef RTE_MACHINE_CPUFLAG_SSE4_2 > +#include > +#define DEFAULT_HASH_FUNC rte_hash_crc > +#else > +#include > +#define DEFAULT_HASH_FUNC rte_jhash > +#endif > + > +/* number of classifier mac table entry */ > +#define NUM_CLASSIFIER_MAC_TABLE_ENTRY 128 > + > +/* interval that transmit burst packet, if buffer is not filled. > + nano second */ > +#define DRAIN_TX_PACKET_INTERVAL 100 > + > +/* mac address string(xx:xx:xx:xx:xx:xx) buffer size */ > +static const size_t ETHER_ADDR_STR_BUF_SZ = > + ETHER_ADDR_LEN * 2 + (ETHER_ADDR_LEN - 1) + 1; > + > +/* classified data (destination port, target packets, etc) */ > +struct classified_data { > + int if_no; > + uint8_t tx_port; > + uint16_t num_pkt; > + struct rte_mbuf *pkts[MAX_PKT_BURST]; > +}; > + > +/* initialize classifier. */ > +static int > +init_classifier(const struct spp_core_info *core_info, > + struct rte_hash **classifier_mac_table, struct classified_data *classified_data) > +{ > + int ret = -1; > + int i; > + struct ether_addr eth_addr; > + char mac_addr_str[ETHER_ADDR_STR_BUF_SZ]; > + > + /* set hash creating parameters */ > + struct rte_hash_parameters hash_params = { > + .name = "classifier_mac_table", > + .entries = NUM_CLASSIFIER_MAC_TABLE_ENTRY, > + .key_len = sizeof(struct ether_addr), > + .hash_func = DEFAULT_HASH_FUNC, > + .hash_func_init_val = 0, > + .socket_id = rte_socket_id(), > + }; > + > +#ifdef RTE_MACHINE_CPUFLAG_SSE4_2 > + RTE_LOG(DEBUG, SPP_CLASSIFIER_MAC, "Enabled SSE4.2. use crc hash.\n"); > +#else > + RTE_LOG(DEBUG, SPP_CLASSIFIER_MAC, "Disabled SSE4.2. use jenkins hash.\n"); > +#endif > + > + /* create classifier mac table (hash table) */ > + *classifier_mac_table = rte_hash_create(&hash_params); > + if (unlikely(*classifier_mac_table == NULL)) { > + RTE_LOG(ERR, SPP_CLASSIFIER_MAC, "Cannot create classifier mac table\n"); > + return -1; > + } > + > + /* populate the hash */ > + for (i = 0; i < core_info->num_tx_port; i++) { > + rte_memcpy(ð_addr, &core_info->tx_ports[i].mac_addr, ETHER_ADDR_LEN); > + > + /* add entry to classifier mac table */ > + ret = rte_hash_add_key_data(*classifier_mac_table, (void*)ð_addr, (void*)(long)i); > + if (unlikely(ret < 0)) { > + ether_format_addr(mac_addr_str, sizeof(mac_addr_str), ð_addr); > + RTE_LOG(ERR, SPP_CLASSIFIER_MAC, > + "Cannot add entry to classifier mac table. " > + "ret=%d, mac_addr=%s\n", ret, mac_addr_str); > + rte_hash_free(*classifier_mac_table); > + *classifier_mac_table = NULL; > + return -1; > + } > + > + /* set value */ > + classified_data[i].if_no = i; > + classified_data[i].tx_port = core_info->tx_ports[i].dpdk_port; > + classified_data[i].num_pkt = 0; > + } > + > + return 0; > +} > + > +/* transimit packet to one destination. */ > +static inline void > +transimit_packet(struct classified_data *classified_data) > +{ > + int i; > + uint16_t n_tx; > + > + /* set ringlatencystats */ > + spp_ringlatencystats_add_time_stamp(classified_data->if_no, > + classified_data->pkts, classified_data->num_pkt); > + > + /* transimit packets */ > + n_tx = rte_eth_tx_burst(classified_data->tx_port, 0, > + classified_data->pkts, classified_data->num_pkt); > + > + /* free cannnot transiit packets */ > + if (unlikely(n_tx != classified_data->num_pkt)) { > + for (i = n_tx; i < classified_data->num_pkt; i++) > + rte_pktmbuf_free(classified_data->pkts[i]); > + RTE_LOG(DEBUG, SPP_CLASSIFIER_MAC, > + "drop packets(tx). num=%hu, dpdk_port=%hhu\n", > + classified_data->num_pkt - n_tx, classified_data->tx_port); > + } > + > + classified_data->num_pkt = 0; > +} > + > +/* classify packet by destination mac address, > + and transimit packet (conditional). */ > +static inline void > +classify_packet(struct rte_mbuf **rx_pkts, uint16_t n_rx, > + struct rte_hash *classifier_mac_table, struct classified_data *classified_data) > +{ > + int ret; > + int i; > + struct ether_hdr *eth; > + struct classified_data *cd; > + void *lookup_data; > + char mac_addr_str[ETHER_ADDR_STR_BUF_SZ]; > + > + for (i = 0; i < n_rx; i++) { > + eth = rte_pktmbuf_mtod(rx_pkts[i], struct ether_hdr *); > + > + /* find in table (by destination mac address)*/ > + ret = rte_hash_lookup_data(classifier_mac_table, > + (const void*)ð->d_addr, &lookup_data); > + if (unlikely(ret < 0)) { > + ether_format_addr(mac_addr_str, sizeof(mac_addr_str), ð->d_addr); > + RTE_LOG(ERR, SPP_CLASSIFIER_MAC, > + "unknown mac address. ret=%d, mac_addr=%s\n", ret, mac_addr_str); > + rte_pktmbuf_free(rx_pkts[i]); > + continue; > + } > + > + /* set mbuf pointer to tx buffer */ > + cd = classified_data + (long)lookup_data; > + cd->pkts[cd->num_pkt++] = rx_pkts[i]; > + > + /* transimit packet, if buffer is filled */ > + if (unlikely(cd->num_pkt == MAX_PKT_BURST)) > + transimit_packet(cd); > + } > +} > + > +/* classifier(mac address) thread function. */ > +int > +spp_classifier_mac_do(void *arg) > +{ > + int ret = -1; > + int i; > + int n_rx; > + struct spp_core_info *core_info = (struct spp_core_info *)arg; > + struct rte_mbuf *rx_pkts[MAX_PKT_BURST]; > + > + struct rte_hash *classifier_mac_table = NULL; > + const int n_classified_data = core_info->num_tx_port; > + struct classified_data classified_data[n_classified_data]; > + > + uint64_t cur_tsc, prev_tsc = 0; > + const uint64_t drain_tsc = (rte_get_tsc_hz() + US_PER_S - 1) / > + US_PER_S * DRAIN_TX_PACKET_INTERVAL; > + > + /* initialize */ > + ret = init_classifier(core_info, &classifier_mac_table, classified_data); > + if (unlikely(ret != 0)) > + return ret; > + > + /* to idle */ > + core_info->status = SPP_CORE_IDLE; > + while(likely(core_info->status == SPP_CORE_IDLE) || > + likely(core_info->status == SPP_CORE_FORWARD)) { > + > + while(likely(core_info->status == SPP_CORE_FORWARD)) { > + /* drain tx packets, if buffer is not filled for interval */ > + cur_tsc = rte_rdtsc(); > + if (unlikely(cur_tsc - prev_tsc > drain_tsc)) { > + for (i = 0; i < n_classified_data; i++) { > + if (unlikely(classified_data[i].num_pkt != 0)) > + transimit_packet(&classified_data[i]); > + } > + prev_tsc = cur_tsc; > + } > + > + /* retrieve packets */ > + n_rx = rte_eth_rx_burst(core_info->rx_ports[0].dpdk_port, 0, > + rx_pkts, MAX_PKT_BURST); > + if (unlikely(n_rx == 0)) > + continue; > + > + /* classify and transimit (filled) */ > + classify_packet(rx_pkts, n_rx, classifier_mac_table, classified_data); > + } > + } > + > + /* uninitialize */ > + if (classifier_mac_table != NULL) { > + rte_hash_free(classifier_mac_table); > + classifier_mac_table = NULL; > + } > + core_info->status = SPP_CORE_STOP; > + > + return 0; > +} > diff --git a/src/vf/classifier_mac.h b/src/vf/classifier_mac.h > new file mode 100644 > index 0000000..2661206 > --- /dev/null > +++ b/src/vf/classifier_mac.h > @@ -0,0 +1,12 @@ > +#ifndef _CLASSIFIER_MAC_H_ > +#define _CLASSIFIER_MAC_H_ > + > +/** > + * classifier(mac address) thread function. > + * > + * @param arg > + * pointer to struct spp_core_info. > + */ > +int spp_classifier_mac_do(void *arg); > + > +#endif /* _CLASSIFIER_MAC_H_ */ > diff --git a/src/vf/ringlatencystats.c b/src/vf/ringlatencystats.c > new file mode 100644 > index 0000000..8f44020 > --- /dev/null > +++ b/src/vf/ringlatencystats.c > @@ -0,0 +1,147 @@ > +#include > +#include > +#include > +#include > +#include > + > +#include > +#include > +#include > +#include > +#include > + > +#include "ringlatencystats.h" > + > +#define NS_PER_SEC 1E9 > + > +#define RTE_LOGTYPE_SPP_RING_LATENCY_STATS RTE_LOGTYPE_USER1 > + > +#ifdef SPP_RINGLATENCYSTATS_ENABLE > + > +/** ring latency statistics information */ > +struct ring_latency_stats_info { > + uint64_t timer_tsc; /**< sampling interval counter */ > + uint64_t prev_tsc; /**< previous time */ > + struct spp_ringlatencystats_ring_latency_stats stats; /**< ring latency statistics list */ > +}; > + > +/** sampling interval */ > +static uint64_t g_samp_intvl = 0; > + > +/** ring latency statistics information instance */ > +static struct ring_latency_stats_info *g_stats_info = NULL; > + > +/** number of ring latency statisics */ > +static uint16_t g_stats_count = 0; > + > +/* clock cycles per nano second */ > +static inline uint64_t > +cycles_per_ns(void) > +{ > + return rte_get_timer_hz() / NS_PER_SEC; > +} > + > +int > +spp_ringlatencystats_init(uint64_t samp_intvl, uint16_t stats_count) > +{ > + /* allocate memory for ring latency statisics infromation */ > + g_stats_info = rte_zmalloc( > + "global ring_latency_stats_info", > + sizeof(struct ring_latency_stats_info) * stats_count, 0); > + if (unlikely(g_stats_info == NULL)) { > + RTE_LOG(ERR, SPP_RING_LATENCY_STATS, > + "Cannot allocate memory for ring latency stats info\n"); > + return -1; > + } > + > + /* store global information for ring latency statistics */ > + g_samp_intvl = samp_intvl * cycles_per_ns(); > + g_stats_count = stats_count; > + > + RTE_LOG(DEBUG, SPP_RING_LATENCY_STATS, > + "g_samp_intvl=%lu, g_stats_count=%hu, cpns=%lu\n", > + g_samp_intvl, g_stats_count, cycles_per_ns()); > + > + return 0; > +} > + > +void > +spp_ringlatencystats_uninit(void) > +{ > + /* free memory for ring latency statisics infromation */ > + if (likely(g_stats_info != NULL)) { > + rte_free(g_stats_info); > + g_stats_count = 0; > + } > +} > + > +void > +spp_ringlatencystats_add_time_stamp(int ring_id, > + struct rte_mbuf **pkts, uint16_t nb_pkts) > +{ > + unsigned int i; > + uint64_t diff_tsc, now; > + struct ring_latency_stats_info *stats_info = &g_stats_info[ring_id]; > + > + for (i = 0; i < nb_pkts; i++) { > + > + /* get tsc now */ > + now = rte_rdtsc(); > + > + /* calculate difference from the previous processing time */ > + diff_tsc = now - stats_info->prev_tsc; > + stats_info->timer_tsc += diff_tsc; > + > + /* when it is over sampling interval */ > + /* set tsc to mbuf::timestamp */ > + if (unlikely(stats_info->timer_tsc >= g_samp_intvl)) { > + pkts[i]->timestamp = now; > + stats_info->timer_tsc = 0; > + } > + > + /* update previus tsc */ > + stats_info->prev_tsc = now; > + } > +} > + > +void > +spp_ringlatencystats_calculate_latency(int ring_id, > + struct rte_mbuf **pkts, uint16_t nb_pkts) > +{ > + unsigned int i; > + uint64_t now; > + int64_t latency; > + struct ring_latency_stats_info *stats_info = &g_stats_info[ring_id]; > + > + now = rte_rdtsc(); > + for (i = 0; i < nb_pkts; i++) { > + if (likely(pkts[i]->timestamp == 0)) > + continue; > + > + /* when mbuf::timestamp is not zero */ > + /* calculate latency */ > + latency = (uint64_t)floor((now - pkts[i]->timestamp) / cycles_per_ns()); > + if (likely(latency < SPP_RINGLATENCYSTATS_STATS_SLOT_COUNT-1)) > + stats_info->stats.slot[latency]++; > + else > + stats_info->stats.slot[SPP_RINGLATENCYSTATS_STATS_SLOT_COUNT-1]++; > + } > +} > + > +int > +spp_ringlatencystats_get_count(void) > +{ > + return g_stats_count; > +} > + > +void > +spp_ringlatencystats_get_stats(int ring_id, > + struct spp_ringlatencystats_ring_latency_stats *stats) > +{ > + struct ring_latency_stats_info *stats_info = &g_stats_info[ring_id]; > + > + rte_memcpy(stats, &stats_info->stats, > + sizeof(struct spp_ringlatencystats_ring_latency_stats)); > +} > + > +#endif /* SPP_RINGLATENCYSTATS_ENABLE */ > diff --git a/src/vf/ringlatencystats.h b/src/vf/ringlatencystats.h > new file mode 100644 > index 0000000..bc47699 > --- /dev/null > +++ b/src/vf/ringlatencystats.h > @@ -0,0 +1,69 @@ > +#ifndef _RINGLATENCYSTATS_H_ > +#define _RINGLATENCYSTATS_H_ > + > +#include > + > +/** number of slots to save latency. 0ns~99ns and 100ns over */ > +#define SPP_RINGLATENCYSTATS_STATS_SLOT_COUNT 101 > + > +/** ring latency statistics */ > +struct spp_ringlatencystats_ring_latency_stats { > + uint64_t slot[SPP_RINGLATENCYSTATS_STATS_SLOT_COUNT]; /**< slots to save latency */ > +}; > + > + > +#ifdef SPP_RINGLATENCYSTATS_ENABLE > +/** > + * initialize ring latency statisics. > + * > + * @retval 0: succeeded. > + * @retval -1: failed. > + */ > +int spp_ringlatencystats_init(uint64_t samp_intvl, uint16_t stats_count); > + > +/** > + *uninitialize ring latency statisics. > + */ > +void spp_ringlatencystats_uninit(void); > + > +/** > + * add time-stamp to mbuf's member. > + * > + * call at enqueue. > + */ > +void spp_ringlatencystats_add_time_stamp(int ring_id, > + struct rte_mbuf **pkts, uint16_t nb_pkts); > + > +/** > + * calculate latency. > + * > + * call at dequeue. > + */ > +void spp_ringlatencystats_calculate_latency(int ring_id, > + struct rte_mbuf **pkts, uint16_t nb_pkts); > + > +/** > + * get number of ring latency statisics. > + * > + * @return spp_ringlatencystats_init's parameter "stats_count" > + */ > +int spp_ringlatencystats_get_count(void); > + > +/** > + *get specific ring latency statisics. > + */ > +void spp_ringlatencystats_get_stats(int ring_id, > + struct spp_ringlatencystats_ring_latency_stats *stats); > + > +#else > + > +#define spp_ringlatencystats_init(arg1, arg2) 0 > +#define spp_ringlatencystats_uninit() > +#define spp_ringlatencystats_add_time_stamp(arg1, arg2, arg3) > +#define spp_ringlatencystats_calculate_latency(arg1, arg2, arg3) > +#define spp_ringlatencystats_get_count() 0 > +#define spp_ringlatencystats_get_stats(arg1, arg2) > + > +#endif /* SPP_RINGLATENCYSTATS_ENABLE */ > + > +#endif /* _RINGLATENCYSTATS_H_ */ > diff --git a/src/vf/spp_config.c b/src/vf/spp_config.c > new file mode 100644 > index 0000000..63b85f2 > --- /dev/null > +++ b/src/vf/spp_config.c > @@ -0,0 +1,669 @@ > +#include > +#include > + > +#include > + > +#include "spp_config.h" > + > +#define CONFIG_CORE_TYPE_CLASSIFIER_MAC "classifier_mac" > +#define CONFIG_CORE_TYPE_MERGE "merge" > +#define CONFIG_CORE_TYPE_FORWARD "forward" > + > +#define JSONPATH_CLASSIFIER_TABLE "$.classifier_table" > +#define JSONPATH_PROC_TABLE "$.vfs" > +#define JSONPATH_NAME "$.name" > +#define JSONPATH_TABLE "$.table" > +#define JSONPATH_MAC "$.mac" > +#define JSONPATH_PORT "$.port" > +#define JSONPATH_NUM_VHOST "$.num_vhost" > +#define JSONPATH_NUM_RING "$.num_ring" > +#define JSONPATH_FUNCTIONS "$.functions" > +#define JSONPATH_CORE_NO "$.core" > +#define JSONPATH_CORE_TYPE "$.type" > +#define JSONPATH_RX_PORT "$.rx_port" > +#define JSONPATH_TX_PORT "$.tx_port" > +#define JSONPATH_TX_TABLE "$.tx_port_table" > + > +/* > + * Get integer data from config > + */ > +static int > +config_get_int_value(const json_t *obj, const char *path, int *value) > +{ > + /* 指定パラメータのJsonオブジェクト取得 */ > + json_t *tmp_obj = json_path_get(obj, path); > + if (unlikely(tmp_obj == NULL)) { > + /* 必須でないデータを取得する場合を考慮し、DEBUGログとする。 */ > + RTE_LOG(DEBUG, APP, "No parameter. (path = %s)\n", path); > + return -1; > + } > + > + /* Integer type check */ > + if (unlikely(!json_is_integer(tmp_obj))) { > + /* 必須でないデータを取得する場合を考慮し、DEBUGログとする。 */ > + RTE_LOG(DEBUG, APP, "Not an integer. (path = %s)\n", path); > + return -1; > + } > + > + /* Set to OUT parameter */ > + *value = json_integer_value(tmp_obj); > + RTE_LOG(DEBUG, APP, "get value = %d\n", *value); > + return 0; > +} > + > +/* > + * Get String data from config > + */ > +static int > +config_get_str_value(const json_t *obj, const char *path, char *value) > +{ > + /* 指定パラメータのJsonオブジェクト取得 */ > + json_t *tmp_obj = json_path_get(obj, path); > + if (unlikely(tmp_obj == NULL)) { > + RTE_LOG(DEBUG, APP, "No parameter. (path = %s)\n", path); > + return -1; > + } > + > + /* String type check */ > + if (unlikely(!json_is_string(tmp_obj))) { > + RTE_LOG(DEBUG, APP, "Not a string. (path = %s)\n", path); > + return -1; > + } > + > + /* Set to OUT parameter */ > + strcpy(value, json_string_value(tmp_obj)); > + RTE_LOG(DEBUG, APP, "get value = %s\n", value); > + return 0; > +} > + > +/* > + * コンフィグ情報初期化 > + */ > +static void > +config_init_data(struct spp_config_area *config) > +{ > + /* 0クリア */ > + memset(config, 0x00, sizeof(struct spp_config_area)); > + int core_cnt, port_cnt, table_cnt; > + > + /* IF種別初期設定 */ > + for (core_cnt = 0; core_cnt < SPP_CONFIG_CORE_MAX; core_cnt++) { > + for (port_cnt = 0; port_cnt < RTE_MAX_ETHPORTS; port_cnt++) { > + config->proc.functions[core_cnt].rx_ports[port_cnt].if_type = UNDEF; > + config->proc.functions[core_cnt].tx_ports[port_cnt].if_type = UNDEF; > + } > + } > + for (table_cnt = 0; table_cnt < SPP_CONFIG_MAC_TABLE_MAX; table_cnt++) { > + config->classifier_table.mac_tables[table_cnt].port.if_type = UNDEF; > + } > + > + return; > +} > + > +/* > + * IFの情報からIF種別とIF番号を取得する > + * ("ring0" -> 種別:"ring"、番号:0) > + */ > +static int > +config_get_if_info(const char *port, enum port_type *if_type, int *if_no) > +{ > + enum port_type type = UNDEF; > + const char *no_str = NULL; > + char *endptr = NULL; > + > + /* IF type check */ > + if (strncmp(port, SPP_CONFIG_IFTYPE_NIC, strlen(SPP_CONFIG_IFTYPE_NIC)) == 0) { > + /* NIC */ > + type = PHY; > + no_str = &port[strlen(SPP_CONFIG_IFTYPE_NIC)]; > + } else if (strncmp(port, SPP_CONFIG_IFTYPE_VHOST, strlen(SPP_CONFIG_IFTYPE_VHOST)) == 0) { > + /* VHOST */ > + type = VHOST; > + no_str = &port[strlen(SPP_CONFIG_IFTYPE_VHOST)]; > + } else if (strncmp(port, SPP_CONFIG_IFTYPE_RING, strlen(SPP_CONFIG_IFTYPE_RING)) == 0) { > + /* RING */ > + type = RING; > + no_str = &port[strlen(SPP_CONFIG_IFTYPE_RING)]; > + } else { > + /* OTHER */ > + RTE_LOG(ERR, APP, "Unknown interface type. (port = %s)\n", port); > + return -1; > + } > + > + /* IF番号を文字列から数値変換 */ > + int ret_no = strtol(no_str, &endptr, 0); > + if (unlikely(no_str == endptr) || unlikely(*endptr != '\0')) { > + /* No IF number */ > + RTE_LOG(ERR, APP, "No interface number. (port = %s)\n", port); > + return -1; > + } > + > + /* Set OUT parameter */ > + *if_type = type; > + *if_no = ret_no; > + > + RTE_LOG(DEBUG, APP, "Port = %s => Type = %d No = %d\n", > + port, *if_type, *if_no); > + return 0; > +} > + > +/* > + * MAC addressを文字列から数値へ変換 > + */ > +int64_t > +config_change_mac_str_to_int64(const char *mac) > +{ > + int64_t ret_mac = 0; > + int64_t token_val = 0; > + int token_cnt = 0; > + char tmp_mac[SPP_CONFIG_STR_LEN]; > + char *str = tmp_mac; > + char *saveptr = NULL; > + char *endptr = NULL; > + > + RTE_LOG(DEBUG, APP, "MAC address change. (mac = %s)\n", mac); > + > + strcpy(tmp_mac, mac); > + while(1) { > + /* Split by clolon(':') */ > + char *ret_tok = strtok_r(str, ":", &saveptr); > + if (unlikely(ret_tok == NULL)) { > + break; > + } > + > + /* Convert string to hex value */ > + int ret_tol = strtol(ret_tok, &endptr, 16); > + if (unlikely(ret_tok == endptr) || unlikely(*endptr != '\0')) { > + break; > + } > + > + /* 各数値をまとめる */ > + token_val = (int64_t)ret_tol; > + ret_mac |= token_val << (token_cnt * 8); > + token_cnt++; > + str = NULL; > + } > + > + /* 区切り文字が5個以外 */ > + if (unlikely(token_cnt != ETHER_ADDR_LEN)) { > + RTE_LOG(ERR, APP, "MAC address format error. (mac = %s)\n", > + mac); > + return -1; > + } > + > + RTE_LOG(DEBUG, APP, "MAC address change. (mac = %s => 0x%08lx)\n", > + mac, ret_mac); > + return ret_mac; > +} > + > +/* > + * Classifier table読み込み > + */ > +static int > +config_load_classifier_table(const json_t *obj, > + struct spp_config_classifier_table *classifier_table) > +{ > + /* classifier_table用オブジェクト取得 */ > + json_t *classifier_obj = json_path_get(obj, JSONPATH_CLASSIFIER_TABLE); > + if (unlikely(classifier_obj == NULL)) { > + RTE_LOG(ERR, APP, "Json object get failed. (path = %s)\n", > + JSONPATH_CLASSIFIER_TABLE); > + return -1; > + } > + > + /* name取得 */ > + int ret_name = config_get_str_value(classifier_obj, JSONPATH_NAME, > + classifier_table->name); > + if (unlikely(ret_name != 0)) { > + RTE_LOG(ERR, APP, "Classifier table name get failed.\n"); > + return -1; > + } > + > + /* table用オブジェクト取得 */ > + json_t *array_obj = json_path_get(classifier_obj, JSONPATH_TABLE); > + if (unlikely(!array_obj)) { > + RTE_LOG(ERR, APP, "Json object get failed. (path = %s)\n", > + JSONPATH_TABLE); > + return -1; > + } > + > + /* table用オブジェクトが配列かチェック */ > + if (unlikely(!json_is_array(array_obj))) { > + RTE_LOG(ERR, APP, "Not an array. (path = %s)\n", > + JSONPATH_TABLE); > + return -1; > + } > + > + /* table用オブジェクトの要素数取得 */ > + int array_num = json_array_size(array_obj); > + if (unlikely(array_num <= 0) || > + unlikely(array_num >= SPP_CONFIG_MAC_TABLE_MAX)) { > + RTE_LOG(ERR, APP, "Table size out of range. (path = %s, size = %d)\n", > + JSONPATH_TABLE, array_num); > + return -1; > + } > + classifier_table->num_table = array_num; > + > + /* テーブルの各要素毎にデータ取得 */ > + struct spp_config_mac_table_element *tmp_table = NULL; > + char if_str[SPP_CONFIG_STR_LEN]; > + int table_cnt = 0; > + for (table_cnt = 0; table_cnt < array_num; table_cnt++) { > + tmp_table = &classifier_table->mac_tables[table_cnt]; > + > + /* 要素取得 */ > + json_t *elements_obj = json_array_get(array_obj, table_cnt); > + if (unlikely(elements_obj == NULL)) { > + RTE_LOG(ERR, APP, > + "Element get failed. (No = %d, path = %s)\n", > + table_cnt, JSONPATH_TABLE); > + return -1; > + } > + > + /* MACアドレス(文字列)取得 */ > + int ret_mac = config_get_str_value(elements_obj, JSONPATH_MAC, > + tmp_table->mac_addr_str); > + if (unlikely(ret_mac != 0)) { > + RTE_LOG(ERR, APP, > + "MAC address get failed. (No = %d, path = %s)\n", > + table_cnt, JSONPATH_MAC); > + return -1; > + } > + > + /* MACアドレス数値変換 */ > + int64_t ret_mac64 = config_change_mac_str_to_int64( > + tmp_table->mac_addr_str); > + if (unlikely(ret_mac64 == -1)) { > + RTE_LOG(ERR, APP, > + "MAC address change failed. (No = %d, mac = %s)\n", > + table_cnt, tmp_table->mac_addr_str); > + return -1; > + } > + tmp_table->mac_addr = ret_mac64; > + > + /* IF情報取得 */ > + int ret_if_str = config_get_str_value(elements_obj, > + JSONPATH_PORT, if_str); > + if (unlikely(ret_if_str != 0)) { > + RTE_LOG(ERR, APP, > + "Interface get failed. (No = %d, path = %s)\n", > + table_cnt, JSONPATH_PORT); > + return -1; > + } > + > + /* IF種別とIF番号に分割 */ > + int ret_if = config_get_if_info(if_str, &tmp_table->port.if_type, > + &tmp_table->port.if_no); > + if (unlikely(ret_if != 0)) { > + RTE_LOG(ERR, APP, > + "Interface change failed. (No = %d, IF = %s)\n", > + table_cnt, if_str); > + return -1; > + } > + } > + > + return 0; > +} > + > +/* > + * 処理種別を文字列から数値変換 > + */ > +static enum spp_core_type > +config_change_core_type(const char *core_type) > +{ > + if(strncmp(core_type, CONFIG_CORE_TYPE_CLASSIFIER_MAC, > + strlen(CONFIG_CORE_TYPE_CLASSIFIER_MAC)+1) == 0) { > + /* Classifier */ > + return SPP_CONFIG_CLASSIFIER_MAC; > + } else if (strncmp(core_type, CONFIG_CORE_TYPE_MERGE, > + strlen(CONFIG_CORE_TYPE_MERGE)+1) == 0) { > + /* Merge */ > + return SPP_CONFIG_MERGE; > + } else if (strncmp(core_type, CONFIG_CORE_TYPE_FORWARD, > + strlen(CONFIG_CORE_TYPE_FORWARD)+1) == 0) { > + /* Forward */ > + return SPP_CONFIG_FORWARD; > + } > + return SPP_CONFIG_UNUSE; > +} > + > +/* > + * 受信ポート取得 > + */ > +static int > +config_set_rx_port(enum spp_core_type type, json_t *obj, > + struct spp_config_functions *functions) > +{ > + struct spp_config_port_info *tmp_rx_port = NULL; > + char if_str[SPP_CONFIG_STR_LEN]; > + if (type == SPP_CONFIG_MERGE) { > + /* Merge */ > + /* 受信ポート用オブジェクト取得 */ > + json_t *array_obj = json_path_get(obj, JSONPATH_RX_PORT); > + if (unlikely(!array_obj)) { > + RTE_LOG(ERR, APP, "Json object get failed. (path = %s, route = merge)\n", > + JSONPATH_RX_PORT); > + return -1; > + } > + > + /* 受信ポート用オブジェクトが配列かチェック */ > + if (unlikely(!json_is_array(array_obj))) { > + RTE_LOG(ERR, APP, "Not an array. (path = %s, route = merge)\n", > + JSONPATH_TABLE); > + return -1; > + } > + > + /* 受信ポート用オブジェクトの要素数取得 */ > + int port_num = json_array_size(array_obj); > + if (unlikely(port_num <= 0) || > + unlikely(port_num >= RTE_MAX_ETHPORTS)) { > + RTE_LOG(ERR, APP, "RX port out of range. (path = %s, port = %d, route = merge)\n", > + JSONPATH_RX_PORT, port_num); > + return -1; > + } > + functions->num_rx_port = port_num; > + > + /* 要素毎にデータ取得 */ > + int array_cnt = 0; > + for (array_cnt = 0; array_cnt < port_num; array_cnt++) { > + tmp_rx_port = &functions->rx_ports[array_cnt]; > + > + /* 要素取得 */ > + json_t *elements_obj = json_array_get(array_obj, array_cnt); > + if (unlikely(elements_obj == NULL)) { > + RTE_LOG(ERR, APP, > + "Element get failed. (No = %d, path = %s, route = merge)\n", > + array_cnt, JSONPATH_RX_PORT); > + return -1; > + } > + > + /* String type check */ > + if (unlikely(!json_is_string(elements_obj))) { > + RTE_LOG(ERR, APP, "Not a string. (path = %s, No = %d, route = merge)\n", > + JSONPATH_RX_PORT, array_cnt); > + return -1; > + } > + strcpy(if_str, json_string_value(elements_obj)); > + > + /* IF種別とIF番号に分割 */ > + int ret_if = config_get_if_info(if_str, &tmp_rx_port->if_type, > + &tmp_rx_port->if_no); > + if (unlikely(ret_if != 0)) { > + RTE_LOG(ERR, APP, > + "Interface change failed. (No = %d, port = %s, route = merge)\n", > + array_cnt, if_str); > + return -1; > + } > + } > + } else { > + /* Classifier/Forward */ > + tmp_rx_port = &functions->rx_ports[0]; > + functions->num_rx_port = 1; > + > + /* 受信ポート取得 */ > + int ret_rx_port = config_get_str_value(obj, JSONPATH_RX_PORT, if_str); > + if (unlikely(ret_rx_port != 0)) { > + RTE_LOG(ERR, APP, "RX port get failed.\n"); > + return -1; > + } > + > + /* IF種別とIF番号に分割 */ > + int ret_if = config_get_if_info(if_str, &tmp_rx_port->if_type, > + &tmp_rx_port->if_no); > + if (unlikely(ret_if != 0)) { > + RTE_LOG(ERR, APP, > + "Interface change failed. (port = %s)\n", if_str); > + return -1; > + } > + } > + > + return 0; > +} > + > +/* > + * 送信先ポート情報取得 > + */ > +static int > +config_set_tx_port(enum spp_core_type type, json_t *obj, > + struct spp_config_functions *functions, > + struct spp_config_classifier_table *classifier_table) > +{ > + struct spp_config_port_info *tmp_tx_port = NULL; > + char if_str[SPP_CONFIG_STR_LEN]; > + if ((type == SPP_CONFIG_MERGE) || (type == SPP_CONFIG_FORWARD)) { > + /* Merge or Forward */ > + tmp_tx_port = &functions->tx_ports[0]; > + functions->num_tx_port = 1; > + > + /* 送信ポート取得 */ > + int ret_tx_port = config_get_str_value(obj, > + JSONPATH_TX_PORT, if_str); > + if (unlikely(ret_tx_port != 0)) { > + RTE_LOG(ERR, APP, "TX port get failed.\n"); > + return -1; > + } > + > + /* IF種別とIF番号に分割 */ > + int ret_if = config_get_if_info(if_str, &tmp_tx_port->if_type, > + &tmp_tx_port->if_no); > + if (unlikely(ret_if != 0)) { > + RTE_LOG(ERR, APP, > + "Interface change failed. (port = %s)\n", > + if_str); > + return -1; > + } > + } else { > + /* Classifier */ > + int cnt = 0; > + functions->num_tx_port = classifier_table->num_table; > + struct spp_config_mac_table_element *tmp_mac_table = NULL; > + for (cnt = 0; cnt < classifier_table->num_table; cnt++) { > + tmp_tx_port = &functions->tx_ports[cnt]; > + tmp_mac_table = &classifier_table->mac_tables[cnt]; > + > + /* MAC振り分けテーブルより設定 */ > + tmp_tx_port->if_type = tmp_mac_table->port.if_type; > + tmp_tx_port->if_no = tmp_mac_table->port.if_no; > + } > + } > + > + return 0; > +} > + > +/* > + * プロセス情報取得 > + */ > +static int > +config_load_proc_info(const json_t *obj, int node_id, struct spp_config_area *config) > +{ > + struct spp_config_proc_info *proc = &config->proc; > + struct spp_config_classifier_table *classifier_table = &config->classifier_table; > + > + /* proc_table用オブジェクト取得 */ > + json_t *proc_table_obj = json_path_get(obj, JSONPATH_PROC_TABLE); > + if (unlikely(proc_table_obj == NULL)) { > + RTE_LOG(ERR, APP, "Json object get failed. (path = %s)\n", > + JSONPATH_PROC_TABLE); > + return -1; > + } > + > + /* table用オブジェクトが配列かチェック */ > + if (unlikely(!json_is_array(proc_table_obj))) { > + RTE_LOG(ERR, APP, "Not an array. (path = %s)\n", > + JSONPATH_TABLE); > + return -1; > + } > + > + /* table用オブジェクトの要素数取得 */ > + int proc_table_num = json_array_size(proc_table_obj); > + if (unlikely(proc_table_num < node_id)) { > + RTE_LOG(ERR, APP, "No process data. (Size = %d, Node = %d)\n", > + proc_table_num, node_id); > + return -1; > + } > + > + /* 要素取得 */ > + json_t *proc_obj = json_array_get(proc_table_obj, node_id); > + if (unlikely(proc_obj == NULL)) { > + RTE_LOG(ERR, APP, "Process data get failed. (Node = %d)\n", > + node_id); > + return -1; > + } > + > + /* name取得 */ > + int ret_name = config_get_str_value(proc_obj, JSONPATH_NAME, proc->name); > + if (unlikely(ret_name != 0)) { > + RTE_LOG(ERR, APP, "Process name get failed.\n"); > + return -1; > + } > + > + /* VHOST数取得 */ > + int ret_vhost = config_get_int_value(proc_obj, JSONPATH_NUM_VHOST, > + &proc->num_vhost); > + if (unlikely(ret_vhost != 0)) { > + RTE_LOG(ERR, APP, "VHOST number get failed.\n"); > + return -1; > + } > + > + /* RING数取得 */ > + int ret_ring = config_get_int_value(proc_obj, JSONPATH_NUM_RING, > + &proc->num_ring); > + if (unlikely(ret_ring != 0)) { > + RTE_LOG(ERR, APP, "RING number get failed.\n"); > + return -1; > + } > + > + /* functions用オブジェクト取得 */ > + json_t *array_obj = json_path_get(proc_obj, JSONPATH_FUNCTIONS); > + if (unlikely(!array_obj)) { > + RTE_LOG(ERR, APP, "Json object get failed. (path = %s)\n", > + JSONPATH_FUNCTIONS); > + return -1; > + } > + > + /* functions用オブジェクトが配列かチェック */ > + if (unlikely(!json_is_array(array_obj))) { > + RTE_LOG(ERR, APP, "Not an array. (path = %s)\n", > + JSONPATH_FUNCTIONS); > + return -1; > + } > + > + /* functions用オブジェクトの要素数取得 */ > + int array_num = json_array_size(array_obj); > + if (unlikely(array_num <= 0) || > + unlikely(array_num >= SPP_CONFIG_CORE_MAX)) { > + RTE_LOG(ERR, APP, "Functions size out of range. (path = %s, size = %d)\n", > + JSONPATH_TABLE, array_num); > + return -1; > + } > + proc->num_func = array_num; > + > + /* 要素毎にデータ取得 */ > + struct spp_config_functions *tmp_functions = NULL; > + char core_type_str[SPP_CONFIG_STR_LEN]; > + int array_cnt = 0; > + for (array_cnt = 0; array_cnt < array_num; array_cnt++) { > + tmp_functions = &proc->functions[array_cnt]; > + > + /* 要素取得 */ > + json_t *elements_obj = json_array_get(array_obj, array_cnt); > + if (unlikely(elements_obj == NULL)) { > + RTE_LOG(ERR, APP, > + "Element get failed. (No = %d, path = %s)\n", > + array_cnt, JSONPATH_FUNCTIONS); > + return -1; > + } > + > + /* CORE番号取得 */ > + int ret_core = config_get_int_value(elements_obj, JSONPATH_CORE_NO, > + &tmp_functions->core_no); > + if (unlikely(ret_core != 0)) { > + RTE_LOG(ERR, APP, "Core number get failed. (No = %d)\n", > + array_cnt); > + return -1; > + } > + > + /* 処理種別取得 */ > + int ret_core_type = config_get_str_value(elements_obj, > + JSONPATH_CORE_TYPE, core_type_str); > + if (unlikely(ret_core_type != 0)) { > + RTE_LOG(ERR, APP, "Core type get failed. (No = %d)\n", > + array_cnt); > + return -1; > + } > + > + /* 処理種別を数値に変換 */ > + enum spp_core_type core_type = config_change_core_type(core_type_str); > + if (unlikely(core_type == SPP_CONFIG_UNUSE)) { > + RTE_LOG(ERR, APP, > + "Unknown core type. (No = %d, type = %s)\n", > + array_cnt, core_type_str); > + return -1; > + } > + tmp_functions->type = core_type; > + > + /* 受信ポート取得 */ > + int ret_rx_port = config_set_rx_port(core_type, elements_obj, > + tmp_functions); > + if (unlikely(ret_rx_port != 0)) { > + RTE_LOG(ERR, APP, "RX port set failure. (No = %d)\n", > + array_cnt); > + return -1; > + } > + > + /* 送信ポート取得 */ > + int ret_tx_port = config_set_tx_port(core_type, elements_obj, > + tmp_functions, classifier_table); > + if (unlikely(ret_tx_port != 0)) { > + RTE_LOG(ERR, APP, "TX port set failure. (No = %d)\n", > + array_cnt); > + return -1; > + } > + } > + > + return 0; > +} > + > +/* > + * Load config file > + * OK : 0 > + * NG : -1 > + */ > +int > +spp_config_load_file(int node_id, struct spp_config_area *config) > +{ > + /* Config initialize */ > + config_init_data(config); > + > + /* Config load */ > + json_error_t json_error; > + json_t *conf_obj = json_load_file(SPP_CONFIG_FILE_PATH, 0, &json_error); > + if (unlikely(conf_obj == NULL)) { > + /* Load error */ > + RTE_LOG(ERR, APP, "Config load failed. (path = %s, text = %s)\n", > + SPP_CONFIG_FILE_PATH, json_error.text); > + return -1; > + } > + > + /* classifier table */ > + int ret_classifier = config_load_classifier_table(conf_obj, > + &config->classifier_table); > + if (unlikely(ret_classifier != 0)) { > + RTE_LOG(ERR, APP, "Classifier table load failed.\n"); > + json_decref(conf_obj); > + return -1; > + } > + > + /* proc info */ > + int ret_proc = config_load_proc_info(conf_obj, node_id, config); > + if (unlikely(ret_proc != 0)) { > + RTE_LOG(ERR, APP, "Process table load failed.\n"); > + json_decref(conf_obj); > + return -1; > + } > + > + /* Config object release */ > + json_decref(conf_obj); > + > + return 0; > +} > diff --git a/src/vf/spp_config.h b/src/vf/spp_config.h > new file mode 100644 > index 0000000..d2a6a4b > --- /dev/null > +++ b/src/vf/spp_config.h > @@ -0,0 +1,90 @@ > +#ifndef __SPP_CONFIG_H__ > +#define __SPP_CONFIG_H__ > + > +#include "common.h" > + > +#define SPP_CONFIG_FILE_PATH "/usr/local/etc/spp/spp.json" > + > +#define SPP_CONFIG_IFTYPE_NIC "nic" > +#define SPP_CONFIG_IFTYPE_VHOST "vhost" > +#define SPP_CONFIG_IFTYPE_RING "ring" > + > +#define SPP_CONFIG_STR_LEN 32 > +#define SPP_CONFIG_MAC_TABLE_MAX 16 > +#define SPP_CONFIG_CORE_MAX 64 > + > +/* > + * Process type for each CORE > + */ > +enum spp_core_type { > + SPP_CONFIG_UNUSE, > + SPP_CONFIG_CLASSIFIER_MAC, > + SPP_CONFIG_MERGE, > + SPP_CONFIG_FORWARD, > +}; > + > +/* > + * Interface information structure > + */ > +struct spp_config_port_info { > + enum port_type if_type; > + int if_no; > +}; > + > +/* > + * MAC Table information structure > + */ > +struct spp_config_mac_table_element { > + struct spp_config_port_info port; > + char mac_addr_str[SPP_CONFIG_STR_LEN]; > + uint64_t mac_addr; > +}; > + > +/* > + * Classifier Table information structure > + */ > +struct spp_config_classifier_table { > + char name[SPP_CONFIG_STR_LEN]; > + int num_table; > + struct spp_config_mac_table_element mac_tables[SPP_CONFIG_MAC_TABLE_MAX]; > +}; > + > +/* > + * Functions information structure > + */ > +struct spp_config_functions { > + int core_no; > + enum spp_core_type type; > + int num_rx_port; > + int num_tx_port; > + struct spp_config_port_info rx_ports[RTE_MAX_ETHPORTS]; > + struct spp_config_port_info tx_ports[RTE_MAX_ETHPORTS]; > +}; > + > +/* > + * Process information structure > + */ > +struct spp_config_proc_info { > + char name[SPP_CONFIG_STR_LEN]; > + int num_vhost; > + int num_ring; > + int num_func; > + struct spp_config_functions functions[SPP_CONFIG_CORE_MAX]; > +}; > + > +/* > + * Config information structure > + */ > +struct spp_config_area { > + struct spp_config_proc_info proc; > + struct spp_config_classifier_table classifier_table; > +}; > + > +/* > + * Load config file > + * OK : 0 > + * NG : -1 > + */ > +int spp_config_load_file(int node_id, struct spp_config_area *config); > + > +#endif /* __SPP_CONFIG_H__ */ > diff --git a/src/vf/spp_forward.c b/src/vf/spp_forward.c > new file mode 100644 > index 0000000..4396929 > --- /dev/null > +++ b/src/vf/spp_forward.c > @@ -0,0 +1,106 @@ > +#include "spp_vf.h" > +#include "ringlatencystats.h" > + > +#define RTE_LOGTYPE_SPP_FORWARD RTE_LOGTYPE_USER1 > + > +/* > + * 送受信ポートの経路情報 > + */ > +struct rxtx { > + struct spp_core_port_info rx; > + struct spp_core_port_info tx; > +}; > + > +/* > + * 使用するIF情報を移し替える > + */ > +void > +set_use_interface(struct spp_core_port_info *dst, > + struct spp_core_port_info *src) > +{ > + dst->if_type = src->if_type; > + dst->if_no = src->if_no; > + dst->dpdk_port = src->dpdk_port; > +} > + > +/* > + * Merge/Forward > + */ > +int > +spp_forward(void *arg) > +{ > + unsigned int lcore_id = rte_lcore_id(); > + struct spp_core_info *core_info = (struct spp_core_info *)arg; > + int if_cnt, rxtx_num = 0; > + struct rxtx patch[RTE_MAX_ETHPORTS]; > + > + /* RX/TX Info setting */ > + rxtx_num = core_info->num_rx_port; > + for (if_cnt = 0; if_cnt < rxtx_num; if_cnt++) { > + set_use_interface(&patch[if_cnt].rx, > + &core_info->rx_ports[if_cnt]); > + if (core_info->type == SPP_CONFIG_FORWARD) { > + /* FORWARD */ > + set_use_interface(&patch[if_cnt].tx, > + &core_info->tx_ports[if_cnt]); > + } else { > + /* MERGE */ > + set_use_interface(&patch[if_cnt].tx, > + &core_info->tx_ports[0]); > + } > + } > + > + /* Thread IDLE */ > + core_info->status = SPP_CORE_IDLE; > + RTE_LOG(INFO, FORWARD, "Core[%d] Start. (type = %d)\n", lcore_id, > + core_info->type); > + > + int cnt, nb_rx, nb_tx, buf; > + struct spp_core_port_info *rx; > + struct spp_core_port_info *tx; > + struct rte_mbuf *bufs[MAX_PKT_BURST]; > + while (likely(core_info->status == SPP_CORE_IDLE) || > + likely(core_info->status == SPP_CORE_FORWARD)) { > + while (likely(core_info->status == SPP_CORE_FORWARD)) { > + for (cnt = 0; cnt < rxtx_num; cnt++) { > + rx = &patch[cnt].rx; > + tx = &patch[cnt].tx; > + > + /* Packet receive */ > + nb_rx = rte_eth_rx_burst(rx->dpdk_port, 0, bufs, MAX_PKT_BURST); > + if (unlikely(nb_rx == 0)) { > + continue; > + } > + > +#ifdef SPP_RINGLATENCYSTATS_ENABLE /* RING滞留時間 */ > + if (rx->if_type == RING) { > + /* Receive port is RING */ > + spp_ringlatencystats_calculate_latency(rx->if_no, > + bufs, nb_rx); > + } > + if (tx->if_type == RING) { > + /* Send port is RING */ > + spp_ringlatencystats_add_time_stamp(tx->if_no, > + bufs, nb_rx); > + } > +#endif /* SPP_RINGLATENCYSTATS_ENABLE */ > + > + /* Send packet */ > + nb_tx = rte_eth_tx_burst(tx->dpdk_port, 0, bufs, nb_rx); > + > + /* Free any unsent packets. */ > + if (unlikely(nb_tx < nb_rx)) { > + for (buf = nb_tx; buf < nb_rx; buf++) { > + rte_pktmbuf_free(bufs[buf]); > + } > + } > + } > + } > + } > + > + /* Thread STOP */ > + RTE_LOG(INFO, FORWARD, "Core[%d] End. (type = %d)\n", lcore_id, > + core_info->type); > + core_info->status = SPP_CORE_STOP; > + return 0; > +} > diff --git a/src/vf/spp_forward.h b/src/vf/spp_forward.h > new file mode 100644 > index 0000000..33208bf > --- /dev/null > +++ b/src/vf/spp_forward.h > @@ -0,0 +1,9 @@ > +#ifndef __SPP_FORWARD_H__ > +#define __SPP_FORWARD_H__ > + > +/* > + * Merge/Forward > + */ > +int spp_forward(void *arg); > + > +#endif /* __SPP_FORWARD_H__ */ > diff --git a/src/vf/spp_vf.c b/src/vf/spp_vf.c > new file mode 100644 > index 0000000..ee5cf63 > --- /dev/null > +++ b/src/vf/spp_vf.c > @@ -0,0 +1,794 @@ > +#include > +#include > + > +#include > +#include > +#include > + > +#include "spp_vf.h" > +#include "ringlatencystats.h" > +#include "classifier_mac.h" > +#include "spp_forward.h" > + > +/* define */ > +#define SPP_CORE_STATUS_CHECK_MAX 5 > +#define SPP_RING_LATENCY_STATS_SAMPLING_INTERVAL 1000000 > + > +/* struct */ > +struct startup_param { > + uint64_t cpu; > +}; > + > +struct patch_info { > + int use_flg; > + int dpdk_port; > + struct spp_config_mac_table_element *mac_info; > + struct spp_core_port_info *rx_core; > + struct spp_core_port_info *tx_core; > +}; > + > +struct if_info { > + int num_nic; > + int num_vhost; > + int num_ring; > + struct patch_info nic_patchs[RTE_MAX_ETHPORTS]; > + struct patch_info vhost_patchs[RTE_MAX_ETHPORTS]; > + struct patch_info ring_patchs[RTE_MAX_ETHPORTS]; > +}; > + > +static struct spp_config_area g_config; > +static struct startup_param g_startup_param; > +static struct if_info g_if_info; > +static struct spp_core_info g_core_info[SPP_CONFIG_CORE_MAX]; > + > +/* > + * print a usage message > + */ > +static void > +usage(const char *progname) > +{ > + RTE_LOG(INFO, APP, "Usage: %s [EAL args]\n\n", progname); > +} > + > +/* > + * Set RING PMD > + */ > +static int > +add_ring_pmd(int ring_id) > +{ > + struct rte_ring *ring; > + int ring_port_id; > + > + /* look up ring, based on user's provided id*/ > + ring = rte_ring_lookup(get_rx_queue_name(ring_id)); > + if (unlikely(ring == NULL)) { > + RTE_LOG(ERR, APP, > + "Cannot get RX ring - is server process running?\n"); > + return -1; > + } > + > + /* create ring pmd*/ > + ring_port_id = rte_eth_from_ring(ring); > + RTE_LOG(DEBUG, APP, "ring port id %d\n", ring_port_id); > + > + return ring_port_id; > +} > + > +/* > + * Set VHOST PMD > + */ > +static int > +add_vhost_pmd(int index) > +{ > + struct rte_eth_conf port_conf = { > + .rxmode = { .max_rx_pkt_len = ETHER_MAX_LEN } > + }; > + struct rte_mempool *mp; > + uint8_t vhost_port_id; > + int nr_queues = 1; > + const char *name; > + char devargs[64]; > + char *iface; > + uint16_t q; > + int ret; > +#define NR_DESCS 128 > + > + mp = rte_mempool_lookup(PKTMBUF_POOL_NAME); > + if (unlikely(mp == NULL)) { > + RTE_LOG(ERR, APP, "Cannot get mempool for mbufs. (name = %s)\n", > + PKTMBUF_POOL_NAME); > + return -1; > + } > + > + /* eth_vhost0 index 0 iface /tmp/sock0 on numa 0 */ > + name = get_vhost_backend_name(index); > + iface = get_vhost_iface_name(index); > + > + sprintf(devargs, "%s,iface=%s,queues=%d", name, iface, nr_queues); > + ret = rte_eth_dev_attach(devargs, &vhost_port_id); > + if (unlikely(ret < 0)) { > + RTE_LOG(ERR, APP, "rte_eth_dev_attach error. (ret = %d)\n", ret); > + return ret; > + } > + > + ret = rte_eth_dev_configure(vhost_port_id, nr_queues, nr_queues, > + &port_conf); > + if (unlikely(ret < 0)) { > + RTE_LOG(ERR, APP, "rte_eth_dev_configure error. (ret = %d)\n", > + ret); > + return ret; > + } > + > + /* Allocate and set up 1 RX queue per Ethernet port. */ > + for (q = 0; q < nr_queues; q++) { > + ret = rte_eth_rx_queue_setup(vhost_port_id, q, NR_DESCS, > + rte_eth_dev_socket_id(vhost_port_id), NULL, mp); > + if (unlikely(ret < 0)) { > + RTE_LOG(ERR, APP, > + "rte_eth_rx_queue_setup error. (ret = %d)\n", > + ret); > + return ret; > + } > + } > + > + /* Allocate and set up 1 TX queue per Ethernet port. */ > + for (q = 0; q < nr_queues; q++) { > + ret = rte_eth_tx_queue_setup(vhost_port_id, q, NR_DESCS, > + rte_eth_dev_socket_id(vhost_port_id), NULL); > + if (unlikely(ret < 0)) { > + RTE_LOG(ERR, APP, > + "rte_eth_tx_queue_setup error. (ret = %d)\n", > + ret); > + return ret; > + } > + } > + > + /* Start the Ethernet port. */ > + ret = rte_eth_dev_start(vhost_port_id); > + if (unlikely(ret < 0)) { > + RTE_LOG(ERR, APP, "rte_eth_dev_start error. (ret = %d)\n", ret); > + return ret; > + } > + > + RTE_LOG(DEBUG, APP, "vhost port id %d\n", vhost_port_id); > + > + return vhost_port_id; > +} > + > +/* > + * Check core status > + */ > +static int > +check_core_status(enum spp_core_status status) > +{ > + int cnt; > + for (cnt = 0; cnt < SPP_CONFIG_CORE_MAX; cnt++) { > + if (g_core_info[cnt].type == SPP_CONFIG_UNUSE) { > + continue; > + } > + if (g_core_info[cnt].status != status) { > + /* Status mismatch */ > + return -1; > + } > + } > + return 0; > +} > + > +/* > + * Wait for core status check > + */ > +static int > +check_core_status_wait(enum spp_core_status status) > +{ > + int cnt = 0; > + for (cnt = 0; cnt < SPP_CORE_STATUS_CHECK_MAX; cnt++) { > + sleep(1); > + int ret = check_core_status(status); > + if (ret == 0) { > + return 0; > + } > + } > + > + RTE_LOG(ERR, APP, "Status check time out. (status = %d)\n", status); > + return -1; > +} > + > +/* > + * Set core status > + */ > +static void > +set_core_status(enum spp_core_status status) > +{ > + int core_cnt = 0; > + for(core_cnt = 0; core_cnt < SPP_CONFIG_CORE_MAX; core_cnt++) { > + g_core_info[core_cnt].status = status; > + } > +} > + > +/* > + * Process stop > + */ > +void > +stop_process(int signal) { > + if (unlikely(signal != SIGTERM) && > + unlikely(signal != SIGINT)) { > + /* Other signals */ > + return; > + } > + > + set_core_status(SPP_CORE_STOP_REQUEST); > +} > + > +/* > + * 起動パラメータのCPUのbitmapを数値へ変換 > + */ > +static int > +parse_cpu_bit(uint64_t *cpu, const char *cpu_bit) > +{ > + char *endptr = NULL; > + uint64_t temp; > + > + temp = strtoull(cpu_bit, &endptr, 0); > + if (unlikely(endptr == cpu_bit) || unlikely(*endptr != '\0')) { > + return -1; > + } > + > + *cpu = temp; > + RTE_LOG(DEBUG, APP, "cpu = %lu", *cpu); > + return 0; > +} > + > +/* > + * Parse the application arguments to the client app. > + */ > +static int > +parse_app_args(int argc, char *argv[]) > +{ > + int option_index, opt; > + char **argvopt = argv; > + const char *progname = argv[0]; > + static struct option lgopts[] = { {0} }; > + > + /* Check DPDK parameter */ > + optind = 0; > + opterr = 0; > + while ((opt = getopt_long(argc, argvopt, "c:", lgopts, > + &option_index)) != EOF) { > + switch (opt) { > + case 'c': > + /* CPU */ > + if (parse_cpu_bit(&g_startup_param.cpu, optarg) != 0) { > + usage(progname); > + return -1; > + } > + break; > + default: > + /* CPU */ > + /* DPDKのパラメータは他にもあるので、エラーとはしない */ > + break; > + } > + } > + > + return 0; > +} > + > +/* > + * IF種別&IF番号のIF情報の領域取得 > + */ > +static struct patch_info * > +get_if_area(enum port_type if_type, int if_no) > +{ > + switch (if_type) { > + case PHY: > + return &g_if_info.nic_patchs[if_no]; > + break; > + case VHOST: > + return &g_if_info.vhost_patchs[if_no]; > + break; > + case RING: > + return &g_if_info.ring_patchs[if_no]; > + break; > + default: > + /* エラー出力は呼び元でチェック */ > + return NULL; > + break; > + } > +} > + > +/* > + * IF情報初期化 > + */ > +static void > +init_if_info() > +{ > + memset(&g_if_info, 0x00, sizeof(g_if_info)); > +} > + > +/* > + * CORE情報初期化 > + */ > +static void > +init_core_info() > +{ > + memset(&g_core_info, 0x00, sizeof(g_core_info)); > + int core_cnt, port_cnt; > + for (core_cnt = 0; core_cnt < SPP_CONFIG_CORE_MAX; core_cnt++) { > + for (port_cnt = 0; port_cnt < RTE_MAX_ETHPORTS; port_cnt++) { > + g_core_info[core_cnt].rx_ports[port_cnt].if_type = UNDEF; > + g_core_info[core_cnt].tx_ports[port_cnt].if_type = UNDEF; > + } > + } > +} > + > +/* > + * Configのプロセス情報から管理情報に設定 > + */ > +static int > +set_form_proc_info(struct spp_config_area *config) > +{ > + /* Configのproc_infoから内部管理情報へ設定 */ > + int core_cnt, rx_start, rx_cnt, tx_start, tx_cnt; > + enum port_type if_type; > + int if_no; > + int64_t cpu_bit = 0; > + struct spp_config_functions *core_func = NULL; > + struct spp_core_info *core_info = NULL; > + struct patch_info *patch_info = NULL; > + for (core_cnt = 0; core_cnt < config->proc.num_func; core_cnt++) { > + core_func = &config->proc.functions[core_cnt]; > + core_info = &g_core_info[core_func->core_no]; > + > + if (core_func->type == SPP_CONFIG_UNUSE) { > + continue; > + } > + > + /* Forwardをまとめる事は可、他種別は不可 */ > + if ((core_info->type != SPP_CONFIG_UNUSE) && > + ((core_info->type != SPP_CONFIG_FORWARD) && > + (core_func->type != SPP_CONFIG_FORWARD))) { > + RTE_LOG(ERR, APP, "Core in use. (core = %d, type = %d/%d)\n", > + core_func->core_no, > + core_func->type, core_info->type); > + return -1; > + } > + > + /* Set CORE type */ > + core_info->type = core_func->type; > + cpu_bit |= 1 << core_func->core_no; > + > + /* Set RX port */ > + rx_start = core_info->num_rx_port; > + core_info->num_rx_port += core_func->num_rx_port; > + for (rx_cnt = 0; rx_cnt < core_func->num_rx_port; rx_cnt++) { > + if_type = core_func->rx_ports[rx_cnt].if_type; > + if_no = core_func->rx_ports[rx_cnt].if_no; > + > + core_info->rx_ports[rx_start + rx_cnt].if_type = if_type; > + core_info->rx_ports[rx_start + rx_cnt].if_no = if_no; > + > + /* IF種別とIF番号に対応するIF情報の領域取得 */ > + patch_info = get_if_area(if_type, if_no); > + > + patch_info->use_flg = 1; > + if (unlikely(patch_info->rx_core != NULL)) { > + RTE_LOG(ERR, APP, "Used RX port (if_type = %d, if_no = %d)\n", > + if_type, if_no); > + return -1; > + } > + > + /* IF情報からCORE情報を変更する場合用に設定 */ > + patch_info->rx_core = &core_info->rx_ports[rx_start + rx_cnt]; > + } > + > + /* Set TX port */ > + tx_start = core_info->num_tx_port; > + core_info->num_tx_port += core_func->num_tx_port; > + for (tx_cnt = 0; tx_cnt < core_func->num_tx_port; tx_cnt++) { > + if_type = core_func->tx_ports[tx_cnt].if_type; > + if_no = core_func->tx_ports[tx_cnt].if_no; > + > + core_info->tx_ports[tx_start + tx_cnt].if_type = if_type; > + core_info->tx_ports[tx_start + tx_cnt].if_no = if_no; > + > + /* IF種別とIF番号に対応するIF情報の領域取得 */ > + patch_info = get_if_area(if_type, if_no); > + > + patch_info->use_flg = 1; > + if (unlikely(patch_info->tx_core != NULL)) { > + RTE_LOG(ERR, APP, "Used TX port (if_type = %d, if_no = %d)\n", > + if_type, if_no); > + return -1; > + } > + > + /* IF情報からCORE情報を変更する場合用に設定 */ > + patch_info->tx_core = &core_info->tx_ports[tx_start + tx_cnt]; > + } > + } > + > + if (unlikely((cpu_bit & g_startup_param.cpu) != cpu_bit)) { > + /* CPU mismatch */ > + RTE_LOG(ERR, APP, "CPU mismatch (cpu param = %lx, config = %lx)\n", > + g_startup_param.cpu, cpu_bit); > + return -1; > + } > + return 0; > +} > + > +/* > + * ConfigのMACテーブル情報から管理情報に設定 > + */ > +static int > +set_from_classifier_table(struct spp_config_area *config) > +{ > + /* MAC table */ > + enum port_type if_type; > + int if_no = 0; > + int mac_cnt = 0; > + struct spp_config_mac_table_element *mac_table = NULL; > + struct patch_info *patch_info = NULL; > + for (mac_cnt = 0; mac_cnt < config->classifier_table.num_table; mac_cnt++) { > + mac_table = &config->classifier_table.mac_tables[mac_cnt]; > + > + if_type = mac_table->port.if_type; > + if_no = mac_table->port.if_no; > + > + /* IF種別とIF番号に対応するIF情報の領域取得 */ > + patch_info = get_if_area(if_type, if_no); > + > + if (unlikely(patch_info->use_flg == 0)) { > + RTE_LOG(ERR, APP, "Not used interface (if_type = %d, if_no = %d)\n", > + if_type, if_no); > + return -1; > + } > + > + /* CORE情報側にもMACアドレスの情報設定 */ > + /* MACアドレスは送信側のみに影響する為、送信側のみ設定 */ > + patch_info->mac_info = mac_table; > + if (unlikely(patch_info->tx_core != NULL)) { > + patch_info->tx_core->mac_addr = mac_table->mac_addr; > + strcpy(patch_info->tx_core->mac_addr_str, mac_table->mac_addr_str); > + } > + } > + return 0; > +} > + > +/* > + * NIC用の情報設定 > + */ > +static int > +set_nic_interface(struct spp_config_area *config) > +{ > + /* NIC Setting */ > + g_if_info.num_nic = rte_eth_dev_count(); > + if (g_if_info.num_nic > RTE_MAX_ETHPORTS) { > + g_if_info.num_nic = RTE_MAX_ETHPORTS; > + } > + > + int nic_cnt, nic_num = 0; > + struct patch_info *patch_info = NULL; > + for (nic_cnt = 0; nic_cnt < RTE_MAX_ETHPORTS; nic_cnt++) { > + patch_info = &g_if_info.nic_patchs[nic_cnt]; > + /* Set DPDK port */ > + patch_info->dpdk_port = nic_cnt; > + > + if (patch_info->use_flg == 0) { > + /* Not Used */ > + continue; > + } > + > + /* CORE情報側にもDPDKポート番号の情報設定 */ > + if (patch_info->rx_core != NULL) { > + patch_info->rx_core->dpdk_port = nic_cnt; > + } > + if (patch_info->tx_core != NULL) { > + patch_info->tx_core->dpdk_port = nic_cnt; > + } > + > + /* NICの設定数カウント */ > + nic_num++; > + } > + > + if (unlikely(nic_num > g_if_info.num_nic)) { > + RTE_LOG(ERR, APP, "NIC Setting mismatch. (IF = %d, config = %d)\n", > + nic_num, g_if_info.num_nic); > + return -1; > + } > + > + return 0; > +} > + > +/* > + * VHOST用の情報設定 > + */ > +static int > +set_vhost_interface(struct spp_config_area *config) > +{ > + /* VHOST Setting */ > + int vhost_cnt, vhost_num = 0; > + g_if_info.num_vhost = config->proc.num_vhost; > + struct patch_info *patch_info = NULL; > + for (vhost_cnt = 0; vhost_cnt < RTE_MAX_ETHPORTS; vhost_cnt++) { > + patch_info = &g_if_info.vhost_patchs[vhost_cnt]; > + if (patch_info->use_flg == 0) { > + /* Not Used */ > + continue; > + } > + > + /* Set DPDK port */ > + int dpdk_port = add_vhost_pmd(vhost_cnt); > + if (unlikely(dpdk_port < 0)) { > + RTE_LOG(ERR, APP, "VHOST add failed. (no = %d)\n", > + vhost_cnt); > + return -1; > + } > + patch_info->dpdk_port = dpdk_port; > + > + /* CORE情報側にもDPDKポート番号の情報設定 */ > + if (patch_info->rx_core != NULL) { > + patch_info->rx_core->dpdk_port = dpdk_port; > + } > + if (patch_info->tx_core != NULL) { > + patch_info->tx_core->dpdk_port = dpdk_port; > + } > + vhost_num++; > + } > + if (unlikely(vhost_num > g_if_info.num_vhost)) { > + RTE_LOG(ERR, APP, "VHOST Setting mismatch. (IF = %d, config = %d)\n", > + vhost_num, g_if_info.num_vhost); > + return -1; > + } > + return 0; > +} > + > +/* > + * RING用の情報設定 > + */ > +static int > +set_ring_interface(struct spp_config_area *config) > +{ > + /* RING Setting */ > + int ring_cnt, ring_num = 0; > + g_if_info.num_ring = config->proc.num_ring; > + struct patch_info *patch_info = NULL; > + for (ring_cnt = 0; ring_cnt < RTE_MAX_ETHPORTS; ring_cnt++) { > + patch_info = &g_if_info.ring_patchs[ring_cnt]; > + if (patch_info->use_flg == 0) { > + /* Not Used */ > + continue; > + } > + > + /* Set DPDK port */ > + int dpdk_port = add_ring_pmd(ring_cnt); > + if (unlikely(dpdk_port < 0)) { > + RTE_LOG(ERR, APP, "RING add failed. (no = %d)\n", > + ring_cnt); > + return -1; > + } > + patch_info->dpdk_port = dpdk_port; > + > + /* CORE情報側にもDPDKポート番号の情報設定 */ > + if (patch_info->rx_core != NULL) { > + patch_info->rx_core->dpdk_port = dpdk_port; > + } > + if (patch_info->tx_core != NULL) { > + patch_info->tx_core->dpdk_port = dpdk_port; > + } > + ring_num++; > + } > + if (unlikely(ring_num > g_if_info.num_ring)) { > + RTE_LOG(ERR, APP, "RING Setting mismatch. (IF = %d, config = %d)\n", > + ring_num, g_if_info.num_ring); > + return -1; > + } > + return 0; > +} > + > +/* > + * 管理データ初期設定 > + */ > +static int > +init_manage_data(struct spp_config_area *config) > +{ > + /* Initialize */ > + init_if_info(config); > + init_core_info(config); > + > + /* Set config data */ > + int ret_proc = set_form_proc_info(config); > + if (unlikely(ret_proc != 0)) { > + /* 関数内でログ出力済みなので、省略 */ > + return -1; > + } > + int ret_classifier = set_from_classifier_table(config); > + if (unlikely(ret_classifier != 0)) { > + /* 関数内でログ出力済みなので、省略 */ > + return -1; > + } > + > + /* Set interface data */ > + int ret_nic = set_nic_interface(config); > + if (unlikely(ret_nic != 0)) { > + /* 関数内でログ出力済みなので、省略 */ > + return -1; > + } > + > + int ret_vhost = set_vhost_interface(config); > + if (unlikely(ret_vhost != 0)) { > + /* 関数内でログ出力済みなので、省略 */ > + return -1; > + } > + > + int ret_ring = set_ring_interface(config); > + if (unlikely(ret_ring != 0)) { > + /* 関数内でログ出力済みなので、省略 */ > + return -1; > + } > + > + return 0; > +} > + > +#ifdef SPP_RINGLATENCYSTATS_ENABLE /* RING滞留時間 */ > +static void > +print_ring_latency_stats() > +{ > + /* Clear screen and move to top left */ > + const char topLeft[] = { 27, '[', '1', ';', '1', 'H', '\0' }; > + const char clr[] = { 27, '[', '2', 'J', '\0' }; > + printf("%s%s", clr, topLeft); > + > + /* Print per RING */ > + int ring_cnt, stats_cnt; > + struct spp_ringlatencystats_ring_latency_stats stats[RTE_MAX_ETHPORTS]; > + memset(&stats, 0x00, sizeof(stats)); > + > + printf("RING Latency\n"); > + printf(" RING"); > + for (ring_cnt = 0; ring_cnt < RTE_MAX_ETHPORTS; ring_cnt++) { > + if (g_if_info.ring_patchs[ring_cnt].use_flg == 0) { > + continue; > + } > + spp_ringlatencystats_get_stats(ring_cnt, &stats[ring_cnt]); > + printf(", %-18d", ring_cnt); > + } > + printf("\n"); > + > + for (stats_cnt = 0; stats_cnt < SPP_RINGLATENCYSTATS_STATS_SLOT_COUNT; stats_cnt++) { > + printf("%3dns", stats_cnt); > + for (ring_cnt = 0; ring_cnt < RTE_MAX_ETHPORTS; ring_cnt++) { > + if (g_if_info.ring_patchs[ring_cnt].use_flg == 0) { > + continue; > + } > + > + printf(", 0x%-16lx", stats[ring_cnt].slot[stats_cnt]); > + } > + printf("\n"); > + } > + > + return; > +} > +#endif /* SPP_RINGLATENCYSTATS_ENABLE */ > + > +/* > + * main > + */ > +int > +#ifndef USE_UT_SPP_VF > +main(int argc, char *argv[]) > +#else /* ifndef USE_UT_SPP_VF */ > +ut_main(int argc, char *argv[]) > +#endif /* ifndef USE_UT_SPP_VF */ > +{ > + int ret = -1; > +#ifdef SPP_DEMONIZE > + /* Daemonize process */ > + int ret_daemon = daemon(0, 0); > + if (unlikely(ret_daemon != 0)) { > + RTE_LOG(ERR, APP, "daemonize is faild. (ret = %d)\n", ret_daemon); > + return ret_daemon; > + } > +#endif > + > + /* Signal handler registration (SIGTERM/SIGINT) */ > + signal(SIGTERM, stop_process); > + signal(SIGINT, stop_process); > + > + unsigned int main_lcore_id = 0xffffffff; > + while(1) { > + /* Parse parameters */ > + int ret_parse = parse_app_args(argc, argv); > + if (unlikely(ret_parse != 0)) { > + break; > + } > + > + /* Load config */ > + int ret_config = spp_config_load_file(0, &g_config); > + if (unlikely(ret_config != 0)) { > + break; > + } > + > + /* DPDK initialize */ > + int ret_dpdk = rte_eal_init(argc, argv); > + if (unlikely(ret_dpdk < 0)) { > + break; > + } > + /* Get core id. */ > + main_lcore_id = rte_lcore_id(); > + > + /* 起動パラメータとコンフィグチェック */ > + /* 各IF情報設定 */ > + int ret_manage = init_manage_data(&g_config); > + if (unlikely(ret_manage != 0)) { > + break; > + } > + > + /* 他機能部初期化 */ > +#ifdef SPP_RINGLATENCYSTATS_ENABLE /* RING滞留時間 */ > + int ret_ringlatency = spp_ringlatencystats_init( > + SPP_RING_LATENCY_STATS_SAMPLING_INTERVAL, g_if_info.num_ring); > + if (unlikely(ret_ringlatency != 0)) { > + break; > + } > +#endif /* SPP_RINGLATENCYSTATS_ENABLE */ > + > + /* Start thread */ > + unsigned int lcore_id = 0; > + RTE_LCORE_FOREACH_SLAVE(lcore_id) { > + if (g_core_info[lcore_id].type == SPP_CONFIG_CLASSIFIER_MAC) { > + rte_eal_remote_launch(spp_classifier_mac_do, > + (void *)&g_core_info[lcore_id], > + lcore_id); > + } else { > + rte_eal_remote_launch(spp_forward, > + (void *)&g_core_info[lcore_id], > + lcore_id); > + } > + } > + > + /* スレッド状態確認 */ > + g_core_info[main_lcore_id].status = SPP_CORE_IDLE; > + int ret_wait = check_core_status_wait(SPP_CORE_IDLE); > + if (unlikely(ret_wait != 0)) { > + break; > + } > + > + /* Start forward */ > + set_core_status(SPP_CORE_FORWARD); > + RTE_LOG(INFO, APP, "My ID %d start handling message\n", 0); > + RTE_LOG(INFO, APP, "[Press Ctrl-C to quit ...]\n"); > + > + /* loop */ > +#ifndef USE_UT_SPP_VF > + while(likely(g_core_info[main_lcore_id].status != SPP_CORE_STOP_REQUEST)) { > +#else > + { > +#endif > + sleep(1); > + > +#ifdef SPP_RINGLATENCYSTATS_ENABLE /* RING滞留時間 */ > + print_ring_latency_stats(); > +#endif /* SPP_RINGLATENCYSTATS_ENABLE */ > + } > + > + /* 正常終了 */ > + ret = 0; > + break; > + } > + > + /* exit */ > + stop_process(SIGINT); > + if (main_lcore_id == rte_lcore_id()) > + { > + g_core_info[main_lcore_id].status = SPP_CORE_STOP; > + int ret_core_end = check_core_status_wait(SPP_CORE_STOP); > + if (unlikely(ret_core_end != 0)) { > + RTE_LOG(ERR, APP, "Core did not stop.\n"); > + } > + } > + > + /* 他機能部終了処理 */ > +#ifdef SPP_RINGLATENCYSTATS_ENABLE /* RING滞留時間 */ > + spp_ringlatencystats_uninit(); > +#endif /* SPP_RINGLATENCYSTATS_ENABLE */ > + RTE_LOG(INFO, APP, "spp_vf exit.\n"); > + return ret; > +} > diff --git a/src/vf/spp_vf.h b/src/vf/spp_vf.h > new file mode 100644 > index 0000000..feb59b6 > --- /dev/null > +++ b/src/vf/spp_vf.h > @@ -0,0 +1,40 @@ > +#ifndef __SPP_VF_H__ > +#define __SPP_VF_H__ > + > +#include "common.h" > +#include "spp_config.h" > + > +/* > + * State on core > + */ > +enum spp_core_status { > + SPP_CORE_STOP, > + SPP_CORE_IDLE, > + SPP_CORE_FORWARD, > + SPP_CORE_STOP_REQUEST > +}; > + > +/* > + * Port info on core > + */ > +struct spp_core_port_info { > + enum port_type if_type; > + int if_no; > + int dpdk_port; > + uint64_t mac_addr; > + char mac_addr_str[SPP_CONFIG_STR_LEN]; > +}; > + > +/* > + * Core info > + */ > +struct spp_core_info { > + enum spp_core_status status; > + enum spp_core_type type; > + int num_rx_port; > + int num_tx_port; > + struct spp_core_port_info rx_ports[RTE_MAX_ETHPORTS]; > + struct spp_core_port_info tx_ports[RTE_MAX_ETHPORTS]; > +}; > + > +#endif /* __SPP_VF_H__ */ > -- Yasufumi Ogawa NTT Network Service Systems Labs