From 79d98f2a6e3cbd875bd1474d0eef4fc16c9c1b38 Mon Sep 17 00:00:00 2001 From: root Date: Fri, 22 Oct 2021 16:07:44 +0800 Subject: [PATCH 1/5] add dpdk code --- hwcompatible/compatibility.py | 31 +- hwcompatible/dpdkutil.py | 141 +++++ hwcompatible/job.py | 12 +- scripts/oech | 2 +- server/server.py | 53 +- test.py | 27 + tests/dpdk/Makefile | 28 + tests/dpdk/__init__.py | 0 tests/dpdk/dpdk-native-test/Makefile | 43 ++ tests/dpdk/dpdk-native-test/config.h | 201 +++++++ tests/dpdk/dpdk-native-test/icmpecho.c | 515 +++++++++++++++++ tests/dpdk/dpdk-native-test/latency.c | 386 +++++++++++++ tests/dpdk/dpdk-native-test/main.c | 732 ++++++++++++++++++++++++ tests/dpdk/dpdk-native-test/meson.build | 13 + tests/dpdk/dpdk-native-test/rx.c | 87 +++ tests/dpdk/dpdk-native-test/stats.c | 435 ++++++++++++++ tests/dpdk/dpdk-native-test/stats.h | 21 + tests/dpdk/dpdk-native-test/tx.c | 338 +++++++++++ tests/dpdk/dpdk.py | 257 +++++++++ tests/dpdk/hugepages.py | 76 +++ tests/dpdk/spdk.py | 34 ++ 21 files changed, 3419 insertions(+), 13 deletions(-) create mode 100755 hwcompatible/dpdkutil.py create mode 100755 test.py create mode 100755 tests/dpdk/Makefile create mode 100755 tests/dpdk/__init__.py create mode 100755 tests/dpdk/dpdk-native-test/Makefile create mode 100755 tests/dpdk/dpdk-native-test/config.h create mode 100755 tests/dpdk/dpdk-native-test/icmpecho.c create mode 100755 tests/dpdk/dpdk-native-test/latency.c create mode 100755 tests/dpdk/dpdk-native-test/main.c create mode 100755 tests/dpdk/dpdk-native-test/meson.build create mode 100755 tests/dpdk/dpdk-native-test/rx.c create mode 100755 tests/dpdk/dpdk-native-test/stats.c create mode 100755 tests/dpdk/dpdk-native-test/stats.h create mode 100755 tests/dpdk/dpdk-native-test/tx.c create mode 100755 tests/dpdk/dpdk.py create mode 100755 tests/dpdk/hugepages.py create mode 100755 tests/dpdk/spdk.py diff --git a/hwcompatible/compatibility.py b/hwcompatible/compatibility.py index a4c27aa..d4f7928 100755 --- a/hwcompatible/compatibility.py +++ b/hwcompatible/compatibility.py @@ -27,6 +27,7 @@ from .commandUI import CommandUI from .job import Job from .reboot import Reboot from .client import Client +from .dpdkutil import check_ib, get_devices_with_compatible_driver class EulerCertification(): @@ -294,10 +295,17 @@ class EulerCertification(): except KeyError: sort_devices["infiniband"] = [device] elif interface in line and "ethernet" in line: - try: - sort_devices["ethernet"].extend([device]) - except KeyError: - sort_devices["ethernet"] = [device] + if 'connected' in line: # bug ? + try: + sort_devices["ethernet"].extend([device]) + except KeyError: + sort_devices["ethernet"] = [device] + + if check_ib(interface): # add to testcase if it's an IB card + try: + sort_devices["dpdk"].extend([device]) + except KeyError: + sort_devices["dpdk"] = [device] elif interface in line and "wifi" in line: try: sort_devices["wlan"].extend([device]) @@ -318,6 +326,21 @@ class EulerCertification(): break if device.get_property("SUBSYSTEM") == "ipmi": sort_devices["ipmi"] = [empty_device] + + # # add dpdk test devices + dpdk_devs = get_devices_with_compatible_driver() + dpdk_dev_nb = 0 + for dev in dpdk_devs: + dpdk_dev_nb += 1 + prop = dict() + prop["DEVNAME"] = dev + prop["DEVPATH"] = "" # TODO: do we need a path? + prop["PORTNB"] = dpdk_dev_nb + try: + sort_devices["dpdk"].extend([Device(prop)]) + except KeyError: + sort_devices["dpdk"] = [Device(prop)] + try: Command("dmidecode").get_str("IPMI Device Information", single_line=False) diff --git a/hwcompatible/dpdkutil.py b/hwcompatible/dpdkutil.py new file mode 100755 index 0000000..116fd99 --- /dev/null +++ b/hwcompatible/dpdkutil.py @@ -0,0 +1,141 @@ +import sys +import os +import subprocess +import argparse + +from glob import glob +from os.path import exists, basename +from os.path import join as path_join + +from hwcompatible.command import Command + +## some of the codes are ported from dpdk official repo + +network_class = {'Class': '02', 'Vendor': None, 'Device': None, + 'SVendor': None, 'SDevice': None} + +ifpga_class = {'Class': '12', 'Vendor': '8086', 'Device': '0b30', + 'SVendor': None, 'SDevice': None} + +cavium_pkx = {'Class': '08', 'Vendor': '177d', 'Device': 'a0dd,a049', + 'SVendor': None, 'SDevice': None} + +avp_vnic = {'Class': '05', 'Vendor': '1af4', 'Device': '1110', + 'SVendor': None, 'SDevice': None} + +supported_modules = ["igb_uio", "vfio-pci", "uio_pci_generic"] +network_devices = [network_class, cavium_pkx, avp_vnic, ifpga_class] + +def is_module_loaded(supported_modules): + comm = Command("lsmod") + comm.start() + + all_modules = [] + while True: + line = comm.readline() + if not line: + break + all_modules.append(line.split()[0]) + + module_found_nb = 0 + for mod in supported_modules: + if mod in all_modules: + print(mod, "found") + module_found_nb += 1 + + return not module_found_nb == 0 + +def get_devices_with_compatible_driver(): + global network_devices + global supported_modules + + pci_slots = [] + devices = get_devices(network_devices) + if len(devices) == 0: + return pci_slots + for d in devices.keys(): + if "Driver_str" in devices[d]: + if devices[d]["Driver_str"] in supported_modules: + pci_slots.append(devices[d]["Slot"]) + return pci_slots + +def is_device_bind(): + global network_devices + global supported_modules + + devices = get_devices(network_devices) + if len(devices) == 0: + print("[X] No interface detected.") + return False + for d in devices.keys(): + if "Driver_str" in devices[d]: + if devices[d]["Driver_str"] in supported_modules: + return True + print('[X] No device was bound to DPDK suported drivers.' + 'Try solving this using "dpdk-devbind.py" provided by DPDK installation') + return False + +def device_type_match(dev, devices_type): + for i in range(len(devices_type)): + param_count = len( + [x for x in devices_type[i].values() if x is not None]) + match_count = 0 + if dev["Class"][0:2] == devices_type[i]["Class"]: + match_count = match_count + 1 + for key in devices_type[i].keys(): + if key != 'Class' and devices_type[i][key]: + value_list = devices_type[i][key].split(',') + for value in value_list: + if value.strip(' ') == dev[key]: + match_count = match_count + 1 + # count must be the number of non None parameters to match + if match_count == param_count: + return True + return False + +def get_devices(device_type): + devices = {} + dev = {} + comm = Command("lspci -Dvmmnnk") + comm.start() + + while True: + line = comm.readline() + if not line: + break + + if line == '\n': + if device_type_match(dev, device_type): + if "Driver" in dev.keys(): # for consistency of key names + dev["Driver_str"] = dev.pop("Driver") + if "Module" in dev.keys(): + dev["Module_str"] = dev.pop("Module") + devices[dev["Slot"]] = dict(dev) + dev = {} + else: + line = line.strip() + name, value = line.split("\t", 1) + value_list = value.rsplit(' ', 1) + if len(value_list) == 2: + # String stored in _str + dev[name.rstrip(":") + '_str'] = value_list[0] + # Numeric IDs stored in + dev[name.rstrip(":")] = value_list[len(value_list) - 1] \ + .strip().rstrip("]").lstrip("[") + + return devices + +def check_ib(interface): + if interface == None: + return False + ib_devices = [] + pipe = Command("ls -d /sys/class/net/*/device/infiniband_verbs/uverbs* | cut -d / -f 5") + pipe.start() + while True: + line = pipe.readline() + if "No such file" in line: + break + if not line: + break + ib_devices.append(line.strip()) + return interface in ib_devices diff --git a/hwcompatible/job.py b/hwcompatible/job.py index 5630b70..808fc52 100755 --- a/hwcompatible/job.py +++ b/hwcompatible/job.py @@ -74,12 +74,12 @@ class Job(): return None sys.path.insert(0, dirpath) - try: - module = __import__(testname, globals(), locals()) - except Exception as concrete_error: - print("Error: module import failed for %s" % testname) - print(concrete_error) - return None + # try: + module = __import__(testname, globals(), locals()) + # except Exception as concrete_error: + # print("Error: module import failed for %s" % testname) + # print(concrete_error) + # return None for thing in dir(module): test_class = getattr(module, thing) diff --git a/scripts/oech b/scripts/oech index 32ebea3..7a0f7c5 100644 --- a/scripts/oech +++ b/scripts/oech @@ -1,4 +1,4 @@ -#!/usr/bin/env python +#!/usr/bin/env python3 # coding: utf-8 # Copyright (c) 2020 Huawei Technologies Co., Ltd. diff --git a/server/server.py b/server/server.py index 8da7ae5..86682ea 100755 --- a/server/server.py +++ b/server/server.py @@ -19,6 +19,8 @@ import json import time import subprocess import base64 +import sys +import re try: from urllib.parse import urlencode from urllib.request import urlopen, Request @@ -28,7 +30,7 @@ except ImportError: from urllib2 import urlopen, Request, HTTPError from flask import Flask, render_template, redirect, url_for, abort, request, \ - make_response, send_from_directory, flash + make_response, send_from_directory, flash, jsonify from flask_bootstrap import Bootstrap @@ -42,7 +44,7 @@ dir_files = os.path.join(dir_server, 'files') @app.errorhandler(400) -def bad_request(): +def bad_request(e): """ bad request """ @@ -310,6 +312,53 @@ def upload_file(): ret='Successful') +@app.route('/api/dpdk/', methods=['GET', 'POST']) +def dpdk_test_server(act): + ''' + handle dpdk server side + ''' + valid_act = ['start', 'stop'] + if act not in valid_act: + abort(400) + + if act == 'stop': + cmd = "killall -9 dpdk-testpmd" + elif act == 'start': + cmd = "dpdk-testpmd -l 0-1 -n 1 -- --forward-mode=icmpecho" + + if sys.version_info.major < 3: + pipe = subprocess.Popen(cmd, shell=True, + stdin=subprocess.PIPE, + stdout=subprocess.PIPE, + stderr=subprocess.PIPE) + else: + pipe = subprocess.Popen(cmd, shell=True, + stdin=subprocess.PIPE, + stdout=subprocess.PIPE, + stderr=subprocess.PIPE, + encoding='utf8') + time.sleep(3) + + # 0 means finish with success, None means process still running. + if pipe.poll(): + abort(400) + print(cmd) + + if act == 'start': + pattern = re.compile("Port [0-9]*: [0-9a-fA-F:]*") + while True: + line = pipe.stdout.readline() + match = pattern.match(line) + if match: + # get (one of) the MAC of address + break + mac = match.group().split(':', 1)[1].strip() + dic = {'mac': mac} + return jsonify(dic) + elif act == 'stop': + return render_template('index.html') + + @app.route('/api/', methods=['GET', 'POST']) def test_server(act): """ diff --git a/test.py b/test.py new file mode 100755 index 0000000..4fbf859 --- /dev/null +++ b/test.py @@ -0,0 +1,27 @@ +import os +import sys + +from tests.dpdk.dpdk import DPDKTest +from tests.dpdk.devbind import get_devices +from tests.dpdk.devbind import network_devices +from tests.dpdk.devbind import is_device_bind +from hwcompatible.dpdkutil import get_devices_with_compatible_driver +from hwcompatible.env import CertEnv + + +tmp = DPDKTest() + +tmp.numa = True +tmp.test_setup() + +tmp.numa = False +tmp.test_setup() + +dv = get_devices(network_devices) +assert(len([d for d in dv.keys()]) == 3) +print(dv) +is_device_bind() + +l = get_devices_with_compatible_driver() +print(l) + diff --git a/tests/dpdk/Makefile b/tests/dpdk/Makefile new file mode 100755 index 0000000..7916843 --- /dev/null +++ b/tests/dpdk/Makefile @@ -0,0 +1,28 @@ +# Copyright (c) 2020 Huawei Technologies Co., Ltd. +# oec-hardware is licensed under the Mulan PSL v2. +# You can use this software according to the terms and conditions of the Mulan PSL v2. +# You may obtain a copy of Mulan PSL v2 at: +# http://license.coscl.org.cn/MulanPSL2 +# THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, EITHER EXPRESS OR +# IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, MERCHANTABILITY OR FIT FOR A PARTICULAR +# PURPOSE. +# See the Mulan PSL v2 for more details. +# Create: 2020-04-01 + +.PHONY: install clean +SUBDIR=dpdk-native-test + +all: tx; + +tx: dpdk-native-test + $(MAKE) -C $(SUBDIR) static + +install: + mkdir -p $(DEST) + cp -a $(SUBDIR)/build *.py $(DEST) + chmod a+x $(DEST)/*.py + +clean: + rm -rf $(DEST) + + diff --git a/tests/dpdk/__init__.py b/tests/dpdk/__init__.py new file mode 100755 index 0000000..e69de29 diff --git a/tests/dpdk/dpdk-native-test/Makefile b/tests/dpdk/dpdk-native-test/Makefile new file mode 100755 index 0000000..55c5d06 --- /dev/null +++ b/tests/dpdk/dpdk-native-test/Makefile @@ -0,0 +1,43 @@ +# SPDX-License-Identifier: BSD-3-Clause +# Copyright(c) 2010-2014 Intel Corporation + +# binary name +APP = tx + +# all source are stored in SRCS-y +SRCS-y := main.c tx.c stats.c rx.c latency.c icmpecho.c + +# Build using pkg-config variables if possible +ifneq ($(shell pkg-config --exists libdpdk && echo 0),0) +$(error "no installation of DPDK found") +endif + +all: shared +.PHONY: shared static +shared: build/$(APP)-shared + ln -sf $(APP)-shared build/$(APP) +static: build/$(APP)-static + ln -sf $(APP)-static build/$(APP) + +PKGCONF ?= pkg-config + +PC_FILE := $(shell $(PKGCONF) --path libdpdk 2>/dev/null) +CFLAGS += -O3 $(shell $(PKGCONF) --cflags libdpdk) +# Add flag to allow experimental API as l2fwd uses rte_ethdev_set_ptype API +CFLAGS += -DALLOW_EXPERIMENTAL_API +LDFLAGS_SHARED = $(shell $(PKGCONF) --libs libdpdk) +LDFLAGS_STATIC = $(shell $(PKGCONF) --static --libs libdpdk) + +build/$(APP)-shared: $(SRCS-y) Makefile $(PC_FILE) | build + $(CC) $(CFLAGS) $(SRCS-y) -o $@ $(LDFLAGS) $(LDFLAGS_SHARED) + +build/$(APP)-static: $(SRCS-y) Makefile $(PC_FILE) | build + $(CC) $(CFLAGS) $(SRCS-y) -o $@ $(LDFLAGS) $(LDFLAGS_STATIC) + +build: + @mkdir -p $@ + +.PHONY: clean +clean: + rm -f build/$(APP) build/$(APP)-static build/$(APP)-shared + test -d build && rmdir -p build || true \ No newline at end of file diff --git a/tests/dpdk/dpdk-native-test/config.h b/tests/dpdk/dpdk-native-test/config.h new file mode 100755 index 0000000..8279abf --- /dev/null +++ b/tests/dpdk/dpdk-native-test/config.h @@ -0,0 +1,201 @@ +#ifndef __CONFIG_H_ +#define __CONFIG_H_ + +#include + +#include +#include +#include +#include +#include + +#define TX_DEF_PACKET_LEN 64 +/* + * The maximum number of segments per packet is used when creating + * scattered transmit packets composed of a list of mbufs. + */ +#define RTE_MAX_SEGS_PER_PKT 255 /**< nb_segs is a 8-bit unsigned char. */ +/* + * Default size of the mbuf data buffer to receive standard 1518-byte + * Ethernet frames in a mono-segment memory buffer. + */ +#define DEFAULT_MBUF_DATA_SIZE RTE_MBUF_DEFAULT_BUF_SIZE +/**< Default size of mbuf data buffer. */ + +#define MAX_PKT_BURST 512 +#define DEF_PKT_BURST 32 +#define BURST_TX_WAIT_US 1 +#define BURST_TX_RETRIES 64 +#define MIN_TX_AFTER_DELAY 1000 + + +typedef uint8_t lcoreid_t; +typedef uint16_t portid_t; +typedef uint16_t queueid_t; +typedef uint16_t streamid_t; + +uint32_t enabled_port_mask; + +/** + * The data structure associated with each port. + */ +struct rte_port { + struct rte_eth_dev_info dev_info; /**< PCI info + driver name */ + struct rte_eth_conf dev_conf; /**< Port configuration. */ + struct rte_ether_addr eth_addr; /**< Port ethernet address */ + struct rte_eth_stats stats; /**< Last port statistics */ + unsigned int socket_id; /**< For NUMA support */ + uint16_t parse_tunnel:1; /**< Parse internal headers */ + uint16_t tso_segsz; /**< Segmentation offload MSS for non-tunneled packets. */ + uint16_t tunnel_tso_segsz; /**< Segmentation offload MSS for tunneled pkts. */ + uint16_t tx_vlan_id;/**< The tag ID */ + uint16_t tx_vlan_id_outer;/**< The outer tag ID */ + uint8_t tx_queue_stats_mapping_enabled; + uint8_t rx_queue_stats_mapping_enabled; + volatile uint16_t port_status; /**< port started or not */ + uint8_t need_setup; /**< port just attached */ + uint8_t need_reconfig; /**< need reconfiguring port or not */ + uint8_t need_reconfig_queues; /**< need reconfiguring queues or not */ + uint8_t rss_flag; /**< enable rss or not */ + uint8_t dcb_flag; /**< enable dcb */ + uint16_t nb_rx_desc[RTE_MAX_QUEUES_PER_PORT+1]; /**< per queue rx desc number */ + uint16_t nb_tx_desc[RTE_MAX_QUEUES_PER_PORT+1]; /**< per queue tx desc number */ + struct rte_eth_rxconf rx_conf[RTE_MAX_QUEUES_PER_PORT+1]; /**< per queue rx configuration */ + struct rte_eth_txconf tx_conf[RTE_MAX_QUEUES_PER_PORT+1]; /**< per queue tx configuration */ + struct rte_ether_addr *mc_addr_pool; /**< pool of multicast addrs */ + uint32_t mc_addr_nb; /**< nb. of addr. in mc_addr_pool */ + uint8_t slave_flag; /**< bonding slave port */ + struct port_flow *flow_list; /**< Associated flows. */ + const struct rte_eth_rxtx_callback *rx_dump_cb[RTE_MAX_QUEUES_PER_PORT+1]; + const struct rte_eth_rxtx_callback *tx_dump_cb[RTE_MAX_QUEUES_PER_PORT+1]; +#ifdef SOFTNIC + struct softnic_port softport; /**< softnic params */ +#endif + /**< metadata value to insert in Tx packets. */ + uint32_t tx_metadata; + const struct rte_eth_rxtx_callback *tx_set_md_cb[RTE_MAX_QUEUES_PER_PORT+1]; +}; + +struct fwd_stream { + /* "read-only" data */ + portid_t rx_port; /**< port to poll for received packets */ + queueid_t rx_queue; /**< RX queue to poll on "rx_port" */ + portid_t tx_port; /**< forwarding port of received packets */ + queueid_t tx_queue; /**< TX queue to send forwarded packets */ + streamid_t peer_addr; /**< index of peer ethernet address of packets */ + + unsigned int retry_enabled; + + /* "read-write" results */ + uint64_t rx_packets; /**< received packets */ + uint64_t tx_packets; /**< received packets transmitted */ + uint64_t fwd_dropped; /**< received packets not forwarded */ + uint64_t rx_bad_ip_csum ; /**< received packets has bad ip checksum */ + uint64_t rx_bad_l4_csum ; /**< received packets has bad l4 checksum */ + uint64_t rx_bad_outer_l4_csum; + /**< received packets has bad outer l4 checksum */ + unsigned int gro_times; /**< GRO operation times */ +#ifdef RTE_TEST_PMD_RECORD_CORE_CYCLES + uint64_t core_cycles; /**< used for RX and TX processing */ +#endif +#ifdef RTE_TEST_PMD_RECORD_BURST_STATS + struct pkt_burst_stats rx_burst_stats; + struct pkt_burst_stats tx_burst_stats; +#endif + int done; +}; + +/** + * The data structure associated with each forwarding logical core. + * The logical cores are internally numbered by a core index from 0 to + * the maximum number of logical cores - 1. + * The system CPU identifier of all logical cores are setup in a global + * CPU id. configuration table. + */ +struct fwd_lcore { + struct rte_gso_ctx gso_ctx; /**< GSO context */ + struct rte_mempool *mbp; /**< The mbuf pool to use by this core */ + void *gro_ctx; /**< GRO context */ + streamid_t stream_idx; /**< index of 1st stream in "fwd_streams" */ + streamid_t stream_nb; /**< number of streams in "fwd_streams" */ + lcoreid_t cpuid_idx; /**< index of logical core in CPU id table */ + queueid_t tx_queue; /**< TX queue to send forwarded packets */ + volatile char stopped; /**< stop forwarding when set */ +}; + +/* for sharing variables */ +/* + * Configuration of packet segments used by the "txonly" processing engine. + */ +#define TXONLY_DEF_PACKET_LEN 64 +extern uint16_t tx_pkt_length; /**< Length of TXONLY packet */ +extern uint16_t tx_pkt_seg_lengths[RTE_MAX_SEGS_PER_PKT]; /**< Seg. lengths */ +extern uint8_t tx_pkt_nb_segs; /**< Number of segments in TX packets */ +extern uint16_t nb_pkt_per_burst; +extern uint32_t burst_tx_retry_num; /**< Burst tx retry number for mac-retry. */ +extern uint32_t burst_tx_delay_time; /**< Burst tx delay time(us) for mac-retry. */ + +extern struct rte_port ports[RTE_MAX_ETHPORTS]; /**< For all probed ethernet ports. */ +// extern portid_t nb_peer_eth_addrs; /**< Number of peer ethernet addresses. */ +extern struct rte_ether_addr peer_eth_addrs[RTE_MAX_ETHPORTS]; +extern struct fwd_lcore fwd_lcores; +// extern unsigned int fwd_lcores_cpuids[RTE_MAX_LCORE]; + +extern struct fwd_stream fwd_streams; +extern char *file_to_transmit; + +typedef void (*fwd_callback_t)(void *); +typedef void (*packet_fwd_t)(struct fwd_stream *fs); + +enum tx_pkt_split { + TX_PKT_SPLIT_OFF, + TX_PKT_SPLIT_ON, + TX_PKT_SPLIT_RND, +}; +extern enum tx_pkt_split tx_pkt_split; + +struct fwd_engine { + const char *fwd_mode_name; /**< Forwarding mode name. */ + fwd_callback_t port_fwd_begin; /**< NULL if nothing special to do. */ + fwd_callback_t port_fwd_end; /**< NULL if nothing special to do. */ + packet_fwd_t packet_fwd; /**< Mandatory. */ +}; + +extern struct fwd_engine tx_engine; +extern struct fwd_engine rx_engine; +extern struct fwd_engine latency_engine; +extern struct fwd_engine icmp_echo_engine; + +struct fwd_config { + struct fwd_engine *fwd_eng; + int nb_fwd_streams; /* only one in our case*/ + int nb_fwd_lcores; /* only one in our case*/ + int nb_fwd_ports; /* only one in our case*/ +} global_config; + +static inline struct fwd_lcore * +current_fwd_lcore(void) +{ + return &fwd_lcores; +} + +/* + * Work-around of a compilation error with ICC on invocations of the + * rte_be_to_cpu_16() function. + */ +#ifdef __GCC__ +#define RTE_BE_TO_CPU_16(be_16_v) rte_be_to_cpu_16((be_16_v)) +#define RTE_CPU_TO_BE_16(cpu_16_v) rte_cpu_to_be_16((cpu_16_v)) +#else +#if RTE_BYTE_ORDER == RTE_BIG_ENDIAN +#define RTE_BE_TO_CPU_16(be_16_v) (be_16_v) +#define RTE_CPU_TO_BE_16(cpu_16_v) (cpu_16_v) +#else +#define RTE_BE_TO_CPU_16(be_16_v) \ + (uint16_t) ((((be_16_v) & 0xFF) << 8) | ((be_16_v) >> 8)) +#define RTE_CPU_TO_BE_16(cpu_16_v) \ + (uint16_t) ((((cpu_16_v) & 0xFF) << 8) | ((cpu_16_v) >> 8)) +#endif +#endif /* __GCC__ */ + +#endif /* __CONFIG_H_ */ \ No newline at end of file diff --git a/tests/dpdk/dpdk-native-test/icmpecho.c b/tests/dpdk/dpdk-native-test/icmpecho.c new file mode 100755 index 0000000..9466aa6 --- /dev/null +++ b/tests/dpdk/dpdk-native-test/icmpecho.c @@ -0,0 +1,515 @@ +/* SPDX-License-Identifier: BSD-3-Clause + * Copyright(c) 2013 6WIND S.A. + */ + +#include +#include +#include +#include +#include +#include +#include + +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "config.h" + +const static int verbose_level = 0; +static const char * +arp_op_name(uint16_t arp_op) +{ + switch (arp_op) { + case RTE_ARP_OP_REQUEST: + return "ARP Request"; + case RTE_ARP_OP_REPLY: + return "ARP Reply"; + case RTE_ARP_OP_REVREQUEST: + return "Reverse ARP Request"; + case RTE_ARP_OP_REVREPLY: + return "Reverse ARP Reply"; + case RTE_ARP_OP_INVREQUEST: + return "Peer Identify Request"; + case RTE_ARP_OP_INVREPLY: + return "Peer Identify Reply"; + default: + break; + } + return "Unkwown ARP op"; +} + +static const char * +ip_proto_name(uint16_t ip_proto) +{ + static const char * ip_proto_names[] = { + "IP6HOPOPTS", /**< IP6 hop-by-hop options */ + "ICMP", /**< control message protocol */ + "IGMP", /**< group mgmt protocol */ + "GGP", /**< gateway^2 (deprecated) */ + "IPv4", /**< IPv4 encapsulation */ + + "UNASSIGNED", + "TCP", /**< transport control protocol */ + "ST", /**< Stream protocol II */ + "EGP", /**< exterior gateway protocol */ + "PIGP", /**< private interior gateway */ + + "RCC_MON", /**< BBN RCC Monitoring */ + "NVPII", /**< network voice protocol*/ + "PUP", /**< pup */ + "ARGUS", /**< Argus */ + "EMCON", /**< EMCON */ + + "XNET", /**< Cross Net Debugger */ + "CHAOS", /**< Chaos*/ + "UDP", /**< user datagram protocol */ + "MUX", /**< Multiplexing */ + "DCN_MEAS", /**< DCN Measurement Subsystems */ + + "HMP", /**< Host Monitoring */ + "PRM", /**< Packet Radio Measurement */ + "XNS_IDP", /**< xns idp */ + "TRUNK1", /**< Trunk-1 */ + "TRUNK2", /**< Trunk-2 */ + + "LEAF1", /**< Leaf-1 */ + "LEAF2", /**< Leaf-2 */ + "RDP", /**< Reliable Data */ + "IRTP", /**< Reliable Transaction */ + "TP4", /**< tp-4 w/ class negotiation */ + + "BLT", /**< Bulk Data Transfer */ + "NSP", /**< Network Services */ + "INP", /**< Merit Internodal */ + "SEP", /**< Sequential Exchange */ + "3PC", /**< Third Party Connect */ + + "IDPR", /**< InterDomain Policy Routing */ + "XTP", /**< XTP */ + "DDP", /**< Datagram Delivery */ + "CMTP", /**< Control Message Transport */ + "TPXX", /**< TP++ Transport */ + + "ILTP", /**< IL transport protocol */ + "IPv6_HDR", /**< IP6 header */ + "SDRP", /**< Source Demand Routing */ + "IPv6_RTG", /**< IP6 routing header */ + "IPv6_FRAG", /**< IP6 fragmentation header */ + + "IDRP", /**< InterDomain Routing*/ + "RSVP", /**< resource reservation */ + "GRE", /**< General Routing Encap. */ + "MHRP", /**< Mobile Host Routing */ + "BHA", /**< BHA */ + + "ESP", /**< IP6 Encap Sec. Payload */ + "AH", /**< IP6 Auth Header */ + "INLSP", /**< Integ. Net Layer Security */ + "SWIPE", /**< IP with encryption */ + "NHRP", /**< Next Hop Resolution */ + + "UNASSIGNED", + "UNASSIGNED", + "UNASSIGNED", + "ICMPv6", /**< ICMP6 */ + "IPv6NONEXT", /**< IP6 no next header */ + + "Ipv6DSTOPTS",/**< IP6 destination option */ + "AHIP", /**< any host internal protocol */ + "CFTP", /**< CFTP */ + "HELLO", /**< "hello" routing protocol */ + "SATEXPAK", /**< SATNET/Backroom EXPAK */ + + "KRYPTOLAN", /**< Kryptolan */ + "RVD", /**< Remote Virtual Disk */ + "IPPC", /**< Pluribus Packet Core */ + "ADFS", /**< Any distributed FS */ + "SATMON", /**< Satnet Monitoring */ + + "VISA", /**< VISA Protocol */ + "IPCV", /**< Packet Core Utility */ + "CPNX", /**< Comp. Prot. Net. Executive */ + "CPHB", /**< Comp. Prot. HeartBeat */ + "WSN", /**< Wang Span Network */ + + "PVP", /**< Packet Video Protocol */ + "BRSATMON", /**< BackRoom SATNET Monitoring */ + "ND", /**< Sun net disk proto (temp.) */ + "WBMON", /**< WIDEBAND Monitoring */ + "WBEXPAK", /**< WIDEBAND EXPAK */ + + "EON", /**< ISO cnlp */ + "VMTP", /**< VMTP */ + "SVMTP", /**< Secure VMTP */ + "VINES", /**< Banyon VINES */ + "TTP", /**< TTP */ + + "IGP", /**< NSFNET-IGP */ + "DGP", /**< dissimilar gateway prot. */ + "TCF", /**< TCF */ + "IGRP", /**< Cisco/GXS IGRP */ + "OSPFIGP", /**< OSPFIGP */ + + "SRPC", /**< Strite RPC protocol */ + "LARP", /**< Locus Address Resolution */ + "MTP", /**< Multicast Transport */ + "AX25", /**< AX.25 Frames */ + "4IN4", /**< IP encapsulated in IP */ + + "MICP", /**< Mobile Int.ing control */ + "SCCSP", /**< Semaphore Comm. security */ + "ETHERIP", /**< Ethernet IP encapsulation */ + "ENCAP", /**< encapsulation header */ + "AES", /**< any private encr. scheme */ + + "GMTP", /**< GMTP */ + "IPCOMP", /**< payload compression (IPComp) */ + "UNASSIGNED", + "UNASSIGNED", + "PIM", /**< Protocol Independent Mcast */ + }; + + if (ip_proto < sizeof(ip_proto_names) / sizeof(ip_proto_names[0])) + return ip_proto_names[ip_proto]; + switch (ip_proto) { +#ifdef IPPROTO_PGM + case IPPROTO_PGM: /**< PGM */ + return "PGM"; +#endif + case IPPROTO_SCTP: /**< Stream Control Transport Protocol */ + return "SCTP"; +#ifdef IPPROTO_DIVERT + case IPPROTO_DIVERT: /**< divert pseudo-protocol */ + return "DIVERT"; +#endif + case IPPROTO_RAW: /**< raw IP packet */ + return "RAW"; + default: + break; + } + return "UNASSIGNED"; +} + +static void +ipv4_addr_to_dot(uint32_t be_ipv4_addr, char *buf) +{ + uint32_t ipv4_addr; + + ipv4_addr = rte_be_to_cpu_32(be_ipv4_addr); + sprintf(buf, "%d.%d.%d.%d", (ipv4_addr >> 24) & 0xFF, + (ipv4_addr >> 16) & 0xFF, (ipv4_addr >> 8) & 0xFF, + ipv4_addr & 0xFF); +} + +static void +ether_addr_dump(const char *what, const struct rte_ether_addr *ea) +{ + char buf[RTE_ETHER_ADDR_FMT_SIZE]; + + rte_ether_format_addr(buf, RTE_ETHER_ADDR_FMT_SIZE, ea); + if (what) + printf("%s", what); + printf("%s", buf); +} + +static void +ipv4_addr_dump(const char *what, uint32_t be_ipv4_addr) +{ + char buf[16]; + + ipv4_addr_to_dot(be_ipv4_addr, buf); + if (what) + printf("%s", what); + printf("%s", buf); +} + +#define is_multicast_ipv4_addr(ipv4_addr) \ + (((rte_be_to_cpu_32((ipv4_addr)) >> 24) & 0x000000FF) == 0xE0) + +/* + * Receive a burst of packets, lookup for ICMP echo requests, and, if any, + * send back ICMP echo replies. + */ +static void +reply_to_icmp_echo_rqsts(struct fwd_stream *fs) +{ + struct rte_mbuf *pkts_burst[MAX_PKT_BURST]; + struct rte_mbuf *pkt; + struct rte_ether_hdr *eth_h; + struct rte_vlan_hdr *vlan_h; + struct rte_arp_hdr *arp_h; + struct rte_ipv4_hdr *ip_h; + struct rte_icmp_hdr *icmp_h; + struct rte_ether_addr eth_addr; + uint32_t retry; + uint32_t ip_addr; + uint16_t nb_rx; + uint16_t nb_tx; + uint16_t nb_replies; + uint16_t eth_type; + uint16_t vlan_id; + uint16_t arp_op; + uint16_t arp_pro; + uint32_t cksum; + uint8_t i; + int l2_len; +#ifdef RTE_TEST_PMD_RECORD_CORE_CYCLES + uint64_t start_tsc; + uint64_t end_tsc; + uint64_t core_cycles; +#endif + +#ifdef RTE_TEST_PMD_RECORD_CORE_CYCLES + start_tsc = rte_rdtsc(); +#endif + + /* + * First, receive a burst of packets. + */ + nb_rx = rte_eth_rx_burst(fs->rx_port, fs->rx_queue, pkts_burst, + nb_pkt_per_burst); + if (unlikely(nb_rx == 0)) + return; + +#ifdef RTE_TEST_PMD_RECORD_BURST_STATS + fs->rx_burst_stats.pkt_burst_spread[nb_rx]++; +#endif + fs->rx_packets += nb_rx; + nb_replies = 0; + for (i = 0; i < nb_rx; i++) { + if (likely(i < nb_rx - 1)) + rte_prefetch0(rte_pktmbuf_mtod(pkts_burst[i + 1], + void *)); + pkt = pkts_burst[i]; + eth_h = rte_pktmbuf_mtod(pkt, struct rte_ether_hdr *); + eth_type = RTE_BE_TO_CPU_16(eth_h->ether_type); + l2_len = sizeof(struct rte_ether_hdr); + if (verbose_level > 0) { + printf("\nPort %d pkt-len=%u nb-segs=%u\n", + fs->rx_port, pkt->pkt_len, pkt->nb_segs); + ether_addr_dump(" ETH: src=", ð_h->s_addr); + ether_addr_dump(" dst=", ð_h->d_addr); + } + if (eth_type == RTE_ETHER_TYPE_VLAN) { + vlan_h = (struct rte_vlan_hdr *) + ((char *)eth_h + sizeof(struct rte_ether_hdr)); + l2_len += sizeof(struct rte_vlan_hdr); + eth_type = rte_be_to_cpu_16(vlan_h->eth_proto); + if (verbose_level > 0) { + vlan_id = rte_be_to_cpu_16(vlan_h->vlan_tci) + & 0xFFF; + printf(" [vlan id=%u]", vlan_id); + } + } + if (verbose_level > 0) { + printf(" type=0x%04x\n", eth_type); + } + + /* Reply to ARP requests */ + if (eth_type == RTE_ETHER_TYPE_ARP) { + arp_h = (struct rte_arp_hdr *) ((char *)eth_h + l2_len); + arp_op = RTE_BE_TO_CPU_16(arp_h->arp_opcode); + arp_pro = RTE_BE_TO_CPU_16(arp_h->arp_protocol); + if (verbose_level > 0) { + printf(" ARP: hrd=%d proto=0x%04x hln=%d " + "pln=%d op=%u (%s)\n", + RTE_BE_TO_CPU_16(arp_h->arp_hardware), + arp_pro, arp_h->arp_hlen, + arp_h->arp_plen, arp_op, + arp_op_name(arp_op)); + } + if ((RTE_BE_TO_CPU_16(arp_h->arp_hardware) != + RTE_ARP_HRD_ETHER) || + (arp_pro != RTE_ETHER_TYPE_IPV4) || + (arp_h->arp_hlen != 6) || + (arp_h->arp_plen != 4) + ) { + rte_pktmbuf_free(pkt); + if (verbose_level > 0) + printf("\n"); + continue; + } + if (verbose_level > 0) { + rte_ether_addr_copy(&arp_h->arp_data.arp_sha, + ð_addr); + ether_addr_dump(" sha=", ð_addr); + ip_addr = arp_h->arp_data.arp_sip; + ipv4_addr_dump(" sip=", ip_addr); + printf("\n"); + rte_ether_addr_copy(&arp_h->arp_data.arp_tha, + ð_addr); + ether_addr_dump(" tha=", ð_addr); + ip_addr = arp_h->arp_data.arp_tip; + ipv4_addr_dump(" tip=", ip_addr); + printf("\n"); + } + if (arp_op != RTE_ARP_OP_REQUEST) { + rte_pktmbuf_free(pkt); + continue; + } + + /* + * Build ARP reply. + */ + + /* Use source MAC address as destination MAC address. */ + rte_ether_addr_copy(ð_h->s_addr, ð_h->d_addr); + /* Set source MAC address with MAC address of TX port */ + rte_ether_addr_copy(&ports[fs->tx_port].eth_addr, + ð_h->s_addr); + + arp_h->arp_opcode = rte_cpu_to_be_16(RTE_ARP_OP_REPLY); + rte_ether_addr_copy(&arp_h->arp_data.arp_tha, + ð_addr); + rte_ether_addr_copy(&arp_h->arp_data.arp_sha, + &arp_h->arp_data.arp_tha); + rte_ether_addr_copy(ð_h->s_addr, + &arp_h->arp_data.arp_sha); + + /* Swap IP addresses in ARP payload */ + ip_addr = arp_h->arp_data.arp_sip; + arp_h->arp_data.arp_sip = arp_h->arp_data.arp_tip; + arp_h->arp_data.arp_tip = ip_addr; + pkts_burst[nb_replies++] = pkt; + continue; + } + + if (eth_type != RTE_ETHER_TYPE_IPV4) { + rte_pktmbuf_free(pkt); + continue; + } + ip_h = (struct rte_ipv4_hdr *) ((char *)eth_h + l2_len); + if (verbose_level > 0) { + ipv4_addr_dump(" IPV4: src=", ip_h->src_addr); + ipv4_addr_dump(" dst=", ip_h->dst_addr); + printf(" proto=%d (%s)\n", + ip_h->next_proto_id, + ip_proto_name(ip_h->next_proto_id)); + } + + /* + * Check if packet is a ICMP echo request. + */ + icmp_h = (struct rte_icmp_hdr *) ((char *)ip_h + + sizeof(struct rte_ipv4_hdr)); + if (! ((ip_h->next_proto_id == IPPROTO_ICMP) && + (icmp_h->icmp_type == RTE_IP_ICMP_ECHO_REQUEST) && + (icmp_h->icmp_code == 0))) { + rte_pktmbuf_free(pkt); + continue; + } + + if (verbose_level > 0) + printf(" ICMP: echo request seq id=%d\n", + rte_be_to_cpu_16(icmp_h->icmp_seq_nb)); + + /* + * Prepare ICMP echo reply to be sent back. + * - switch ethernet source and destinations addresses, + * - use the request IP source address as the reply IP + * destination address, + * - if the request IP destination address is a multicast + * address: + * - choose a reply IP source address different from the + * request IP source address, + * - re-compute the IP header checksum. + * Otherwise: + * - switch the request IP source and destination + * addresses in the reply IP header, + * - keep the IP header checksum unchanged. + * - set RTE_IP_ICMP_ECHO_REPLY in ICMP header. + * ICMP checksum is computed by assuming it is valid in the + * echo request and not verified. + */ + rte_ether_addr_copy(ð_h->s_addr, ð_addr); + rte_ether_addr_copy(ð_h->d_addr, ð_h->s_addr); + rte_ether_addr_copy(ð_addr, ð_h->d_addr); + ip_addr = ip_h->src_addr; + if (is_multicast_ipv4_addr(ip_h->dst_addr)) { + uint32_t ip_src; + + ip_src = rte_be_to_cpu_32(ip_addr); + if ((ip_src & 0x00000003) == 1) + ip_src = (ip_src & 0xFFFFFFFC) | 0x00000002; + else + ip_src = (ip_src & 0xFFFFFFFC) | 0x00000001; + ip_h->src_addr = rte_cpu_to_be_32(ip_src); + ip_h->dst_addr = ip_addr; + ip_h->hdr_checksum = rte_ipv4_cksum(ip_h); + } else { + ip_h->src_addr = ip_h->dst_addr; + ip_h->dst_addr = ip_addr; + } + icmp_h->icmp_type = RTE_IP_ICMP_ECHO_REPLY; + cksum = ~icmp_h->icmp_cksum & 0xffff; + cksum += ~htons(RTE_IP_ICMP_ECHO_REQUEST << 8) & 0xffff; + cksum += htons(RTE_IP_ICMP_ECHO_REPLY << 8); + cksum = (cksum & 0xffff) + (cksum >> 16); + cksum = (cksum & 0xffff) + (cksum >> 16); + icmp_h->icmp_cksum = ~cksum; + pkts_burst[nb_replies++] = pkt; + } + + /* Send back ICMP echo replies, if any. */ + if (nb_replies > 0) { + nb_tx = rte_eth_tx_burst(fs->tx_port, fs->tx_queue, pkts_burst, + nb_replies); + /* + * Retry if necessary + */ + if (unlikely(nb_tx < nb_replies) && fs->retry_enabled) { + retry = 0; + while (nb_tx < nb_replies && + retry++ < burst_tx_retry_num) { + rte_delay_us(burst_tx_delay_time); + nb_tx += rte_eth_tx_burst(fs->tx_port, + fs->tx_queue, + &pkts_burst[nb_tx], + nb_replies - nb_tx); + } + } + fs->tx_packets += nb_tx; +#ifdef RTE_TEST_PMD_RECORD_BURST_STATS + fs->tx_burst_stats.pkt_burst_spread[nb_tx]++; +#endif + if (unlikely(nb_tx < nb_replies)) { + fs->fwd_dropped += (nb_replies - nb_tx); + do { + rte_pktmbuf_free(pkts_burst[nb_tx]); + } while (++nb_tx < nb_replies); + } + } + +#ifdef RTE_TEST_PMD_RECORD_CORE_CYCLES + end_tsc = rte_rdtsc(); + core_cycles = (end_tsc - start_tsc); + fs->core_cycles = (uint64_t) (fs->core_cycles + core_cycles); +#endif +} + +struct fwd_engine icmp_echo_engine = { + .fwd_mode_name = "icmpecho", + .port_fwd_begin = NULL, + .port_fwd_end = NULL, + .packet_fwd = reply_to_icmp_echo_rqsts, +}; \ No newline at end of file diff --git a/tests/dpdk/dpdk-native-test/latency.c b/tests/dpdk/dpdk-native-test/latency.c new file mode 100755 index 0000000..8d51429 --- /dev/null +++ b/tests/dpdk/dpdk-native-test/latency.c @@ -0,0 +1,386 @@ +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "config.h" +#include "stats.h" + +/* use RFC5735 / RFC2544 reserved network test addresses */ +static uint32_t tx_ip_src_addr = (198U << 24) | (18 << 16) | (0 << 8) | 1; +static uint32_t tx_ip_dst_addr = (198U << 24) | (18 << 16) | (0 << 8) | 2; + +#define IP_DEFTTL 64 /* from RFC 1340. */ + +static struct rte_ipv4_hdr pkt_ip_hdr; /**< IP header of transmitted packets. */ +//RTE_DEFINE_PER_LCORE(uint8_t, _ip_var); /**< IP address variation */ +struct rte_icmp_hdr pkt_icmp_hdr; /**< ICMP header of tx packets. */ + +#define TEST_ECHO_TIMES_NB 10 /* 10 burst of echo packets */ +#define TEST_INTERVAL_US 1e6 +#define PING_REQUEST_PKT_LEN 64 + +static uint64_t timer_start_tsc; +static uint64_t timer_prev_tsc; +static uint64_t timer_period; +static uint64_t timer_curr_tsc; +static uint64_t timer_diff_tsc; + +static uint64_t echo_seq_nb = 0; + +/* an array to hold all pkt send time */ +static uint64_t send_time[16]; + +static inline uint16_t +icmp_cksum(const struct rte_icmp_hdr *hdr) +{ + uint16_t cksum; + cksum = rte_raw_cksum(hdr, sizeof(struct rte_icmp_hdr)); + return (cksum == 0xffff) ? cksum : (uint16_t)~cksum; +} + +static void +copy_buf_to_pkt_segs(void* buf, unsigned len, struct rte_mbuf *pkt, + unsigned offset) +{ + struct rte_mbuf *seg; + void *seg_buf; + unsigned copy_len; + + seg = pkt; + while (offset >= seg->data_len) { + offset -= seg->data_len; + seg = seg->next; + } + copy_len = seg->data_len - offset; + seg_buf = rte_pktmbuf_mtod_offset(seg, char *, offset); + while (len > copy_len) { + rte_memcpy(seg_buf, buf, (size_t) copy_len); + len -= copy_len; + buf = ((char*) buf + copy_len); + seg = seg->next; + seg_buf = rte_pktmbuf_mtod(seg, char *); + copy_len = seg->data_len; + } + rte_memcpy(seg_buf, buf, (size_t) len); +} + +static inline void +copy_buf_to_pkt(void* buf, unsigned len, struct rte_mbuf *pkt, unsigned offset) +{ + if (offset + len <= pkt->data_len) { + rte_memcpy(rte_pktmbuf_mtod_offset(pkt, char *, offset), + buf, (size_t) len); + return; + } + copy_buf_to_pkt_segs(buf, len, pkt, offset); +} + +static void +update_icmp_hdr(struct rte_icmp_hdr *icmp_hdr) +{ + icmp_hdr->icmp_seq_nb = rte_cpu_to_be_16(echo_seq_nb); + icmp_hdr->icmp_cksum = icmp_cksum(icmp_hdr); +} + +static void +setup_pkt_icmp_ip_headers(struct rte_ipv4_hdr *ip_hdr, + struct rte_icmp_hdr *icmp_hdr, + uint16_t pkt_data_len) +{ + uint16_t pkt_len; + + /* + * Initialize ICMP header. + */ + pkt_len = (uint16_t) (pkt_data_len + sizeof(struct rte_icmp_hdr)); + icmp_hdr->icmp_type = RTE_IP_ICMP_ECHO_REQUEST; /* ping request */ + icmp_hdr->icmp_code = 0; + icmp_hdr->icmp_cksum = 0; + icmp_hdr->icmp_ident = rte_cpu_to_be_16((uint16_t) getpid()); /* TODO: add pid based identifier */ + icmp_hdr->icmp_seq_nb = 0; + + /* + * Initialize IP header. + */ + pkt_len = (uint16_t) (pkt_len + sizeof(struct rte_ipv4_hdr)); + ip_hdr->version_ihl = RTE_IPV4_VHL_DEF; + ip_hdr->type_of_service = 0; + ip_hdr->fragment_offset = 0; + ip_hdr->time_to_live = IP_DEFTTL; + ip_hdr->next_proto_id = IPPROTO_ICMP; + ip_hdr->packet_id = 0; + ip_hdr->total_length = RTE_CPU_TO_BE_16(pkt_len); + ip_hdr->src_addr = rte_cpu_to_be_32(tx_ip_src_addr); + ip_hdr->dst_addr = rte_cpu_to_be_32(tx_ip_dst_addr); + + /* + * Compute IP header checksum. + */ + ip_hdr->hdr_checksum = 0; + ip_hdr->hdr_checksum = rte_ipv4_cksum(ip_hdr); +} + +static inline bool +pkt_burst_prepare(struct rte_mbuf *pkt, struct rte_mempool *mbp, + struct rte_ether_hdr *eth_hdr, const uint16_t vlan_tci, + const uint16_t vlan_tci_outer, const uint64_t ol_flags) +{ + uint32_t nb_segs, pkt_len; + uint8_t i; + + nb_segs = 1; + + rte_pktmbuf_reset_headroom(pkt); + pkt->data_len = PING_REQUEST_PKT_LEN; + pkt->ol_flags = ol_flags; + pkt->vlan_tci = vlan_tci; + pkt->vlan_tci_outer = vlan_tci_outer; + pkt->l2_len = sizeof(struct rte_ether_hdr); + pkt->l3_len = sizeof(struct rte_ipv4_hdr); + + pkt_len = pkt->data_len; + pkt->next = NULL; + + /* + * Copy headers in first packet segment(s). + */ + copy_buf_to_pkt(eth_hdr, sizeof(*eth_hdr), pkt, 0); + copy_buf_to_pkt(&pkt_ip_hdr, sizeof(pkt_ip_hdr), pkt, + sizeof(struct rte_ether_hdr)); + // if (txonly_multi_flow) { ... + copy_buf_to_pkt(&pkt_icmp_hdr, sizeof(pkt_icmp_hdr), pkt, + sizeof(struct rte_ether_hdr) + + sizeof(struct rte_ipv4_hdr)); + + pkt->nb_segs = nb_segs; + pkt->pkt_len = pkt_len; + + return true; +} + +static bool +check_echo_response(struct rte_mbuf *buff) +{ + struct rte_ipv4_hdr *hdr; + struct rte_icmp_hdr *icmp; + + hdr = rte_pktmbuf_mtod_offset(buff, struct rte_ipv4_hdr *, + sizeof(struct rte_ether_hdr)); + if (!hdr || !hdr->next_proto_id) + return false; + if (likely(hdr->next_proto_id != IPPROTO_ICMP)) + return false; + icmp = rte_pktmbuf_mtod_offset(buff, struct rte_icmp_hdr *, + sizeof(struct rte_ether_hdr) + sizeof(struct rte_ipv4_hdr)); + if (icmp && icmp->icmp_type == RTE_IP_ICMP_ECHO_REPLY) + return true; + return false; +} + +static void +print_latency(struct rte_mbuf *buff) +{ + struct rte_icmp_hdr *icmp; + icmp = rte_pktmbuf_mtod_offset(buff, struct rte_icmp_hdr *, + sizeof(struct rte_ether_hdr) + sizeof(struct rte_ipv4_hdr)); + uint16_t seq = rte_be_to_cpu_16(icmp->icmp_seq_nb); + if (send_time[seq - 1] != 0) { + uint64_t now = rte_rdtsc(); + uint64_t lat = now - send_time[seq - 1]; + printf("rtt: %.2fms\n", 1.0 * lat / rte_get_tsc_hz() * MS_PER_S); + } else { + printf("wrong seq nb being %d!\n", seq); + } +} + +/* + * Transmit a burst of multi-segments packets. + */ +static void +pkt_burst_transmit(struct fwd_stream *fs) +{ + struct rte_mbuf *pkts_burst[MAX_PKT_BURST]; + struct rte_port *txp; + struct rte_mbuf *pkt; + struct rte_mempool *mbp; + struct rte_ether_hdr eth_hdr; + uint16_t nb_tx, nb_rx; + int i; + uint16_t nb_pkt; + uint16_t vlan_tci, vlan_tci_outer; + uint32_t retry; + uint64_t ol_flags = 0; + uint64_t tx_offloads; +#ifdef RTE_TEST_PMD_RECORD_CORE_CYCLES + uint64_t start_tsc; + uint64_t end_tsc; + uint64_t core_cycles; +#endif + +#ifdef RTE_TEST_PMD_RECORD_CORE_CYCLES + start_tsc = rte_rdtsc(); +#endif + + /** TODO: recv here */ + + struct rte_mbuf *mb; + nb_rx = rte_eth_rx_burst(fs->rx_port, fs->rx_queue, pkts_burst, + nb_pkt_per_burst); + for (i = 0; i < nb_rx; i++) { + if (likely(i < nb_rx - 1)) + rte_prefetch0(rte_pktmbuf_mtod(pkts_burst[i + 1], + void *)); + mb = pkts_burst[i]; + if (check_echo_response(mb)) { + print_latency(mb); + } + } + + for (i = 0; i < nb_rx; i++) + rte_pktmbuf_free(pkts_burst[i]); + + /* is it the time to send another? */ + timer_curr_tsc = rte_rdtsc(); + timer_diff_tsc = timer_curr_tsc - timer_prev_tsc; + if (likely(timer_diff_tsc < timer_period)) { + return; /* not yet, continue */ + } + timer_prev_tsc = timer_curr_tsc; + + echo_seq_nb++; + if (echo_seq_nb > TEST_ECHO_TIMES_NB) { + fs->done = true; + return; + } + + mbp = current_fwd_lcore()->mbp; + txp = &ports[fs->tx_port]; + tx_offloads = txp->dev_conf.txmode.offloads; + vlan_tci = txp->tx_vlan_id; + vlan_tci_outer = txp->tx_vlan_id_outer; + if (tx_offloads & DEV_TX_OFFLOAD_VLAN_INSERT) + ol_flags = PKT_TX_VLAN_PKT; + if (tx_offloads & DEV_TX_OFFLOAD_QINQ_INSERT) + ol_flags |= PKT_TX_QINQ_PKT; + if (tx_offloads & DEV_TX_OFFLOAD_MACSEC_INSERT) + ol_flags |= PKT_TX_MACSEC; + + /* + * Initialize Ethernet header. + */ + /* from ... to ... */ + rte_ether_addr_copy(&peer_eth_addrs[fs->peer_addr], ð_hdr.d_addr); + rte_ether_addr_copy(&ports[fs->tx_port].eth_addr, ð_hdr.s_addr); + eth_hdr.ether_type = rte_cpu_to_be_16(RTE_ETHER_TYPE_IPV4); + + update_icmp_hdr(&pkt_icmp_hdr); + + /* allocate a single packet */ + pkt = rte_mbuf_raw_alloc(mbp); + if (pkt == NULL) + return; + if (unlikely(!pkt_burst_prepare(pkt, mbp, ð_hdr, + vlan_tci, + vlan_tci_outer, + ol_flags))) { + rte_pktmbuf_free(pkt); + return; + } + + nb_pkt = 1; + + send_time[echo_seq_nb - 1] = rte_rdtsc(); + + nb_tx = rte_eth_tx_burst(fs->tx_port, fs->tx_queue, &pkt, 1); + /* + * Retry if necessary + */ + + // if (nb_tx < 1 && fs->retry_enabled) { + // retry = 0; + // while (nb_tx < nb_pkt && retry++ < burst_tx_retry_num) { + // rte_delay_us(burst_tx_delay_time); + // nb_tx += rte_eth_tx_burst(fs->tx_port, fs->tx_queue, + // &pkts_burst[nb_tx], nb_pkt - nb_tx); + // } + // } + + fs->tx_packets += nb_tx; + +#ifdef RTE_TEST_PMD_RECORD_BURST_STATS + fs->tx_burst_stats.pkt_burst_spread[nb_tx]++; +#endif + if (unlikely(nb_tx < nb_pkt)) { + fs->fwd_dropped += (nb_pkt - nb_tx); + do { + rte_pktmbuf_free(pkts_burst[nb_tx]); + } while (++nb_tx < nb_pkt); + } +} + +static void +latency_begin(void *arg) +{ + uint16_t pkt_data_len; + timer_period = (rte_get_tsc_hz() + US_PER_S - 1) / US_PER_S * + TEST_INTERVAL_US; + + /* for echo latency test, we only send 64-byte packets */ + const int echo_pkt_len = PING_REQUEST_PKT_LEN; + pkt_data_len = (uint16_t) (echo_pkt_len - ( + sizeof(struct rte_ether_hdr) + + sizeof(struct rte_ipv4_hdr) + + sizeof(struct rte_icmp_hdr))); + setup_pkt_icmp_ip_headers(&pkt_ip_hdr, &pkt_icmp_hdr, pkt_data_len); + timer_start_tsc = rte_rdtsc(); + timer_prev_tsc = timer_start_tsc; + // fwd_stats_reset(); +} + +static void +latency_end(void *arg) +{ + // latency_stats_display(); + // fwd_stats_display(); +} + +struct fwd_engine latency_engine = { + .fwd_mode_name = "latency", + .port_fwd_begin = latency_begin, + .port_fwd_end = latency_end, + .packet_fwd = pkt_burst_transmit, +}; diff --git a/tests/dpdk/dpdk-native-test/main.c b/tests/dpdk/dpdk-native-test/main.c new file mode 100755 index 0000000..e15bc0b --- /dev/null +++ b/tests/dpdk/dpdk-native-test/main.c @@ -0,0 +1,732 @@ +/* SPDX-License-Identifier: BSD-3-Clause + * Copyright(c) 2010-2016 Intel Corporation + */ + +/** TODO: potential bug, port 1 & port 0 have different speed */ +/** TODO: potential bug, too many droped packets are*/ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "config.h" +#include "stats.h" + +static volatile bool force_quit; + +/* MAC updating enabled by default */ + +#define RTE_LOGTYPE_L2FWD RTE_LOGTYPE_USER1 + +#define BURST_TX_DRAIN_US 100 /* TX drain every ~100us */ +#define MEMPOOL_CACHE_SIZE 256 + +/* + * Configurable number of RX/TX ring descriptors + */ +#define RTE_TEST_RX_DESC_DEFAULT 8192 /** number of rx descriptors */ +#define RTE_TEST_TX_DESC_DEFAULT 8192 /** number of tx descriptors */ +static uint16_t nb_rxd = RTE_TEST_RX_DESC_DEFAULT; +static uint16_t nb_txd = RTE_TEST_TX_DESC_DEFAULT; + +/* + * Ethernet device configuration. + */ +struct rte_eth_rxmode rx_mode = { + .max_rx_pkt_len = RTE_ETHER_MAX_LEN, + /**< Default maximum frame length. */ +}; + +struct rte_eth_txmode tx_mode = { + .offloads = DEV_TX_OFFLOAD_MBUF_FAST_FREE, +}; + +/* + * Probed Target Environment. + */ +struct fwd_lcore fwd_lcores; /**< For all probed logical cores. */ +// lcoreid_t nb_lcores; /**< Number of probed logical cores. it's 1 in our case*/ + +uint16_t nb_pkt_per_burst = DEF_PKT_BURST; +uint32_t burst_tx_retry_num = BURST_TX_RETRIES; /**< Burst tx retry number for mac-retry. */ +uint32_t burst_tx_delay_time = BURST_TX_WAIT_US; /**< Burst tx delay time(us) for mac-retry. */ + +enum tx_pkt_split tx_pkt_split = TX_PKT_SPLIT_OFF; /** we don't want to split packet */ +// unsigned int fwd_lcores_cpuids[RTE_MAX_LCORE]; /** we only use the first lcore */ + +/* + * Configuration of packet segments used by the "txonly" processing engine. + */ +uint16_t tx_pkt_length = TXONLY_DEF_PACKET_LEN; /**< TXONLY packet length. */ +uint16_t tx_pkt_seg_lengths[RTE_MAX_SEGS_PER_PKT] = { + TXONLY_DEF_PACKET_LEN, +}; +/**< Number of segments in TXONLY packets, only 1 in our case to keep it simple */ +uint8_t tx_pkt_nb_segs = 1; + + +/* + * Record the Ethernet address of peer target ports to which packets are + * forwarded. + * Must be instantiated with the ethernet addresses of peer traffic generator + * ports. + */ + +/* tables */ +struct rte_port ports[RTE_MAX_ETHPORTS]; /**< For all probed ethernet ports. */ +// portid_t nb_ports; /**< Number of probed ethernet ports. */ + +portid_t ports_ids[RTE_MAX_ETHPORTS]; /* store port ids */ +struct rte_ether_addr peer_eth_addrs[RTE_MAX_ETHPORTS]; +struct fwd_stream fwd_streams; /* we only have one stream */ +// portid_t nb_peer_eth_addrs = 0; +char *peer_addr_str; +char *file_to_transmit = NULL; + +/* Per-port statistics struct */ +struct l2fwd_port_statistics { + uint64_t tx; + uint64_t rx; + uint64_t dropped; +} __rte_cache_aligned; +struct l2fwd_port_statistics port_statistics[RTE_MAX_ETHPORTS]; + +/** TODO: + 1. do we need header split? + 2. do we need to use hw CRC support? +*/ +static void +signal_handler(int signum) { + if (signum == SIGINT || signum == SIGTERM) { + printf("\n\nSignal %d received, preparing to exit...\n", + signum); + fwd_lcores.stopped = 1; + force_quit = true; + // signal(signum, SIG_DFL); + // kill(getpid(), signum); + } +} + + +static int +start_remote_callback(void *arg) { + struct fwd_lcore *fc = (struct fwd_lcore *)arg; + packet_fwd_t packet_fwd = global_config.fwd_eng->packet_fwd; + do { + (*packet_fwd)(&fwd_streams); + if (fwd_streams.done) { + break; + } + } while (!fc->stopped); + return 0; +} + +static void +launch_pkt_fwd() { + /* initialize */ + fwd_callback_t fwd_begin = global_config.fwd_eng->port_fwd_begin; + fwd_callback_t fwd_end = global_config.fwd_eng->port_fwd_end; + int error; + if (fwd_begin) { + /* for each port */ + (*fwd_begin)(&fwd_streams); + } + + /* for now we only have one lcore, call it on master */ + // for (i = 0; i < cur_fwd_config.nb_fwd_lcores; i++) { + /* calling run_pkt_fwd_on_lcore */ + + // error = rte_eal_remote_launch(start_remote_callback, + // (void *) &fwd_lcores, fwd_lcores.cpuid_idx); + + error = start_remote_callback((void *) &fwd_lcores); + rte_delay_ms(MIN_TX_AFTER_DELAY); /* allow NIC to consume all due packets */ + + if (fwd_end) { + (*fwd_end)(NULL); + } + if (error < 0) { + rte_exit(EXIT_FAILURE, "core busy\n"); + } +} + +/* display usage */ +static void +usage(const char *prgname) +{ + printf("./%s -l 0 -n number_of_memory_channels [EAL parameters] -- [app parameters]\n" + "tx parameters: (--peer peer_mac_address) \n" + " (-l length) the length of each packet(burstlet)\n" + " (--tx-mode) for testing only. send 0 filled packets\n" + " (--latency-mode) send icmp ping requests\n" + , prgname); +} + +static int +parse_portmask(const char *portmask) +{ + char *end = NULL; + unsigned long pm; + + /* parse hexadecimal string */ + pm = strtoul(portmask, &end, 16); + if ((portmask[0] == '\0') || (end == NULL) || (*end != '\0')) + return -1; + + if (pm == 0) + return -1; + + return pm; +} + +/* Parse the argument given in the command line of the application */ +static int +tx_parse_args(int argc, char **argv) +{ + int opt, ret; + char **argvopt; + int option_index; + char *prgname = argv[0]; + + argvopt = argv; + + global_config.fwd_eng = &tx_engine; + global_config.nb_fwd_lcores = 1; + global_config.nb_fwd_streams = 1; + global_config.nb_fwd_ports = 1; + + static struct option long_options[] = { + {"peer", required_argument, NULL, 1}, + // {"src-ip", required_argument, NULL, 2}, + // {"dst-ip", required_argument, NULL, 3}, + {"pkt-len", required_argument, NULL, 'l'}, + {"rx-mode", no_argument, NULL, '1'}, + {"tx-mode", no_argument, NULL, '2'}, + {"latency-mode", no_argument, NULL, '3'}, + {"icmpecho", no_argument, NULL, '4'}, + {0, 0, 0, 0} + }; + + while ((opt = getopt_long(argc, argvopt, "l:f:p:", + long_options, &option_index)) != EOF) { + + switch (opt) { + /* portmask */ + case 'p': + enabled_port_mask = parse_portmask(optarg); + if (enabled_port_mask == 0) { + printf("invalid portmask\n"); + usage(prgname); + return -1; + } + break; + + // /* nqueue */ + // case 'q': + // /* TODO: parse nqueue here */ + // break; + /* long options */ + case 'l': + tx_pkt_length = atoi(optarg); + /* we don't split */ + tx_pkt_seg_lengths[0] = tx_pkt_length; + break; + case 'f': + file_to_transmit = optarg; + break; + + case '1': + global_config.fwd_eng = &rx_engine; + break; + case '2': + global_config.fwd_eng = &tx_engine; + break; + case '3': + global_config.fwd_eng = &latency_engine; + break; + case '4': + global_config.fwd_eng = &icmp_echo_engine; + break; + + case 1: + peer_addr_str = optarg; + break; + + default: + usage(prgname); + return -1; + } + } + + if ((global_config.fwd_eng == &tx_engine + || global_config.fwd_eng == &tx_engine) + && peer_addr_str == NULL) { + usage(prgname); + return -1; + } + + if (optind >= 0) + argv[optind-1] = prgname; + + ret = optind-1; + optind = 1; /* reset getopt lib */ + return ret; +} + +/* Check the link status of all ports in up to 9s, and print them finally */ +static void +check_all_ports_link_status(uint32_t port_mask) +{ +#define CHECK_INTERVAL 100 /* 100ms */ +#define MAX_CHECK_TIME 90 /* 9s (90 * 100ms) in total */ + uint16_t portid; + uint8_t count, all_ports_up, print_flag = 0; + struct rte_eth_link link; + int ret; + + printf("\nChecking link status"); + fflush(stdout); + for (count = 0; count <= MAX_CHECK_TIME; count++) { + if (force_quit) + return; + all_ports_up = 1; + RTE_ETH_FOREACH_DEV(portid) { + if (force_quit) + return; + if ((port_mask & (1 << portid)) == 0) + continue; + memset(&link, 0, sizeof(link)); + ret = rte_eth_link_get_nowait(portid, &link); + if (ret < 0) { + all_ports_up = 0; + if (print_flag == 1) + printf("Port %u link get failed: %s\n", + portid, rte_strerror(-ret)); + continue; + } + /* print link status if flag set */ + if (print_flag == 1) { + if (link.link_status) + printf( + "Port%d Link Up. Speed %u Mbps - %s\n", + portid, link.link_speed, + (link.link_duplex == ETH_LINK_FULL_DUPLEX) ? + ("full-duplex") : ("half-duplex\n")); + else + printf("Port %d Link Down\n", portid); + continue; + } + /* clear all_ports_up flag if any link down */ + if (link.link_status == ETH_LINK_DOWN) { + all_ports_up = 0; + break; + } + } + /* after finally printing all link status, get out */ + if (print_flag == 1) + break; + + if (all_ports_up == 0) { + printf("."); + fflush(stdout); + rte_delay_ms(CHECK_INTERVAL); + } + + /* set the print_flag if all ports up or timeout */ + if (all_ports_up == 1 || count == (MAX_CHECK_TIME - 1)) { + print_flag = 1; + printf("done\n"); + } + } +} + +// /* TODO: implement this to use multiple lcore */ +// static void +// init_fwd_lcore_config(void) +// { +// unsigned int i; +// unsigned int nb_lc = 0; +// // unsigned int sock_num; + +// for (i = 0; i < RTE_MAX_LCORE; i++) { +// if (!rte_lcore_is_enabled(i)) +// continue; +// // sock_num = rte_lcore_to_socket_id(i); +// if (i == rte_get_master_lcore()) +// continue; +// fwd_lcores_cpuids[nb_lc++] = i; +// } +// nb_lcores = (lcoreid_t) nb_lc; +// } + +static int +parse_ether_addr_str(const char *addr, struct rte_ether_addr *eth_addr) +{ + char addrbuf[18] = {0}, b[3] = {0}; + size_t len = strlen(addr); + if (len != 17) { + return -1; + } + strncpy(addrbuf, addr, 17); + addrbuf[17] = 0; + + int c = 0, byte = -0, newbyte = 0; + while (c != len) { + if (addrbuf[c] == ':') { + if (c - newbyte != 2) { + return -1; + } + strncpy(b, addrbuf + newbyte, 2); + sscanf(b, "%hhx", ð_addr->addr_bytes[byte++]); + if (c + 1 < len) { + newbyte = c + 1; + } + } + c++; + } + strncpy(b, addrbuf + newbyte, 2); + sscanf(b, "%hhx", ð_addr->addr_bytes[byte++]); + + if (byte != 6) { + return -1; + } + return 0; +} + +static void +set_def_peer_eth_addrs(void) +{ + portid_t i; + int error; + + if (peer_addr_str == NULL) + return; + for (i = 0; i < RTE_MAX_ETHPORTS; i++) { + error = parse_ether_addr_str(peer_addr_str, &peer_eth_addrs[i]); + if (error < 0) { + rte_exit(EXIT_FAILURE, "Invalid peer MAC address\n"); + } + } + + printf("Peer MAC address: %02X:%02X:%02X:%02X:%02X:%02X\n\n", + peer_eth_addrs[0].addr_bytes[0], + peer_eth_addrs[0].addr_bytes[1], + peer_eth_addrs[0].addr_bytes[2], + peer_eth_addrs[0].addr_bytes[3], + peer_eth_addrs[0].addr_bytes[4], + peer_eth_addrs[0].addr_bytes[5] + ); +} + +/* TODO: implement this to use multiple ports */ +// set_default_fwd_ports_config(void) + +static bool +check_nb_ports() +{ + int count = 0; + portid_t portid; + RTE_ETH_FOREACH_DEV(portid) { + ports_ids[count] = portid; + count++; + } + if (count != 1) { + return -1; + } + return 0; +} + + + +static void +init_fwd_lcore(void) +{ + unsigned int i, nb_mbufs; + fwd_lcores.stopped = 0; + for (i = 0; i < RTE_MAX_LCORE; i++) { + if (rte_lcore_is_enabled(i)) { + fwd_lcores.cpuid_idx = i; + break; + } + } + + nb_mbufs = RTE_MAX(1 * (nb_rxd + nb_txd + MAX_PKT_BURST + + 1 * MEMPOOL_CACHE_SIZE), 8192U); + + /* create the mbuf pool */ + fwd_lcores.mbp = rte_pktmbuf_pool_create("mbuf_pool", nb_mbufs, + MEMPOOL_CACHE_SIZE, 0, RTE_MBUF_DEFAULT_BUF_SIZE, + rte_socket_id()); + if (fwd_lcores.mbp == NULL) + rte_exit(EXIT_FAILURE, "Cannot init mbuf pool\n"); +} + +static void +init_fwd_stream(portid_t portid) { + fwd_streams.rx_port = portid; + fwd_streams.rx_queue = 0; + fwd_streams.tx_port = portid; + fwd_streams.rx_queue = 0; + fwd_streams.peer_addr = fwd_streams.tx_port; + fwd_streams.retry_enabled = 1; +} + +static void +init_port(portid_t portid) { + struct rte_eth_dev_info *dev_info; + struct rte_eth_conf *dev_conf; + struct rte_eth_rxconf *rx_conf; + struct rte_eth_txconf *tx_conf; + struct rte_port *port; + int ret; + + port = &ports[portid]; + dev_info = &(port->dev_info); + dev_conf = &(port->dev_conf); + rx_conf = &port->rx_conf[0]; + tx_conf = &port->tx_conf[0]; + + /* TODO: we only have one queue per port */ + port->nb_rx_desc[0] = RTE_TEST_RX_DESC_DEFAULT; + port->nb_tx_desc[0] = RTE_TEST_TX_DESC_DEFAULT; + port->socket_id = rte_eth_dev_socket_id(portid); + dev_conf->rx_adv_conf.rss_conf.rss_key = NULL; + dev_conf->rx_adv_conf.rss_conf.rss_hf = 0; + dev_conf->rxmode.mq_mode = ETH_MQ_RX_NONE; + + + ret = rte_eth_dev_info_get(portid, dev_info); + if (ret != 0) + rte_exit(EXIT_FAILURE, + "Error during getting device (port %u) info: %s\n", + portid, strerror(-ret)); + + if (dev_info->tx_offload_capa & DEV_TX_OFFLOAD_MBUF_FAST_FREE) + dev_conf->txmode.offloads |= + DEV_TX_OFFLOAD_MBUF_FAST_FREE; + /* port id to configure, number of rx queue for that device, + number of tx queue for that device, andd config structure */ + ret = rte_eth_dev_configure(portid, 1, 1, dev_conf); + if (ret < 0) + rte_exit(EXIT_FAILURE, "Cannot configure device: err=%d, port=%u\n", + ret, portid); + + /* Check that numbers of Rx and Tx descriptors satisfy + descriptors limits from the ethernet device information, + otherwise adjust them to boundaries. */ + ret = rte_eth_dev_adjust_nb_rx_tx_desc(portid, &port->nb_rx_desc[0], + &port->nb_tx_desc[0]); + if (ret < 0) + rte_exit(EXIT_FAILURE, + "Cannot adjust number of descriptors: err=%d, port=%u\n", + ret, portid); + + ret = rte_eth_macaddr_get(portid, &port->eth_addr); + if (ret < 0) + rte_exit(EXIT_FAILURE, + "Cannot get MAC address: err=%d, port=%u\n", + ret, portid); + + /* init one RX queue */ + fflush(stdout); + *rx_conf = dev_info->default_rxconf; + rx_conf->offloads = dev_conf->rxmode.offloads; + /* port, queue id, number of descriptor, socket id, config, + from which to allocate*/ + ret = rte_eth_rx_queue_setup(portid, 0, port->nb_rx_desc[0], + port->socket_id, + rx_conf, + fwd_lcores.mbp); + if (ret < 0) + rte_exit(EXIT_FAILURE, "rte_eth_rx_queue_setup:err=%d, port=%u\n", + ret, portid); + + /* init one TX queue on each port */ + fflush(stdout); + *tx_conf = dev_info->default_txconf; + tx_conf->offloads = dev_conf->txmode.offloads; + ret = rte_eth_tx_queue_setup(portid, 0, port->nb_tx_desc[0], + port->socket_id, + tx_conf); + if (ret < 0) + rte_exit(EXIT_FAILURE, "rte_eth_tx_queue_setup:err=%d, port=%u\n", + ret, portid); + + /* XXX what is this */ + ret = rte_eth_dev_set_ptypes(portid, RTE_PTYPE_UNKNOWN, NULL, + 0); + if (ret < 0) + printf("Port %u, Failed to disable Ptype parsing\n", + portid); + /* Start device */ + ret = rte_eth_dev_start(portid); + if (ret < 0) + rte_exit(EXIT_FAILURE, "rte_eth_dev_start:err=%d, port=%u\n", + ret, portid); + + ret = rte_eth_promiscuous_enable(portid); + if (ret != 0) + rte_exit(EXIT_FAILURE, + "rte_eth_promiscuous_enable:err=%s, port=%u\n", + rte_strerror(-ret), portid); + + printf("Port %u, MAC address: %02X:%02X:%02X:%02X:%02X:%02X\n\n", + portid, + port->eth_addr.addr_bytes[0], + port->eth_addr.addr_bytes[1], + port->eth_addr.addr_bytes[2], + port->eth_addr.addr_bytes[3], + port->eth_addr.addr_bytes[4], + port->eth_addr.addr_bytes[5]); + + map_port_queue_stats_mapping_registers(portid, port); +} + +int +main(int argc, char **argv) +{ + int ret; + uint16_t nb_ports; + uint16_t nb_ports_available = 0; + uint16_t portid; + int do_mlockall = 0; + + /* init EAL */ + ret = rte_eal_init(argc, argv); + if (ret < 0) + rte_exit(EXIT_FAILURE, "Invalid EAL arguments\n"); + argc -= ret; + argv += ret; + + force_quit = false; + signal(SIGINT, signal_handler); + signal(SIGTERM, signal_handler); + + /* on FreeBSD, mlockall() is disabled by default */ +#ifdef RTE_EXEC_ENV_FREEBSD + do_mlockall = 0; +#else + do_mlockall = 1; +#endif + + + /* parse application arguments (after the EAL ones) */ + ret = tx_parse_args(argc, argv); + if (ret < 0) + rte_exit(EXIT_FAILURE, "Invalid arguments\n"); + + if (do_mlockall && mlockall(MCL_CURRENT | MCL_FUTURE)) { + perror("mlockall failed"); + } + + nb_ports = rte_eth_dev_count_avail(); + if (nb_ports == 0) + rte_exit(EXIT_FAILURE, "No Ethernet ports - bye\n"); + + /* check port mask to possible port mask */ + if (enabled_port_mask & ~((1 << nb_ports) - 1)) + rte_exit(EXIT_FAILURE, "Invalid portmask; possible (0x%x)\n", + (1 << nb_ports) - 1); + + init_fwd_lcore(); + check_nb_ports(); + set_def_peer_eth_addrs(); + + /* Initialise each port */ + RTE_ETH_FOREACH_DEV(portid) { + /* skip port that's not enabled */ + if ((enabled_port_mask & (1 << portid)) == 0) + continue; + + nb_ports_available++; + + /* init port */ + printf("Initializing port %u... ", portid); + fflush(stdout); + init_port(portid); + + init_fwd_stream(portid); + printf("done: \n"); + + // /* Initialize TX buffers */ we don't need buffers + // tx_buffer[portid] = rte_zmalloc_socket("tx_buffer", + // RTE_ETH_TX_BUFFER_SIZE(MAX_PKT_BURST), 0, + // rte_eth_dev_socket_id(portid)); + // if (tx_buffer[portid] == NULL) + // rte_exit(EXIT_FAILURE, "Cannot allocate buffer for tx on port %u\n", + // portid); + + // rte_eth_tx_buffer_init(tx_buffer[portid], MAX_PKT_BURST); + + /* Register a specific callback to be called when an attempt is + made to send all packets buffered on an ethernet port, but + not all packets can successfully be sent */ + // ret = rte_eth_tx_buffer_set_err_callback(tx_buffer[portid], + // rte_eth_tx_buffer_count_callback, + // &port_statistics[portid].dropped); + // if (ret < 0) + // rte_exit(EXIT_FAILURE, + // "Cannot set error callback for tx buffer on port %u\n", + // portid); + } + + if (!nb_ports_available) { + rte_exit(EXIT_FAILURE, + "All available ports are disabled. Please set portmask.\n"); + } + + check_all_ports_link_status(enabled_port_mask); + + ret = 0; + + /* we run on main, no need to wait */ + launch_pkt_fwd(); + + RTE_ETH_FOREACH_DEV(portid) { + if ((enabled_port_mask & (1 << portid)) == 0) + continue; + printf("Closing port %d...", portid); + rte_eth_dev_stop(portid); + rte_eth_dev_close(portid); + printf(" Done\n"); + } + if (fwd_lcores.mbp != NULL) { + rte_mempool_free(fwd_lcores.mbp); + } + printf("Bye...\n"); + + return ret; +} diff --git a/tests/dpdk/dpdk-native-test/meson.build b/tests/dpdk/dpdk-native-test/meson.build new file mode 100755 index 0000000..50d88ca --- /dev/null +++ b/tests/dpdk/dpdk-native-test/meson.build @@ -0,0 +1,13 @@ +# SPDX-License-Identifier: BSD-3-Clause +# Copyright(c) 2017 Intel Corporation + +# meson file, for building this example as part of a main DPDK build. +# +# To build this example as a standalone application with an already-installed +# DPDK instance, use 'make' + +# Enable experimental API flag as l2fwd uses rte_ethdev_set_ptype API +allow_experimental_apis = true +sources = files( + 'main.c' +) diff --git a/tests/dpdk/dpdk-native-test/rx.c b/tests/dpdk/dpdk-native-test/rx.c new file mode 100755 index 0000000..06c2731 --- /dev/null +++ b/tests/dpdk/dpdk-native-test/rx.c @@ -0,0 +1,87 @@ +/* SPDX-License-Identifier: BSD-3-Clause + * Copyright(c) 2010-2014 Intel Corporation + */ + +#include +#include +#include +#include +#include +#include +#include + +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "config.h" +/* + * Received a burst of packets. + */ +static void +pkt_burst_receive(struct fwd_stream *fs) +{ + struct rte_mbuf *pkts_burst[MAX_PKT_BURST]; + uint16_t nb_rx; + uint16_t i; + +#ifdef RTE_TEST_PMD_RECORD_CORE_CYCLES + uint64_t start_tsc; + uint64_t end_tsc; + uint64_t core_cycles; + + start_tsc = rte_rdtsc(); +#endif + + /* + * Receive a burst of packets. + */ + nb_rx = rte_eth_rx_burst(fs->rx_port, fs->rx_queue, pkts_burst, + nb_pkt_per_burst); + if (unlikely(nb_rx == 0)) + return; + +#ifdef RTE_TEST_PMD_RECORD_BURST_STATS + fs->rx_burst_stats.pkt_burst_spread[nb_rx]++; +#endif + fs->rx_packets += nb_rx; + for (i = 0; i < nb_rx; i++) + rte_pktmbuf_free(pkts_burst[i]); + +#ifdef RTE_TEST_PMD_RECORD_CORE_CYCLES + end_tsc = rte_rdtsc(); + core_cycles = (end_tsc - start_tsc); + fs->core_cycles = (uint64_t) (fs->core_cycles + core_cycles); +#endif +} + +struct fwd_engine rx_engine = { + .fwd_mode_name = "rxonly", + .port_fwd_begin = NULL, + .port_fwd_end = NULL, + .packet_fwd = pkt_burst_receive, +}; diff --git a/tests/dpdk/dpdk-native-test/stats.c b/tests/dpdk/dpdk-native-test/stats.c new file mode 100755 index 0000000..dd5d535 --- /dev/null +++ b/tests/dpdk/dpdk-native-test/stats.c @@ -0,0 +1,435 @@ +#include +#include +#include +#include +#include +#include +#include + +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "config.h" +#include "stats.h" + + +struct queue_stats_mappings tx_queue_stats_mappings_array[MAX_TX_QUEUE_STATS_MAPPINGS]; +struct queue_stats_mappings rx_queue_stats_mappings_array[MAX_RX_QUEUE_STATS_MAPPINGS]; + +struct queue_stats_mappings *tx_queue_stats_mappings = tx_queue_stats_mappings_array; +struct queue_stats_mappings *rx_queue_stats_mappings = rx_queue_stats_mappings_array; + +uint16_t nb_tx_queue_stats_mappings = 0; +uint16_t nb_rx_queue_stats_mappings = 0; + +uint64_t start_tsc_stats; + +static int +set_tx_queue_stats_mapping_registers(portid_t port_id, struct rte_port *port) +{ + uint16_t i; + int diag; + uint8_t mapping_found = 0; + + for (i = 0; i < nb_tx_queue_stats_mappings; i++) { + if ((tx_queue_stats_mappings[i].port_id == port_id) && + (tx_queue_stats_mappings[i].queue_id < 1 /* nb_txq */)) { + diag = rte_eth_dev_set_tx_queue_stats_mapping(port_id, + tx_queue_stats_mappings[i].queue_id, + tx_queue_stats_mappings[i].stats_counter_id); + if (diag != 0) + return diag; + mapping_found = 1; + } + } + if (mapping_found) + port->tx_queue_stats_mapping_enabled = 1; + return 0; +} + +static int +set_rx_queue_stats_mapping_registers(portid_t port_id, struct rte_port *port) +{ + uint16_t i; + int diag; + uint8_t mapping_found = 0; + + for (i = 0; i < nb_rx_queue_stats_mappings; i++) { + if ((rx_queue_stats_mappings[i].port_id == port_id) && + (rx_queue_stats_mappings[i].queue_id < 1 /* nb_rxq */ )) { + diag = rte_eth_dev_set_rx_queue_stats_mapping(port_id, + rx_queue_stats_mappings[i].queue_id, + rx_queue_stats_mappings[i].stats_counter_id); + if (diag != 0) + return diag; + mapping_found = 1; + } + } + if (mapping_found) + port->rx_queue_stats_mapping_enabled = 1; + return 0; +} + +void +map_port_queue_stats_mapping_registers(portid_t pi, struct rte_port *port) +{ + int diag = 0; + + diag = set_tx_queue_stats_mapping_registers(pi, port); + if (diag != 0) { + if (diag == -ENOTSUP) { + port->tx_queue_stats_mapping_enabled = 0; + printf("TX queue stats mapping not supported port id=%d\n", pi); + } + else + rte_exit(EXIT_FAILURE, + "set_tx_queue_stats_mapping_registers " + "failed for port id=%d diag=%d\n", + pi, diag); + } + + diag = set_rx_queue_stats_mapping_registers(pi, port); + if (diag != 0) { + if (diag == -ENOTSUP) { + port->rx_queue_stats_mapping_enabled = 0; + printf("RX queue stats mapping not supported port id=%d\n", pi); + } + else + rte_exit(EXIT_FAILURE, + "set_rx_queue_stats_mapping_registers " + "failed for port id=%d diag=%d\n", + pi, diag); + } +} + +void fwd_stats_display_neat(void) +{ + struct { + struct fwd_stream *rx_stream; + struct fwd_stream *tx_stream; + uint64_t tx_dropped; + uint64_t tx_packets; + uint64_t rx_bad_ip_csum; + uint64_t rx_bad_l4_csum; + uint64_t rx_bad_outer_l4_csum; + } ports_stats[RTE_MAX_ETHPORTS]; + + uint64_t total_rx_dropped = 0; + uint64_t total_tx_dropped = 0; + uint64_t total_rx_nombuf = 0; + + struct rte_eth_stats stats; +#ifdef RTE_TEST_PMD_RECORD_CORE_CYCLES + uint64_t fwd_cycles = 0; +#endif + uint64_t total_recv = 0; + uint64_t total_xmit = 0; + struct rte_port *port; + portid_t pt_id; + + memset(ports_stats, 0, sizeof(ports_stats)); + + uint64_t curr_tsc = rte_get_tsc_cycles(); + uint64_t hz = rte_get_tsc_hz(); + uint64_t elapsed = (curr_tsc - start_tsc_stats) - hz * (MIN_TX_AFTER_DELAY) / 1000; + + struct fwd_stream *fs = &fwd_streams; + + ports_stats[fs->tx_port].tx_stream = fs; + ports_stats[fs->rx_port].rx_stream = fs; + + ports_stats[fs->tx_port].tx_dropped += fs->fwd_dropped; + ports_stats[fs->tx_port].tx_packets += fs->tx_packets; + + ports_stats[fs->rx_port].rx_bad_ip_csum += fs->rx_bad_ip_csum; + ports_stats[fs->rx_port].rx_bad_l4_csum += fs->rx_bad_l4_csum; + ports_stats[fs->rx_port].rx_bad_outer_l4_csum += + fs->rx_bad_outer_l4_csum; + + RTE_ETH_FOREACH_DEV(pt_id) { + if ((enabled_port_mask & (1 << pt_id)) == 0) + continue; + uint8_t j; + + port = &ports[pt_id]; + + rte_eth_stats_get(pt_id, &stats); + stats.ipackets -= port->stats.ipackets; + stats.opackets -= port->stats.opackets; + stats.ibytes -= port->stats.ibytes; + stats.obytes -= port->stats.obytes; + stats.imissed -= port->stats.imissed; + stats.oerrors -= port->stats.oerrors; + stats.rx_nombuf -= port->stats.rx_nombuf; + + total_recv += stats.ipackets; + total_xmit += stats.opackets; + total_rx_dropped += stats.imissed; + total_tx_dropped += ports_stats[pt_id].tx_dropped; + total_tx_dropped += stats.oerrors; + total_rx_nombuf += stats.rx_nombuf; + + printf("port %d: tx-pps: %-14.2f\n", + pt_id, + 1.0 * ports_stats[pt_id].tx_packets / elapsed * hz); + } + + printf("all: tx-pps: %-14.2f\n", 1.0 * total_xmit / elapsed * hz); +} + +void +fwd_stats_display(void) +{ + static const char *fwd_stats_border = "----------------------"; + static const char *acc_stats_border = "+++++++++++++++"; + struct { + struct fwd_stream *rx_stream; + struct fwd_stream *tx_stream; + uint64_t tx_dropped; + uint64_t tx_packets; + uint64_t rx_bad_ip_csum; + uint64_t rx_bad_l4_csum; + uint64_t rx_bad_outer_l4_csum; + } ports_stats[RTE_MAX_ETHPORTS]; + + uint64_t total_rx_dropped = 0; + uint64_t total_tx_dropped = 0; + uint64_t total_rx_nombuf = 0; + + struct rte_eth_stats stats; +#ifdef RTE_TEST_PMD_RECORD_CORE_CYCLES + uint64_t fwd_cycles = 0; +#endif + uint64_t total_recv = 0; + uint64_t total_xmit = 0; + struct rte_port *port; + portid_t pt_id; + + memset(ports_stats, 0, sizeof(ports_stats)); + + uint64_t curr_tsc = rte_get_tsc_cycles(); + uint64_t hz = rte_get_tsc_hz(); + uint64_t elapsed = (curr_tsc - start_tsc_stats) - hz * (MIN_TX_AFTER_DELAY) / 1000; + + struct fwd_stream *fs = &fwd_streams; + + ports_stats[fs->tx_port].tx_stream = fs; + ports_stats[fs->rx_port].rx_stream = fs; + + ports_stats[fs->tx_port].tx_dropped += fs->fwd_dropped; + ports_stats[fs->tx_port].tx_packets += fs->tx_packets; + + ports_stats[fs->rx_port].rx_bad_ip_csum += fs->rx_bad_ip_csum; + ports_stats[fs->rx_port].rx_bad_l4_csum += fs->rx_bad_l4_csum; + ports_stats[fs->rx_port].rx_bad_outer_l4_csum += + fs->rx_bad_outer_l4_csum; + +#ifdef RTE_TEST_PMD_RECORD_CORE_CYCLES + fwd_cycles += fs->core_cycles; +#endif + + RTE_ETH_FOREACH_DEV(pt_id) { + if ((enabled_port_mask & (1 << pt_id)) == 0) + continue; + uint8_t j; + + port = &ports[pt_id]; + + rte_eth_stats_get(pt_id, &stats); + stats.ipackets -= port->stats.ipackets; + stats.opackets -= port->stats.opackets; + stats.ibytes -= port->stats.ibytes; + stats.obytes -= port->stats.obytes; + stats.imissed -= port->stats.imissed; + stats.oerrors -= port->stats.oerrors; + stats.rx_nombuf -= port->stats.rx_nombuf; + + total_recv += stats.ipackets; + total_xmit += stats.opackets; + total_rx_dropped += stats.imissed; + total_tx_dropped += ports_stats[pt_id].tx_dropped; + total_tx_dropped += stats.oerrors; + total_rx_nombuf += stats.rx_nombuf; + + printf("\n %s Forward statistics for port %-2d %s\n", + fwd_stats_border, pt_id, fwd_stats_border); + + if (!port->rx_queue_stats_mapping_enabled && + !port->tx_queue_stats_mapping_enabled) { + printf(" RX-packets: %-14"PRIu64 + " RX-dropped: %-14"PRIu64 + "RX-total: %-"PRIu64"\n", + stats.ipackets, stats.imissed, + stats.ipackets + stats.imissed); + + // if (cur_fwd_eng == &csum_fwd_engine) + // printf(" Bad-ipcsum: %-14"PRIu64 + // " Bad-l4csum: %-14"PRIu64 + // "Bad-outer-l4csum: %-14"PRIu64"\n", + // ports_stats[pt_id].rx_bad_ip_csum, + // ports_stats[pt_id].rx_bad_l4_csum, + // ports_stats[pt_id].rx_bad_outer_l4_csum); + if (stats.ierrors + stats.rx_nombuf > 0) { + printf(" RX-error: %-"PRIu64"\n", + stats.ierrors); + printf(" RX-nombufs: %-14"PRIu64"\n", + stats.rx_nombuf); + } + + printf(" TX-packets: %-14"PRIu64 + " TX-dropped: %-14"PRIu64 + "TX-total: %-"PRIu64"\n", + ports_stats[pt_id].tx_packets, ports_stats[pt_id].tx_dropped, + ports_stats[pt_id].tx_packets + ports_stats[pt_id].tx_dropped); + printf(" RX-PPS: %-19.2f" + "TX-PPS: %-14.2f""\n", + 1.0 * stats.ipackets / elapsed * hz, + 1.0 * ports_stats[pt_id].tx_packets / elapsed * hz + ); + } else { + printf(" RX-packets: %14"PRIu64 + " RX-dropped:%14"PRIu64 + " RX-total:%14"PRIu64"\n", + stats.ipackets, stats.imissed, + stats.ipackets + stats.imissed); + + // if (cur_fwd_eng == &csum_fwd_engine) + // printf(" Bad-ipcsum:%14"PRIu64 + // " Bad-l4csum:%14"PRIu64 + // " Bad-outer-l4csum: %-14"PRIu64"\n", + // ports_stats[pt_id].rx_bad_ip_csum, + // ports_stats[pt_id].rx_bad_l4_csum, + // ports_stats[pt_id].rx_bad_outer_l4_csum); + if ((stats.ierrors + stats.rx_nombuf) > 0) { + printf(" RX-error:%"PRIu64"\n", stats.ierrors); + printf(" RX-nombufs: %14"PRIu64"\n", + stats.rx_nombuf); + } + + printf(" TX-packets: %14"PRIu64 + " TX-dropped:%14"PRIu64 + " TX-total:%14"PRIu64"\n", + stats.opackets, ports_stats[pt_id].tx_dropped, + stats.opackets + ports_stats[pt_id].tx_dropped); + printf(" RX-PPS: %14.2f" + " TX-PPS: %14.2f""\n", + 1.0 * stats.ipackets / elapsed * hz, + 1.0 * stats.opackets / elapsed * hz + ); + } + +#ifdef RTE_TEST_PMD_RECORD_BURST_STATS + if (ports_stats[pt_id].rx_stream) + pkt_burst_stats_display("RX", + &ports_stats[pt_id].rx_stream->rx_burst_stats); + if (ports_stats[pt_id].tx_stream) + pkt_burst_stats_display("TX", + &ports_stats[pt_id].tx_stream->tx_burst_stats); +#endif + + if (port->rx_queue_stats_mapping_enabled) { + printf("\n"); + for (j = 0; j < RTE_ETHDEV_QUEUE_STAT_CNTRS; j++) { + printf(" Stats reg %2d RX-packets:%14"PRIu64 + " RX-errors:%14"PRIu64 + " RX-bytes:%14"PRIu64"\n", + j, stats.q_ipackets[j], + stats.q_errors[j], stats.q_ibytes[j]); + } + printf("\n"); + } + if (port->tx_queue_stats_mapping_enabled) { + for (j = 0; j < RTE_ETHDEV_QUEUE_STAT_CNTRS; j++) { + printf(" Stats reg %2d TX-packets:%14"PRIu64 + " TX-bytes:%14" + PRIu64"\n", + j, stats.q_opackets[j], + stats.q_obytes[j]); + } + } + + printf(" %s--------------------------------%s\n", + fwd_stats_border, fwd_stats_border); + } + + printf("\n %s Accumulated forward statistics for all ports" + "%s\n", + acc_stats_border, acc_stats_border); + printf(" RX-packets: %-14"PRIu64" RX-dropped: %-14"PRIu64"RX-total: " + "%-"PRIu64"\n" + " TX-packets: %-14"PRIu64" TX-dropped: %-14"PRIu64"TX-total: " + "%-"PRIu64"\n", + total_recv, total_rx_dropped, total_recv + total_rx_dropped, + total_xmit, total_tx_dropped, total_xmit + total_tx_dropped); + if (total_rx_nombuf > 0) + printf(" RX-nombufs: %-14"PRIu64"\n", total_rx_nombuf); + printf(" %s++++++++++++++++++++++++++++++++++++++++++++++" + "%s\n", + acc_stats_border, acc_stats_border); +#ifdef RTE_TEST_PMD_RECORD_CORE_CYCLES + if (total_recv > 0) + printf("\n CPU cycles/packet=%u (total cycles=" + "%"PRIu64" / total RX packets=%"PRIu64")\n", + (unsigned int)(fwd_cycles / total_recv), + fwd_cycles, total_recv); +#endif +} + +void +fwd_stats_reset(void) +{ + portid_t portid; + + RTE_ETH_FOREACH_DEV(portid) { + rte_eth_stats_get(portid, &ports[portid].stats); + } + start_tsc_stats = rte_get_tsc_cycles(); + + // for (sm_id = 0; sm_id < cur_fwd_config.nb_fwd_streams; sm_id++) { + struct fwd_stream *fs = &fwd_streams; + fs->rx_packets = 0; + fs->tx_packets = 0; + fs->fwd_dropped = 0; + fs->rx_bad_ip_csum = 0; + fs->rx_bad_l4_csum = 0; + fs->rx_bad_outer_l4_csum = 0; + +#ifdef RTE_TEST_PMD_RECORD_BURST_STATS + memset(&fs->rx_burst_stats, 0, sizeof(fs->rx_burst_stats)); + memset(&fs->tx_burst_stats, 0, sizeof(fs->tx_burst_stats)); +#endif +#ifdef RTE_TEST_PMD_RECORD_CORE_CYCLES + fs->core_cycles = 0; +#endif +} + +void +latency_stats_display(void) +{ + printf("to be implemented."); +} \ No newline at end of file diff --git a/tests/dpdk/dpdk-native-test/stats.h b/tests/dpdk/dpdk-native-test/stats.h new file mode 100755 index 0000000..ee70e21 --- /dev/null +++ b/tests/dpdk/dpdk-native-test/stats.h @@ -0,0 +1,21 @@ +#ifndef __STATS_H +#define __STATS_H + +#define MAX_TX_QUEUE_STATS_MAPPINGS 1024 /* MAX_PORT of 32 @ 32 tx_queues/port */ +#define MAX_RX_QUEUE_STATS_MAPPINGS 4096 /* MAX_PORT of 32 @ 128 rx_queues/port */ + +struct queue_stats_mappings { + portid_t port_id; + uint16_t queue_id; + uint8_t stats_counter_id; +} __rte_cache_aligned; + +void fwd_stats_display(void); +void fwd_stats_reset(void); +void fwd_stats_display_neat(void); +void latency_stats_display(void); + + +void map_port_queue_stats_mapping_registers(portid_t pi, struct rte_port *port); + +#endif /* __STATS_H */ \ No newline at end of file diff --git a/tests/dpdk/dpdk-native-test/tx.c b/tests/dpdk/dpdk-native-test/tx.c new file mode 100755 index 0000000..725f741 --- /dev/null +++ b/tests/dpdk/dpdk-native-test/tx.c @@ -0,0 +1,338 @@ +#include +#include +#include +#include +#include +#include +#include + +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "config.h" +#include "stats.h" + +/* use RFC863 Discard Protocol */ +static uint16_t tx_udp_src_port = 9; +static uint16_t tx_udp_dst_port = 9; + +/* use RFC5735 / RFC2544 reserved network test addresses */ +static uint32_t tx_ip_src_addr = (198U << 24) | (18 << 16) | (0 << 8) | 1; +static uint32_t tx_ip_dst_addr = (198U << 24) | (18 << 16) | (0 << 8) | 2; + +#define IP_DEFTTL 64 /* from RFC 1340. */ + +static struct rte_ipv4_hdr pkt_ip_hdr; /**< IP header of transmitted packets. */ +//RTE_DEFINE_PER_LCORE(uint8_t, _ip_var); /**< IP address variation */ +static struct rte_udp_hdr pkt_udp_hdr; /**< UDP header of tx packets. */ + +#define TEST_INTERVAL_US 10e6 /* 10s of testing */ +static uint64_t timer_start_tsc; +static uint64_t timer_curr_tsc; +static uint64_t timer_period; +static uint64_t timer_diff_tsc; + +static void +copy_buf_to_pkt_segs(void* buf, unsigned len, struct rte_mbuf *pkt, + unsigned offset) +{ + struct rte_mbuf *seg; + void *seg_buf; + unsigned copy_len; + + seg = pkt; + while (offset >= seg->data_len) { + offset -= seg->data_len; + seg = seg->next; + } + copy_len = seg->data_len - offset; + seg_buf = rte_pktmbuf_mtod_offset(seg, char *, offset); + while (len > copy_len) { + rte_memcpy(seg_buf, buf, (size_t) copy_len); + len -= copy_len; + buf = ((char*) buf + copy_len); + seg = seg->next; + seg_buf = rte_pktmbuf_mtod(seg, char *); + copy_len = seg->data_len; + } + rte_memcpy(seg_buf, buf, (size_t) len); +} + +static inline void +copy_buf_to_pkt(void* buf, unsigned len, struct rte_mbuf *pkt, unsigned offset) +{ + if (offset + len <= pkt->data_len) { + rte_memcpy(rte_pktmbuf_mtod_offset(pkt, char *, offset), + buf, (size_t) len); + return; + } + copy_buf_to_pkt_segs(buf, len, pkt, offset); +} + +static void +setup_pkt_udp_ip_headers(struct rte_ipv4_hdr *ip_hdr, + struct rte_udp_hdr *udp_hdr, + uint16_t pkt_data_len) +{ + uint16_t pkt_len; + + /* + * Initialize UDP header. + */ + pkt_len = (uint16_t) (pkt_data_len + sizeof(struct rte_udp_hdr)); + udp_hdr->src_port = rte_cpu_to_be_16(tx_udp_src_port); + udp_hdr->dst_port = rte_cpu_to_be_16(tx_udp_dst_port); + udp_hdr->dgram_len = RTE_CPU_TO_BE_16(pkt_len); + udp_hdr->dgram_cksum = 0; /* No UDP checksum. */ + + /* + * Initialize IP header. + */ + pkt_len = (uint16_t) (pkt_len + sizeof(struct rte_ipv4_hdr)); + ip_hdr->version_ihl = RTE_IPV4_VHL_DEF; + ip_hdr->type_of_service = 0; + ip_hdr->fragment_offset = 0; + ip_hdr->time_to_live = IP_DEFTTL; + ip_hdr->next_proto_id = IPPROTO_UDP; + ip_hdr->packet_id = 0; + ip_hdr->total_length = RTE_CPU_TO_BE_16(pkt_len); + ip_hdr->src_addr = rte_cpu_to_be_32(tx_ip_src_addr); + ip_hdr->dst_addr = rte_cpu_to_be_32(tx_ip_dst_addr); + + /* + * Compute IP header checksum. + */ + ip_hdr->hdr_checksum = 0; + ip_hdr->hdr_checksum = rte_ipv4_cksum(ip_hdr); +} + +static inline bool +pkt_burst_prepare(struct rte_mbuf *pkt, struct rte_mempool *mbp, + struct rte_ether_hdr *eth_hdr, const uint16_t vlan_tci, + const uint16_t vlan_tci_outer, const uint64_t ol_flags) +{ + struct rte_mbuf *pkt_segs[RTE_MAX_SEGS_PER_PKT]; + struct rte_mbuf *pkt_seg; + uint32_t nb_segs, pkt_len; + uint8_t i; + + if (unlikely(tx_pkt_split == TX_PKT_SPLIT_RND)) + nb_segs = rte_rand() % tx_pkt_nb_segs + 1; + else + nb_segs = tx_pkt_nb_segs; + + if (nb_segs > 1) { + if (rte_mempool_get_bulk(mbp, (void **)pkt_segs, nb_segs - 1)) + return false; + } + + rte_pktmbuf_reset_headroom(pkt); + pkt->data_len = tx_pkt_seg_lengths[0]; + pkt->ol_flags = ol_flags; + pkt->vlan_tci = vlan_tci; + pkt->vlan_tci_outer = vlan_tci_outer; + pkt->l2_len = sizeof(struct rte_ether_hdr); + pkt->l3_len = sizeof(struct rte_ipv4_hdr); + + pkt_len = pkt->data_len; + pkt_seg = pkt; + for (i = 1; i < nb_segs; i++) { + pkt_seg->next = pkt_segs[i - 1]; + pkt_seg = pkt_seg->next; + pkt_seg->data_len = tx_pkt_seg_lengths[i]; + pkt_len += pkt_seg->data_len; + } + pkt_seg->next = NULL; /* Last segment of packet. */ + /* + * Copy headers in first packet segment(s). + */ + copy_buf_to_pkt(eth_hdr, sizeof(*eth_hdr), pkt, 0); + copy_buf_to_pkt(&pkt_ip_hdr, sizeof(pkt_ip_hdr), pkt, + sizeof(struct rte_ether_hdr)); + // if (txonly_multi_flow) { ... + copy_buf_to_pkt(&pkt_udp_hdr, sizeof(pkt_udp_hdr), pkt, + sizeof(struct rte_ether_hdr) + + sizeof(struct rte_ipv4_hdr)); + /* + * Complete first mbuf of packet and append it to the + * burst of packets to be transmitted. + */ + pkt->nb_segs = nb_segs; + pkt->pkt_len = pkt_len; + + return true; +} + +/* + * Transmit a burst of multi-segments packets. + */ +static void +pkt_burst_transmit(struct fwd_stream *fs) +{ + struct rte_mbuf *pkts_burst[MAX_PKT_BURST]; + struct rte_port *txp; + struct rte_mbuf *pkt; + struct rte_mempool *mbp; + struct rte_ether_hdr eth_hdr; + uint16_t nb_tx; + uint16_t nb_pkt; + uint16_t vlan_tci, vlan_tci_outer; + uint32_t retry; + uint64_t ol_flags = 0; + uint64_t tx_offloads; +#ifdef RTE_TEST_PMD_RECORD_CORE_CYCLES + uint64_t start_tsc; + uint64_t end_tsc; + uint64_t core_cycles; +#endif + +#ifdef RTE_TEST_PMD_RECORD_CORE_CYCLES + start_tsc = rte_rdtsc(); +#endif + + mbp = current_fwd_lcore()->mbp; + txp = &ports[fs->tx_port]; + tx_offloads = txp->dev_conf.txmode.offloads; + vlan_tci = txp->tx_vlan_id; + vlan_tci_outer = txp->tx_vlan_id_outer; + if (tx_offloads & DEV_TX_OFFLOAD_VLAN_INSERT) + ol_flags = PKT_TX_VLAN_PKT; + if (tx_offloads & DEV_TX_OFFLOAD_QINQ_INSERT) + ol_flags |= PKT_TX_QINQ_PKT; + if (tx_offloads & DEV_TX_OFFLOAD_MACSEC_INSERT) + ol_flags |= PKT_TX_MACSEC; + + /* + * Initialize Ethernet header. + */ + /* from ... to ... */ + rte_ether_addr_copy(&peer_eth_addrs[fs->peer_addr], ð_hdr.d_addr); + rte_ether_addr_copy(&ports[fs->tx_port].eth_addr, ð_hdr.s_addr); + eth_hdr.ether_type = rte_cpu_to_be_16(RTE_ETHER_TYPE_IPV4); + + if (rte_mempool_get_bulk(mbp, (void **)pkts_burst, + nb_pkt_per_burst) == 0) { + for (nb_pkt = 0; nb_pkt < nb_pkt_per_burst; nb_pkt++) { + if (unlikely(!pkt_burst_prepare(pkts_burst[nb_pkt], mbp, + ð_hdr, vlan_tci, + vlan_tci_outer, + ol_flags))) { + rte_mempool_put_bulk(mbp, + (void **)&pkts_burst[nb_pkt], + nb_pkt_per_burst - nb_pkt); + break; + } + } + } else { + for (nb_pkt = 0; nb_pkt < nb_pkt_per_burst; nb_pkt++) { + pkt = rte_mbuf_raw_alloc(mbp); + if (pkt == NULL) + break; + if (unlikely(!pkt_burst_prepare(pkt, mbp, ð_hdr, + vlan_tci, + vlan_tci_outer, + ol_flags))) { + rte_pktmbuf_free(pkt); + break; + } + pkts_burst[nb_pkt] = pkt; + } + } + + if (nb_pkt == 0) + return; + + nb_tx = rte_eth_tx_burst(fs->tx_port, fs->tx_queue, pkts_burst, nb_pkt); + /* + * Retry if necessary + */ + if (unlikely(nb_tx < nb_pkt) && fs->retry_enabled) { + retry = 0; + while (nb_tx < nb_pkt && retry++ < burst_tx_retry_num) { + rte_delay_us(burst_tx_delay_time); + nb_tx += rte_eth_tx_burst(fs->tx_port, fs->tx_queue, + &pkts_burst[nb_tx], nb_pkt - nb_tx); + } + } + fs->tx_packets += nb_tx; + + // if (txonly_multi_flow) + // RTE_PER_LCORE(_ip_var) -= nb_pkt - nb_tx; + +#ifdef RTE_TEST_PMD_RECORD_BURST_STATS + fs->tx_burst_stats.pkt_burst_spread[nb_tx]++; +#endif + if (unlikely(nb_tx < nb_pkt)) { + fs->fwd_dropped += (nb_pkt - nb_tx); + do { + rte_pktmbuf_free(pkts_burst[nb_tx]); + } while (++nb_tx < nb_pkt); + } + +#ifdef RTE_TEST_PMD_RECORD_CORE_CYCLES + end_tsc = rte_rdtsc(); + core_cycles = (end_tsc - start_tsc); + fs->core_cycles = (uint64_t) (fs->core_cycles + core_cycles); +#endif + + timer_curr_tsc = rte_rdtsc(); + timer_diff_tsc = timer_curr_tsc - timer_start_tsc; + if (unlikely(timer_diff_tsc > timer_period)) { + fs->done = true; + } +} + +static void +tx_only_begin(void *arg) +{ + uint16_t pkt_data_len; + timer_period = (rte_get_tsc_hz() + US_PER_S - 1) / US_PER_S * + TEST_INTERVAL_US; + + printf("starting... press ctrl + c to quit and see statistics\n"); + pkt_data_len = (uint16_t) (tx_pkt_length - ( + sizeof(struct rte_ether_hdr) + + sizeof(struct rte_ipv4_hdr) + + sizeof(struct rte_udp_hdr))); + setup_pkt_udp_ip_headers(&pkt_ip_hdr, &pkt_udp_hdr, pkt_data_len); + timer_start_tsc = rte_rdtsc(); + fwd_stats_reset(); +} + +static void +tx_only_end(void *arg) +{ + fwd_stats_display_neat(); +} + +struct fwd_engine tx_engine = { + .fwd_mode_name = "txonly", + .port_fwd_begin = tx_only_begin, + .port_fwd_end = tx_only_end, + .packet_fwd = pkt_burst_transmit, +}; diff --git a/tests/dpdk/dpdk.py b/tests/dpdk/dpdk.py new file mode 100755 index 0000000..15236b2 --- /dev/null +++ b/tests/dpdk/dpdk.py @@ -0,0 +1,257 @@ +import os +import argparse +import json + +try: + from urllib.parse import urlencode + from urllib.request import urlopen, Request + from urllib.error import HTTPError +except ImportError: + from urllib import urlencode + # from urllib2 import urlopen, Request, HTTPError + +from hwcompatible.test import Test +from hwcompatible.command import Command, CertCommandError +from hwcompatible.document import CertDocument +from hwcompatible.env import CertEnv + +import hugepages as hp +# import devbind as db + +# TODO: do we need vfio modules? +class DPDKTest(Test): + def __init__(self): + Test.__init__(self) + self.requirements = [] + self.subtests = [self.test_setup, self.test_speed, + self.test_latency] + self.server_ip = None + self.numa = hp.is_numa() + # list of suported DPDK drivers + self.supported_modules = ["igb_uio", "vfio-pci", "uio_pci_generic"] + self.test_dir = os.path.dirname(os.path.realpath(__file__)) + self.dut = '' # name the the device under test + self.portmask = "0xffff" + + + def setup(self, args=None): + """ + Initialization before test + :return: + """ + self.args = args or argparse.Namespace() + self.dut = getattr(self.args, 'device', None) + + if os.system("dpdk-hugepages.py --setup 2G") != 0: + print("Unable to run dpdk-hugepage script. Please check your dpdk installation.") + + devtype = self._get_dev_name_type(self.dut) + # get pci address + if devtype == 'ib': + self.pci_address = self._get_pci_of_device(self.dut) + else: + self.pci_address = self.dut.get_name() + + self.server_ip = CertDocument(CertEnv.certificationfile).get_server() + self.peermac = "" + + def test(self): + """ + test case + :return: + """ + if not self.test_setup(): + return False + + # use dpdk-testpmd icmpecho as a receive side + if not self.call_remote_server('dpdk-testpmd', 'start'): + print("[X] start dpdk-testpmd server failed." + "Please check your server configuration.") + return False + + if not self.test_speed(): + if not self.call_remote_server('dpdk-testpmd', 'stop'): + print("[X] Stop dpdk-testpmd server failed.") + return False + + if not self.test_latency(): + if not self.call_remote_server('dpdk-testpmd', 'stop'): + print("[X] Stop dpdk-testpmd server failed.") + return False + + if not self.call_remote_server('dpdk-testpmd', 'stop'): + print("[X] Stop dpdk-testpmd server failed.") + return False + + return True + + def test_setup(self): + if not self._check_hugepage_allocate(): + print("[X] No hugepage allocated.") + return False + if not self._check_hugepage_mount(): + print("[X] No hugepage mounted.") + return False + + print("[.] Hugepage successfully configured.") + self._show_hugepage() + + # if not self._check_lsmod(): + # print("[X] No required kernel module was found (uio, igb_uio or vfio).") + # return False + # print("[.] kernel module check done.") + + return True + + def test_speed(self): + '''test (single-core) DPDK speed''' + print("Please wait while speed test is running...") + self.packet_size = 1514 + try: + comm = Command("cd %s; ./build/tx -l 0 -n 1 -w %s -- --peer %s -p 0x1 -l %d --tx-mode" + % (self.test_dir, self.pci_address, self.peermac, self.packet_size)) + print(comm.command) + res = comm.get_str(regex="tx-pps: [0-9.]*", single_line=False) + pps = float(res.split(':')[-1].strip()) + print("[.] The average speed is around %f Mbps" % (8 * self.packet_size * pps / 1e6)) + except CertCommandError as concrete_error: + print(concrete_error) + print("[X] Speed test fail.\n") + return False + + return True + + def test_latency(self): + print('[+] running dpdk latency test...') + try: + # TODO: -w is deprecated since DPDK 20. I use -w for compatibility with version + # before 20. Consider using -a instead + comm = Command("cd %s; ./build/tx -l 0 -n 1 -w %s -- --peer %s -p 0x1 --latency-mode" + % (self.test_dir, self.pci_address, self.peermac)) + rttstrs = comm.get_str(regex="rtt: [0-9.]*ms", single_line=False, return_list=True) + if not rttstrs or len(rttstrs) == 0: + print("[X] no response from server.") + return False + # rtt in ms + rtt = [float(res.split(':')[-1].strip()[:-2]) for res in rttstrs] + rtt_avg = sum(rtt) / len(rtt) + print("[.] Latency test done. The average latency is around %.4f ms" % rtt_avg) + except CertCommandError as concrete_error: + print(concrete_error) + print("[X] latency test fail.") + return False + + return True + + def test_cpu_usage(self): + pass + + def setup_device(self): + pass + + def _show_hugepage(self): + if self.numa: + hp.show_numa_pages() + else: + hp.show_non_numa_pages() + + def _check_hugepage_allocate(self): + return hp.check_hugepage_allocate(self.numa) + + def _check_hugepage_mount(self): + mounted = hp.get_mountpoints() + if mounted: + return True + else: + return False + + def _check_lsmod(self): + return db.is_module_loaded(self.supported_modules) + + def call_remote_server(self, cmd, act='start'): + """ + Connect to the server somehow. + """ + form = dict() + form['cmd'] = cmd + url = 'http://%s/api/dpdk/%s' % (self.server_ip, act) + data = urlencode(form).encode('utf8') + headers = { + 'Content-type': 'application/x-www-form-urlencoded', + 'Accept': 'text/plain' + } + try: + request = Request(url, data=data, headers=headers) + response = urlopen(request) + except Exception as concrete_error: + print(concrete_error) + return False + if act == 'start': + self.peermac = json.loads(response.read())['mac'] + + print("Status: %u %s" % (response.code, response.msg)) + return int(response.code) == 200 + + # def _dev_unbind(self, interface=None): + # if interface == None: + # return + + # # os.system("dpdk-devbind.py -u %s" % (self.pci_address)) + # os.system("dpdk-devbind.py -b %s %s" % (self.old_driver, self.pci_address)) + # os.system("ip link set up %s" % (interface)) + # return + + # def _dev_bind(self, interface=None): + # if interface == None: + # return + + # drivers = ['uio_pci_generic', 'igb_uio', 'vfio_pci'] + # if os.system("modprobe uio_pci_generic"): + # print("uio_pci_generic is not supported. trying without it") + + # if os.system("ip link set down %s" % (interface)): + # print("Unable to set this device down, is this device currently in use?") + # return + + # for driver in drivers: + # if os.system("dpdk-devbind.py -b %s %s" % (driver, interface)) == 0: + # return + + # print("Bind failed. Please make sure at least one supported driver is available.") + # return + + + def _get_dev_name_type(self, device): + ''' + for ethernet devices, we use PCI address, + for IB devices, we use interface name + ''' + name = device.get_name() + if ':' in name: + return 'eth' + else: + return 'ib' + + def _get_pci_of_device(self, device): + name = device.get_name() + comm = Command("ethtool -i %s" % (name)) + comm.start() + pci = "" + while True: + line = comm.readline() + if line.split(":", 1)[0].strip() == "bus-info": + pci = line.split(":", 1)[1].strip() + break + return pci + + # def _get_driver_of_device(self, device): + # name =device.get_name() + # comm = Command("ethtool -i %s" % (name)) + # comm.start() + # driver = "" + # while True: + # line = comm.readline() + # if line.split(":", 1)[0].strip() == "driver": + # pci = line.split(":", 1)[1].strip() + # break + # return driver diff --git a/tests/dpdk/hugepages.py b/tests/dpdk/hugepages.py new file mode 100755 index 0000000..5c46a89 --- /dev/null +++ b/tests/dpdk/hugepages.py @@ -0,0 +1,76 @@ +import os +import glob +from math import log2 + +from hwcompatible.command import Command + +def fmt_memsize(kb): + '''format memsize. this is a code snippit from dpdk repo''' + BINARY_PREFIX = "KMG" + logk = int(log2(kb) / 10) + suffix = BINARY_PREFIX[logk] + unit = 2 ** (logk * 10) + return '{}{}b'.format(int(kb / unit), suffix) + +def get_mountpoints(): + '''Get list of where hugepage filesystem is mounted''' + mounted = [] + with open('/proc/mounts') as mounts: + for line in mounts: + fields = line.split() + if fields[2] != 'hugetlbfs': + continue + mounted.append(fields[1]) + return mounted + +def is_numa(): + '''Test if numa is used on this system''' + return os.path.exists('/sys/devices/system/node') + +def set_hugepage(): + pass + +def show_numa_pages(): + '''Show huge page reservations on numa system''' + print('Node Pages Size Total') + for numa_path in glob.glob('/sys/devices/system/node/node*'): + node = numa_path[29:] # slice after /sys/devices/system/node/node + path = numa_path + '/hugepages/' + for hdir in os.listdir(path): + comm = Command("cat %s" % path + hdir + '/nr_hugepages') + pages = int(comm.read()) + if pages > 0: + kb = int(hdir[10:-2]) # slice out of hugepages-NNNkB + print('{:<4} {:<5} {:<6} {}'.format(node, pages, + fmt_memsize(kb), + fmt_memsize(pages * kb))) + +def show_non_numa_pages(): + '''Show huge page reservations on non numa system''' + print('Pages Size Total') + hugepagedir = '/sys/kernel/mm/hugepages/' + for hdir in os.listdir(hugepagedir): + comm = Command("cat %s" % hugepagedir + hdir + '/nr_hugepages') + pages = int(comm.read()) + if pages > 0: + kb = int(hdir[10:-2]) + print('{:<5} {:<6} {}'.format(pages, fmt_memsize(kb), + fmt_memsize(pages * kb))) + +def check_hugepage_allocate(isnuma): + if not isnuma: + hugepagedir = '/sys/kernel/mm/hugepages/' + else: + numaid = 0 # TODO: detect numaid + hugepagedir = '/sys/devices/system/node/node%d/hugepages/' % numaid + + for (_, dirs, _) in os.walk(hugepagedir): + for directory in dirs: + comm = Command("cat %s" % hugepagedir + directory + '/nr_hugepages') + nb = comm.read() + if int(nb) != 0: + return True + break + return False + # return false when + # 1. no files in hugepagedir, 2. no non-zero entry was found diff --git a/tests/dpdk/spdk.py b/tests/dpdk/spdk.py new file mode 100755 index 0000000..7d00c3d --- /dev/null +++ b/tests/dpdk/spdk.py @@ -0,0 +1,34 @@ +import os +import time +import argparse +try: + from urllib.parse import urlencode + from urllib.request import urlopen, Request + from urllib.error import HTTPError +except ImportError: + from urllib import urlencode + from urllib2 import urlopen, Request, HTTPError + +from hwcompatible.test import Test +from hwcompatible.command import Command +from hwcompatible.document import CertDocument +from hwcompatible.env import CertEnv + +class SPDKTest(Test): + def __init__(self): + Test.__init__(self) + self.requirements = ['test-pmd'] + self.subtests = [] + self.server_ip = None + + def test_speed(self): + pass + + def test_latency(self): + pass + + def test_cpu_usage(self): + pass + + + -- Gitee From c9a8346475b8acf80cd90a79e3f8787d5697811d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E5=BC=A0=E4=BA=9A=E4=B9=90?= Date: Mon, 24 Jan 2022 22:39:46 +0000 Subject: [PATCH 2/5] update server/server.py. --- server/server.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/server/server.py b/server/server.py index 86682ea..b6f121e 100755 --- a/server/server.py +++ b/server/server.py @@ -314,9 +314,9 @@ def upload_file(): @app.route('/api/dpdk/', methods=['GET', 'POST']) def dpdk_test_server(act): - ''' + """ handle dpdk server side - ''' + """ valid_act = ['start', 'stop'] if act not in valid_act: abort(400) -- Gitee From 785499709c747418ecc6fb9869a5a2180338a11d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E5=BC=A0=E4=BA=9A=E4=B9=90?= Date: Mon, 24 Jan 2022 22:41:13 +0000 Subject: [PATCH 3/5] update hwcompatible/dpdkutil.py. --- hwcompatible/dpdkutil.py | 1 + 1 file changed, 1 insertion(+) diff --git a/hwcompatible/dpdkutil.py b/hwcompatible/dpdkutil.py index 116fd99..35f5659 100755 --- a/hwcompatible/dpdkutil.py +++ b/hwcompatible/dpdkutil.py @@ -76,6 +76,7 @@ def is_device_bind(): return False def device_type_match(dev, devices_type): + for i in range(len(devices_type)): param_count = len( [x for x in devices_type[i].values() if x is not None]) -- Gitee From 52b2abd12ca8fd74f80d4b41fc7c9e1fb14c5955 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E5=BC=A0=E4=BA=9A=E4=B9=90?= Date: Mon, 24 Jan 2022 22:46:28 +0000 Subject: [PATCH 4/5] update hwcompatible/dpdkutil.py. --- hwcompatible/dpdkutil.py | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/hwcompatible/dpdkutil.py b/hwcompatible/dpdkutil.py index 35f5659..39d282f 100755 --- a/hwcompatible/dpdkutil.py +++ b/hwcompatible/dpdkutil.py @@ -46,6 +46,7 @@ def is_module_loaded(supported_modules): return not module_found_nb == 0 def get_devices_with_compatible_driver(): + global network_devices global supported_modules @@ -60,6 +61,7 @@ def get_devices_with_compatible_driver(): return pci_slots def is_device_bind(): + global network_devices global supported_modules @@ -95,6 +97,7 @@ def device_type_match(dev, devices_type): return False def get_devices(device_type): + devices = {} dev = {} comm = Command("lspci -Dvmmnnk") @@ -127,7 +130,8 @@ def get_devices(device_type): return devices def check_ib(interface): - if interface == None: + + if interface is None: return False ib_devices = [] pipe = Command("ls -d /sys/class/net/*/device/infiniband_verbs/uverbs* | cut -d / -f 5") -- Gitee From 27d44375919fa214a61133ac5ddd441a4ccefaa3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E5=BC=A0=E4=BA=9A=E4=B9=90?= Date: Mon, 24 Jan 2022 22:49:54 +0000 Subject: [PATCH 5/5] update tests/dpdk/dpdk.py. --- tests/dpdk/dpdk.py | 19 +------------------ 1 file changed, 1 insertion(+), 18 deletions(-) diff --git a/tests/dpdk/dpdk.py b/tests/dpdk/dpdk.py index 15236b2..eefd71b 100755 --- a/tests/dpdk/dpdk.py +++ b/tests/dpdk/dpdk.py @@ -96,11 +96,6 @@ class DPDKTest(Test): print("[.] Hugepage successfully configured.") self._show_hugepage() - # if not self._check_lsmod(): - # print("[X] No required kernel module was found (uio, igb_uio or vfio).") - # return False - # print("[.] kernel module check done.") - return True def test_speed(self): @@ -242,16 +237,4 @@ class DPDKTest(Test): if line.split(":", 1)[0].strip() == "bus-info": pci = line.split(":", 1)[1].strip() break - return pci - - # def _get_driver_of_device(self, device): - # name =device.get_name() - # comm = Command("ethtool -i %s" % (name)) - # comm.start() - # driver = "" - # while True: - # line = comm.readline() - # if line.split(":", 1)[0].strip() == "driver": - # pci = line.split(":", 1)[1].strip() - # break - # return driver + return pci \ No newline at end of file -- Gitee