add examples
This commit is contained in:
parent
9e966c8e05
commit
de2cfbde73
164
examples/basicfwd/main.c
Normal file
164
examples/basicfwd/main.c
Normal file
@ -0,0 +1,164 @@
|
|||||||
|
/* SPDX-License-Identifier: BSD-3-Clause
|
||||||
|
* Copyright(c) 2010-2015 Intel Corporation
|
||||||
|
*/
|
||||||
|
#include <inttypes.h>
|
||||||
|
#include <rte_cycles.h>
|
||||||
|
#include <rte_eal.h>
|
||||||
|
#include <rte_ethdev.h>
|
||||||
|
#include <rte_lcore.h>
|
||||||
|
#include <rte_mbuf.h>
|
||||||
|
#include <stdint.h>
|
||||||
|
#define RX_RING_SIZE 1024
|
||||||
|
#define TX_RING_SIZE 1024
|
||||||
|
#define NUM_MBUFS 8191
|
||||||
|
#define MBUF_CACHE_SIZE 250
|
||||||
|
#define BURST_SIZE 32
|
||||||
|
static const struct rte_eth_conf port_conf_default = {
|
||||||
|
.rxmode =
|
||||||
|
{
|
||||||
|
.max_rx_pkt_len = RTE_ETHER_MAX_LEN,
|
||||||
|
},
|
||||||
|
};
|
||||||
|
/* basicfwd.c: Basic DPDK skeleton forwarding example. */
|
||||||
|
/*
|
||||||
|
* Initializes a given port using global settings and with the RX buffers
|
||||||
|
* coming from the mbuf_pool passed as a parameter.
|
||||||
|
*/
|
||||||
|
static inline int port_init(uint16_t port, struct rte_mempool* mbuf_pool) {
|
||||||
|
struct rte_eth_conf port_conf = port_conf_default;
|
||||||
|
const uint16_t rx_rings = 1, tx_rings = 1;
|
||||||
|
uint16_t nb_rxd = RX_RING_SIZE;
|
||||||
|
uint16_t nb_txd = TX_RING_SIZE;
|
||||||
|
int retval;
|
||||||
|
uint16_t q;
|
||||||
|
struct rte_eth_dev_info dev_info;
|
||||||
|
struct rte_eth_txconf txconf;
|
||||||
|
if (!rte_eth_dev_is_valid_port(port))
|
||||||
|
return -1;
|
||||||
|
retval = rte_eth_dev_info_get(port, &dev_info);
|
||||||
|
if (retval != 0) {
|
||||||
|
printf("Error during getting device (port %u) info: %s\n", port,
|
||||||
|
strerror(-retval));
|
||||||
|
return retval;
|
||||||
|
}
|
||||||
|
if (dev_info.tx_offload_capa & DEV_TX_OFFLOAD_MBUF_FAST_FREE)
|
||||||
|
port_conf.txmode.offloads |= DEV_TX_OFFLOAD_MBUF_FAST_FREE;
|
||||||
|
/* Configure the Ethernet device. */
|
||||||
|
retval = rte_eth_dev_configure(port, rx_rings, tx_rings, &port_conf);
|
||||||
|
if (retval != 0)
|
||||||
|
return retval;
|
||||||
|
retval = rte_eth_dev_adjust_nb_rx_tx_desc(port, &nb_rxd, &nb_txd);
|
||||||
|
if (retval != 0)
|
||||||
|
return retval;
|
||||||
|
/* Allocate and set up 1 RX queue per Ethernet port. */
|
||||||
|
for (q = 0; q < rx_rings; q++) {
|
||||||
|
retval = rte_eth_rx_queue_setup(
|
||||||
|
port, q, nb_rxd, rte_eth_dev_socket_id(port), NULL, mbuf_pool);
|
||||||
|
if (retval < 0)
|
||||||
|
return retval;
|
||||||
|
}
|
||||||
|
txconf = dev_info.default_txconf;
|
||||||
|
txconf.offloads = port_conf.txmode.offloads;
|
||||||
|
/* Allocate and set up 1 TX queue per Ethernet port. */
|
||||||
|
for (q = 0; q < tx_rings; q++) {
|
||||||
|
retval = rte_eth_tx_queue_setup(port, q, nb_txd,
|
||||||
|
rte_eth_dev_socket_id(port), &txconf);
|
||||||
|
if (retval < 0)
|
||||||
|
return retval;
|
||||||
|
}
|
||||||
|
/* Start the Ethernet port. */
|
||||||
|
retval = rte_eth_dev_start(port);
|
||||||
|
if (retval < 0)
|
||||||
|
return retval;
|
||||||
|
/* Display the port MAC address. */
|
||||||
|
struct rte_ether_addr addr;
|
||||||
|
retval = rte_eth_macaddr_get(port, &addr);
|
||||||
|
if (retval != 0)
|
||||||
|
return retval;
|
||||||
|
printf("Port %u MAC: %02" PRIx8 " %02" PRIx8 " %02" PRIx8 " %02" PRIx8
|
||||||
|
" %02" PRIx8 " %02" PRIx8 "\n",
|
||||||
|
port, addr.addr_bytes[0], addr.addr_bytes[1], addr.addr_bytes[2],
|
||||||
|
addr.addr_bytes[3], addr.addr_bytes[4], addr.addr_bytes[5]);
|
||||||
|
/* Enable RX in promiscuous mode for the Ethernet device. */
|
||||||
|
retval = rte_eth_promiscuous_enable(port);
|
||||||
|
if (retval != 0)
|
||||||
|
return retval;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
/*
|
||||||
|
* The lcore main. This is the main thread that does the work, reading from
|
||||||
|
* an input port and writing to an output port.
|
||||||
|
*/
|
||||||
|
static __rte_noreturn void lcore_main(void) {
|
||||||
|
uint16_t port;
|
||||||
|
/*
|
||||||
|
* Check that the port is on the same NUMA node as the polling thread
|
||||||
|
* for best performance.
|
||||||
|
*/
|
||||||
|
RTE_ETH_FOREACH_DEV(port)
|
||||||
|
if (rte_eth_dev_socket_id(port) >= 0 &&
|
||||||
|
rte_eth_dev_socket_id(port) != (int)rte_socket_id())
|
||||||
|
printf("WARNING, port %u is on remote NUMA node to "
|
||||||
|
"polling thread.\n\tPerformance will "
|
||||||
|
"not be optimal.\n",
|
||||||
|
port);
|
||||||
|
printf("\nCore %u forwarding packets. [Ctrl+C to quit]\n", rte_lcore_id());
|
||||||
|
/* Run until the application is quit or killed. */
|
||||||
|
for (;;) {
|
||||||
|
/*
|
||||||
|
* Receive packets on a port and forward them on the paired
|
||||||
|
* port. The mapping is 0 -> 1, 1 -> 0, 2 -> 3, 3 -> 2, etc.
|
||||||
|
*/
|
||||||
|
RTE_ETH_FOREACH_DEV(port) {
|
||||||
|
/* Get burst of RX packets, from first port of pair. */
|
||||||
|
struct rte_mbuf* bufs[BURST_SIZE];
|
||||||
|
const uint16_t nb_rx = rte_eth_rx_burst(port, 0, bufs, BURST_SIZE);
|
||||||
|
if (unlikely(nb_rx == 0))
|
||||||
|
continue;
|
||||||
|
/* Send burst of TX packets, to second port of pair. */
|
||||||
|
const uint16_t nb_tx = rte_eth_tx_burst(port ^ 1, 0, bufs, nb_rx);
|
||||||
|
/* Free any unsent packets. */
|
||||||
|
if (unlikely(nb_tx < nb_rx)) {
|
||||||
|
uint16_t buf;
|
||||||
|
for (buf = nb_tx; buf < nb_rx; buf++)
|
||||||
|
rte_pktmbuf_free(bufs[buf]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
/*
|
||||||
|
* The main function, which does initialization and calls the per-lcore
|
||||||
|
* functions.
|
||||||
|
*/
|
||||||
|
int main(int argc, char* argv[]) {
|
||||||
|
struct rte_mempool* mbuf_pool;
|
||||||
|
unsigned nb_ports;
|
||||||
|
uint16_t portid;
|
||||||
|
/* Initialize the Environment Abstraction Layer (EAL). */
|
||||||
|
int ret = rte_eal_init(argc, argv);
|
||||||
|
if (ret < 0)
|
||||||
|
rte_exit(EXIT_FAILURE, "Error with EAL initialization\n");
|
||||||
|
argc -= ret;
|
||||||
|
argv += ret;
|
||||||
|
/* Check that there is an even number of ports to send/receive on. */
|
||||||
|
nb_ports = rte_eth_dev_count_avail();
|
||||||
|
if (nb_ports < 2 || (nb_ports & 1))
|
||||||
|
rte_exit(EXIT_FAILURE, "Error: number of ports must be even\n");
|
||||||
|
/* Creates a new mempool in memory to hold the mbufs. */
|
||||||
|
mbuf_pool = rte_pktmbuf_pool_create(
|
||||||
|
"MBUF_POOL", NUM_MBUFS * nb_ports, MBUF_CACHE_SIZE, 0,
|
||||||
|
RTE_MBUF_DEFAULT_BUF_SIZE, rte_socket_id());
|
||||||
|
if (mbuf_pool == NULL)
|
||||||
|
rte_exit(EXIT_FAILURE, "Cannot create mbuf pool\n");
|
||||||
|
/* Initialize all ports. */
|
||||||
|
RTE_ETH_FOREACH_DEV(portid)
|
||||||
|
if (port_init(portid, mbuf_pool) != 0)
|
||||||
|
rte_exit(EXIT_FAILURE, "Cannot init port %" PRIu16 "\n", portid);
|
||||||
|
if (rte_lcore_count() > 1)
|
||||||
|
printf("\nWARNING: Too many lcores enabled. Only 1 used.\n");
|
||||||
|
/* Call lcore_main on the main core only. */
|
||||||
|
lcore_main();
|
||||||
|
/* clean up the EAL */
|
||||||
|
rte_eal_cleanup();
|
||||||
|
return 0;
|
||||||
|
}
|
5
examples/basicfwd/meson.build
Normal file
5
examples/basicfwd/meson.build
Normal file
@ -0,0 +1,5 @@
|
|||||||
|
project('dpdk-app', 'c')
|
||||||
|
|
||||||
|
dpdk = dependency('libdpdk')
|
||||||
|
sources = files('main.c')
|
||||||
|
executable('dpdk-app', sources, dependencies: dpdk)
|
81
examples/helloworld/main.c
Normal file
81
examples/helloworld/main.c
Normal file
@ -0,0 +1,81 @@
|
|||||||
|
|
||||||
|
/* SPDX-License-Identifier: BSD-3-Clause
|
||||||
|
* Copyright(c) 2010-2014 Intel Corporation
|
||||||
|
*/
|
||||||
|
#include <errno.h>
|
||||||
|
#include <rte_debug.h>
|
||||||
|
#include <rte_eal.h>
|
||||||
|
#include <rte_launch.h>
|
||||||
|
#include <rte_lcore.h>
|
||||||
|
#include <rte_memory.h>
|
||||||
|
#include <rte_per_lcore.h>
|
||||||
|
#include <stdint.h>
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <string.h>
|
||||||
|
#include <sys/queue.h>
|
||||||
|
#include <rte_cycles.h>
|
||||||
|
|
||||||
|
static int lcore_hello(__rte_unused void *arg) {
|
||||||
|
unsigned lcore_id;
|
||||||
|
lcore_id = rte_lcore_id();
|
||||||
|
printf("hello from core %u\n", lcore_id);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
int main(int argc, char **argv) {
|
||||||
|
int socket_count;
|
||||||
|
int lcore_count;
|
||||||
|
int ret;
|
||||||
|
unsigned lcore_id;
|
||||||
|
ret = rte_eal_init(argc, argv);
|
||||||
|
if (ret < 0)
|
||||||
|
rte_panic("Cannot init EAL\n");
|
||||||
|
|
||||||
|
/* call lcore_hello() on every worker lcore */
|
||||||
|
RTE_LCORE_FOREACH_WORKER(lcore_id) {
|
||||||
|
rte_eal_remote_launch(lcore_hello, NULL, lcore_id);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* call it on main lcore too */
|
||||||
|
lcore_hello(NULL);
|
||||||
|
|
||||||
|
// print socket count
|
||||||
|
socket_count = rte_socket_count();
|
||||||
|
printf("number of sockets:%i", socket_count);
|
||||||
|
|
||||||
|
// print lcore count
|
||||||
|
lcore_count = rte_lcore_count();
|
||||||
|
printf("number of lcores:%i", lcore_count);
|
||||||
|
|
||||||
|
// test timer
|
||||||
|
uint32_t seconds = 0;
|
||||||
|
uint64_t cycles_old = rte_get_tsc_cycles();
|
||||||
|
for (;;) {
|
||||||
|
uint64_t hz = rte_get_tsc_hz();
|
||||||
|
uint64_t cycles = rte_get_tsc_cycles();
|
||||||
|
uint64_t delta_cycles = cycles - cycles_old;
|
||||||
|
|
||||||
|
if (delta_cycles >= hz) {
|
||||||
|
++seconds;
|
||||||
|
cycles_old = cycles - (delta_cycles % hz);
|
||||||
|
}
|
||||||
|
|
||||||
|
printf("seconds : %u\n", seconds);
|
||||||
|
}
|
||||||
|
|
||||||
|
rte_eal_mp_wait_lcore();
|
||||||
|
|
||||||
|
/* clean up the EAL */
|
||||||
|
rte_eal_cleanup();
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
uint64_t int_divide(uint64_t a, uint64_t b) {
|
||||||
|
uint64_t c = 0;
|
||||||
|
while (a >= b) {
|
||||||
|
a -= b;
|
||||||
|
++c;
|
||||||
|
}
|
||||||
|
|
||||||
|
return c;
|
||||||
|
}
|
112
examples/helloworld/main.cpp
Normal file
112
examples/helloworld/main.cpp
Normal file
@ -0,0 +1,112 @@
|
|||||||
|
|
||||||
|
/* SPDX-License-Identifier: BSD-3-Clause
|
||||||
|
* Copyright(c) 2010-2014 Intel Corporation
|
||||||
|
*/
|
||||||
|
#include <chrono>
|
||||||
|
#include <cmath>
|
||||||
|
#include <errno.h>
|
||||||
|
#include <iostream>
|
||||||
|
#include <rte_cycles.h>
|
||||||
|
#include <rte_debug.h>
|
||||||
|
#include <rte_eal.h>
|
||||||
|
#include <rte_launch.h>
|
||||||
|
#include <rte_lcore.h>
|
||||||
|
#include <rte_memory.h>
|
||||||
|
#include <rte_per_lcore.h>
|
||||||
|
#include <stdint.h>
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <string.h>
|
||||||
|
#include <sys/queue.h>
|
||||||
|
|
||||||
|
static int lcore_hello(__rte_unused void* arg) {
|
||||||
|
unsigned lcore_id;
|
||||||
|
lcore_id = rte_lcore_id();
|
||||||
|
printf("hello from core %u\n", lcore_id);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
int main(int argc, char** argv) {
|
||||||
|
int socket_count;
|
||||||
|
int lcore_count;
|
||||||
|
int ret;
|
||||||
|
unsigned lcore_id;
|
||||||
|
ret = rte_eal_init(argc, argv);
|
||||||
|
if (ret < 0)
|
||||||
|
rte_panic("Cannot init EAL\n");
|
||||||
|
|
||||||
|
/* call lcore_hello() on every worker lcore */
|
||||||
|
RTE_LCORE_FOREACH_WORKER(lcore_id) {
|
||||||
|
rte_eal_remote_launch(lcore_hello, NULL, lcore_id);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* call it on main lcore too */
|
||||||
|
lcore_hello(NULL);
|
||||||
|
|
||||||
|
// print socket count
|
||||||
|
socket_count = rte_socket_count();
|
||||||
|
printf("number of sockets:%i", socket_count);
|
||||||
|
|
||||||
|
// print lcore count
|
||||||
|
lcore_count = rte_lcore_count();
|
||||||
|
printf("number of lcores:%i", lcore_count);
|
||||||
|
|
||||||
|
// test timer
|
||||||
|
int hz_mean = 0;
|
||||||
|
int n = 1;
|
||||||
|
int hz_cycles = -1;
|
||||||
|
|
||||||
|
std::chrono::time_point<std::chrono::system_clock> start, end;
|
||||||
|
|
||||||
|
start = std::chrono::system_clock::now();
|
||||||
|
end = std::chrono::system_clock::now();
|
||||||
|
std::chrono::duration<double> elapsed_seconds = end - start;
|
||||||
|
std::chrono::seconds sec(30);
|
||||||
|
|
||||||
|
do {
|
||||||
|
hz_mean = (hz_mean + rte_get_tsc_hz() / n) * n / (n + 1);
|
||||||
|
end = std::chrono::system_clock::now();
|
||||||
|
elapsed_seconds = end - start;
|
||||||
|
} while (elapsed_seconds <= sec);
|
||||||
|
|
||||||
|
int cycles_old = rte_get_tsc_cycles();
|
||||||
|
do {
|
||||||
|
end = std::chrono::system_clock::now();
|
||||||
|
elapsed_seconds = end - start;
|
||||||
|
} while (elapsed_seconds <= sec);
|
||||||
|
|
||||||
|
hz_cycles = (rte_get_tsc_cycles() - cycles_old) / 30;
|
||||||
|
|
||||||
|
std::cout << std::endl << "hz : " << rte_get_tsc_hz() << std::endl;
|
||||||
|
std::cout << "hz_cycles : " << hz_cycles << std::endl;
|
||||||
|
std::cout << "hz_mean : " << hz_mean << std::endl;
|
||||||
|
|
||||||
|
int length = 1000;
|
||||||
|
int hz_cycles_diff[length];
|
||||||
|
int hz_mean_diff[length];
|
||||||
|
int hz_cycles_diff_max = -1;
|
||||||
|
int hz_mean_diff_max = -1;
|
||||||
|
int hz = -1;
|
||||||
|
for (int i = 0; i < length; i++) {
|
||||||
|
hz = rte_get_tsc_hz();
|
||||||
|
|
||||||
|
hz_cycles_diff[i] = abs(hz - hz_cycles);
|
||||||
|
hz_mean_diff[i] = abs(hz - hz_mean);
|
||||||
|
|
||||||
|
if (hz_cycles_diff[i] > hz_cycles_diff_max) {
|
||||||
|
hz_cycles_diff_max = hz_cycles_diff[i];
|
||||||
|
}
|
||||||
|
|
||||||
|
if (hz_mean_diff[i] > hz_mean_diff_max) {
|
||||||
|
hz_mean_diff_max = hz_mean_diff[i];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
std::cout << "hz_cycles_diff_max : " << hz_cycles_diff_max << std::endl;
|
||||||
|
std::cout << "hz_mean_diff_max : " << hz_mean_diff_max << std::endl;
|
||||||
|
|
||||||
|
rte_eal_mp_wait_lcore();
|
||||||
|
|
||||||
|
/* clean up the EAL */
|
||||||
|
rte_eal_cleanup();
|
||||||
|
return 0;
|
||||||
|
}
|
5
examples/helloworld/meson.build
Normal file
5
examples/helloworld/meson.build
Normal file
@ -0,0 +1,5 @@
|
|||||||
|
project('dpdk-app', 'cpp')
|
||||||
|
|
||||||
|
dpdk = dependency('libdpdk')
|
||||||
|
sources = files('main.cpp')
|
||||||
|
executable('dpdk-app', sources, dependencies: dpdk)
|
62
examples/meson.build
Normal file
62
examples/meson.build
Normal file
@ -0,0 +1,62 @@
|
|||||||
|
# list of all example apps. Keep 1-3 per line, in alphabetical order.
|
||||||
|
all_examples = [
|
||||||
|
'receive', 'send'
|
||||||
|
]
|
||||||
|
|
||||||
|
if get_option('examples') == ''
|
||||||
|
subdir_done()
|
||||||
|
endif
|
||||||
|
|
||||||
|
if get_option('examples').to_lower() == 'all'
|
||||||
|
examples = all_examples
|
||||||
|
allow_skips = true # don't flag an error if we can't build an app
|
||||||
|
else
|
||||||
|
examples = get_option('examples').split(',')
|
||||||
|
allow_skips = false # error out if we can't build a requested app
|
||||||
|
endif
|
||||||
|
default_cflags = machine_args
|
||||||
|
if cc.has_argument('-Wno-format-truncation')
|
||||||
|
default_cflags += '-Wno-format-truncation'
|
||||||
|
endif
|
||||||
|
default_ldflags = dpdk_extra_ldflags
|
||||||
|
if get_option('default_library') == 'static' and not is_windows
|
||||||
|
default_ldflags += ['-Wl,--export-dynamic']
|
||||||
|
endif
|
||||||
|
|
||||||
|
foreach example: examples
|
||||||
|
name = example.split('/')[-1]
|
||||||
|
build = true
|
||||||
|
sources = []
|
||||||
|
allow_experimental_apis = false
|
||||||
|
cflags = default_cflags
|
||||||
|
ldflags = default_ldflags
|
||||||
|
|
||||||
|
ext_deps = [execinfo]
|
||||||
|
includes = [include_directories(example)]
|
||||||
|
deps = ['eal', 'mempool', 'net', 'mbuf', 'ethdev', 'cmdline']
|
||||||
|
subdir(example)
|
||||||
|
|
||||||
|
if build
|
||||||
|
dep_objs = ext_deps
|
||||||
|
foreach d:deps
|
||||||
|
var_name = get_option('default_library') + '_rte_' + d
|
||||||
|
if not is_variable(var_name)
|
||||||
|
error('Missing dependency "@0@" for example "@1@"'.format(d, name))
|
||||||
|
endif
|
||||||
|
dep_objs += [get_variable(var_name)]
|
||||||
|
endforeach
|
||||||
|
if allow_experimental_apis
|
||||||
|
cflags += '-DALLOW_EXPERIMENTAL_API'
|
||||||
|
endif
|
||||||
|
executable('dpdk-' + name, sources,
|
||||||
|
include_directories: includes,
|
||||||
|
link_whole: link_whole_libs,
|
||||||
|
link_args: ldflags,
|
||||||
|
c_args: cflags,
|
||||||
|
dependencies: dep_objs)
|
||||||
|
elif not allow_skips
|
||||||
|
error('Cannot build requested example "' + name + '"')
|
||||||
|
else
|
||||||
|
message('Skipping example "' + name + '"')
|
||||||
|
endif
|
||||||
|
endforeach
|
152
examples/receive/main.cpp
Normal file
152
examples/receive/main.cpp
Normal file
@ -0,0 +1,152 @@
|
|||||||
|
#include <stdint.h>
|
||||||
|
#include <inttypes.h>
|
||||||
|
#include <rte_eal.h>
|
||||||
|
#include <rte_ethdev.h>
|
||||||
|
#include <rte_cycles.h>
|
||||||
|
#include <rte_lcore.h>
|
||||||
|
#include <rte_mbuf.h>
|
||||||
|
#include <rte_ether.h>
|
||||||
|
#include <rte_ip.h>
|
||||||
|
#include <rte_udp.h>
|
||||||
|
#include <pthread.h>
|
||||||
|
|
||||||
|
#define RX_RING_SIZE 128
|
||||||
|
#define TX_RING_SIZE 512
|
||||||
|
|
||||||
|
#define NUM_MBUFS 8191
|
||||||
|
#define MBUF_CACHE_SIZE 250
|
||||||
|
#define BURST_SIZE 32
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Ethernet header: Contains the destination address, source address
|
||||||
|
* and frame type.
|
||||||
|
*/
|
||||||
|
struct ether_hdr
|
||||||
|
{
|
||||||
|
struct ether_addr d_addr; /**< Destination address. */
|
||||||
|
struct ether_addr s_addr; /**< Source address. */
|
||||||
|
uint16_t ether_type; /**< Frame type. */
|
||||||
|
} __attribute__((__packed__));
|
||||||
|
|
||||||
|
/**
|
||||||
|
* IPv4 Header
|
||||||
|
*/
|
||||||
|
struct ipv4_hdr
|
||||||
|
{
|
||||||
|
uint8_t version_ihl; /**< version and header length */
|
||||||
|
uint8_t type_of_service; /**< type of service */
|
||||||
|
uint16_t total_length; /**< length of packet */
|
||||||
|
uint16_t packet_id; /**< packet ID */
|
||||||
|
uint16_t fragment_offset; /**< fragmentation offset */
|
||||||
|
uint8_t time_to_live; /**< time to live */
|
||||||
|
uint8_t next_proto_id; /**< protocol ID */
|
||||||
|
uint16_t hdr_checksum; /**< header checksum */
|
||||||
|
uint32_t src_addr; /**< source address */
|
||||||
|
uint32_t dst_addr; /**< destination address */
|
||||||
|
} __attribute__((__packed__));
|
||||||
|
|
||||||
|
/**
|
||||||
|
* UDP Header
|
||||||
|
*/
|
||||||
|
struct udp_hdr
|
||||||
|
{
|
||||||
|
uint16_t src_port; /**< UDP source port. */
|
||||||
|
uint16_t dst_port; /**< UDP destination port. */
|
||||||
|
uint16_t dgram_len; /**< UDP datagram length */
|
||||||
|
uint16_t dgram_cksum; /**< UDP datagram checksum */
|
||||||
|
} __attribute__((__packed__));
|
||||||
|
|
||||||
|
static const struct rte_eth_conf port_conf_default = {.rxmode = {.max_rx_pkt_len = ETHER_MAX_LEN}};
|
||||||
|
|
||||||
|
static inline int port_init(struct rte_mempool *mbuf_pool)
|
||||||
|
{
|
||||||
|
struct rte_eth_conf port_conf = port_conf_default;
|
||||||
|
const uint16_t rx_rings = 1, tx_rings = 1;
|
||||||
|
int retval;
|
||||||
|
uint16_t q;
|
||||||
|
|
||||||
|
retval = rte_eth_dev_configure(0, rx_rings, tx_rings, &port_conf);
|
||||||
|
if (retval != 0)
|
||||||
|
return retval;
|
||||||
|
|
||||||
|
/* Allocate and set up 1 RX queue per Ethernet port. */
|
||||||
|
for (q = 0; q < rx_rings; q++)
|
||||||
|
{
|
||||||
|
retval = rte_eth_rx_queue_setup(0, q, RX_RING_SIZE, rte_eth_dev_socket_id(0), NULL, mbuf_pool);
|
||||||
|
if (retval < 0)
|
||||||
|
return retval;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Allocate and set up 1 TX queue per Ethernet port. */
|
||||||
|
for (q = 0; q < tx_rings; q++)
|
||||||
|
{
|
||||||
|
retval = rte_eth_tx_queue_setup(0, q, TX_RING_SIZE, rte_eth_dev_socket_id(0), NULL);
|
||||||
|
if (retval < 0)
|
||||||
|
return retval;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Start the Ethernet port. */
|
||||||
|
retval = rte_eth_dev_start(0);
|
||||||
|
if (retval < 0)
|
||||||
|
return retval;
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
int main(int argc, char *argv[])
|
||||||
|
{
|
||||||
|
struct rte_mempool *mbuf_pool;
|
||||||
|
|
||||||
|
int ret = rte_eal_init(argc, argv);
|
||||||
|
if (ret < 0)
|
||||||
|
rte_exit(EXIT_FAILURE, "initlize fail!");
|
||||||
|
|
||||||
|
argc -= ret;
|
||||||
|
argv += ret;
|
||||||
|
|
||||||
|
/* Creates a new mempool in memory to hold the mbufs. */
|
||||||
|
mbuf_pool = rte_pktmbuf_pool_create("MBUF_POOL", NUM_MBUFS,
|
||||||
|
MBUF_CACHE_SIZE, 0, RTE_MBUF_DEFAULT_BUF_SIZE, rte_socket_id());
|
||||||
|
|
||||||
|
if (mbuf_pool == NULL)
|
||||||
|
rte_exit(EXIT_FAILURE, "Cannot create mbuf pool\n");
|
||||||
|
|
||||||
|
/* Initialize all ports. */
|
||||||
|
if (port_init(mbuf_pool) != 0)
|
||||||
|
rte_exit(EXIT_FAILURE, "Cannot init port %" PRIu8 "\n",
|
||||||
|
0);
|
||||||
|
|
||||||
|
for (;;)
|
||||||
|
{
|
||||||
|
|
||||||
|
struct rte_mbuf *pkt[BURST_SIZE];
|
||||||
|
int i;
|
||||||
|
for (i = 0; i < BURST_SIZE; i++)
|
||||||
|
{
|
||||||
|
pkt[i] = rte_pktmbuf_alloc(mbuf_pool);
|
||||||
|
}
|
||||||
|
|
||||||
|
uint16_t nb_rx = rte_eth_rx_burst(0, 0, pkt, BURST_SIZE);
|
||||||
|
if (nb_rx == 0)
|
||||||
|
{
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
char *msg;
|
||||||
|
struct ether_hdr *eth_hdr;
|
||||||
|
for (i = 0; i < nb_rx; i++)
|
||||||
|
{
|
||||||
|
eth_hdr = rte_pktmbuf_mtod(pkt[i], struct ether_hdr *);
|
||||||
|
printf("MAC: %02" PRIx8 " %02" PRIx8 " %02" PRIx8 " %02" PRIx8 " %02" PRIx8 " %02" PRIx8 " : ",
|
||||||
|
eth_hdr->s_addr.addr_bytes[0], eth_hdr->s_addr.addr_bytes[1],
|
||||||
|
eth_hdr->s_addr.addr_bytes[2], eth_hdr->s_addr.addr_bytes[3],
|
||||||
|
eth_hdr->s_addr.addr_bytes[4], eth_hdr->s_addr.addr_bytes[5]);
|
||||||
|
msg = ((rte_pktmbuf_mtod(pkt[i], char *)) + sizeof(struct ether_hdr));
|
||||||
|
int j;
|
||||||
|
for (j = 0; j < 10; j++)
|
||||||
|
printf("%c", msg[j]);
|
||||||
|
printf("\n");
|
||||||
|
rte_pktmbuf_free(pkt[0]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
3
examples/receive/meson.build
Normal file
3
examples/receive/meson.build
Normal file
@ -0,0 +1,3 @@
|
|||||||
|
sources = files(
|
||||||
|
'main.cpp'
|
||||||
|
)
|
151
examples/send/main.cpp
Normal file
151
examples/send/main.cpp
Normal file
@ -0,0 +1,151 @@
|
|||||||
|
#include <stdint.h>
|
||||||
|
#include <inttypes.h>
|
||||||
|
#include <rte_eal.h>
|
||||||
|
#include <rte_ethdev.h>
|
||||||
|
#include <rte_cycles.h>
|
||||||
|
#include <rte_lcore.h>
|
||||||
|
#include <rte_mbuf.h>
|
||||||
|
#include <rte_ether.h>
|
||||||
|
#include <rte_ip.h>
|
||||||
|
#include <rte_udp.h>
|
||||||
|
#include <pthread.h>
|
||||||
|
#include <string.h>
|
||||||
|
|
||||||
|
#define RX_RING_SIZE 128
|
||||||
|
#define TX_RING_SIZE 512
|
||||||
|
#define NUM_MBUFS 8191
|
||||||
|
#define MBUF_CACHE_SIZE 250
|
||||||
|
#define BURST_SIZE 12
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Ethernet header: Contains the destination address, source address
|
||||||
|
* and frame type.
|
||||||
|
*/
|
||||||
|
struct ether_hdr
|
||||||
|
{
|
||||||
|
struct ether_addr d_addr; /**< Destination address. */
|
||||||
|
struct ether_addr s_addr; /**< Source address. */
|
||||||
|
uint16_t ether_type; /**< Frame type. */
|
||||||
|
} __attribute__((__packed__));
|
||||||
|
|
||||||
|
/**
|
||||||
|
* IPv4 Header
|
||||||
|
*/
|
||||||
|
struct ipv4_hdr
|
||||||
|
{
|
||||||
|
uint8_t version_ihl; /**< version and header length */
|
||||||
|
uint8_t type_of_service; /**< type of service */
|
||||||
|
uint16_t total_length; /**< length of packet */
|
||||||
|
uint16_t packet_id; /**< packet ID */
|
||||||
|
uint16_t fragment_offset; /**< fragmentation offset */
|
||||||
|
uint8_t time_to_live; /**< time to live */
|
||||||
|
uint8_t next_proto_id; /**< protocol ID */
|
||||||
|
uint16_t hdr_checksum; /**< header checksum */
|
||||||
|
uint32_t src_addr; /**< source address */
|
||||||
|
uint32_t dst_addr; /**< destination address */
|
||||||
|
} __attribute__((__packed__));
|
||||||
|
|
||||||
|
/**
|
||||||
|
* UDP Header
|
||||||
|
*/
|
||||||
|
struct udp_hdr
|
||||||
|
{
|
||||||
|
uint16_t src_port; /**< UDP source port. */
|
||||||
|
uint16_t dst_port; /**< UDP destination port. */
|
||||||
|
uint16_t dgram_len; /**< UDP datagram length */
|
||||||
|
uint16_t dgram_cksum; /**< UDP datagram checksum */
|
||||||
|
} __attribute__((__packed__));
|
||||||
|
|
||||||
|
static const struct rte_eth_conf port_conf_default = {.rxmode = {.max_rx_pkt_len = ETHER_MAX_LEN}};
|
||||||
|
|
||||||
|
static inline int port_init(struct rte_mempool *mbuf_pool)
|
||||||
|
{
|
||||||
|
struct rte_eth_conf port_conf = port_conf_default;
|
||||||
|
const uint16_t rx_rings = 1, tx_rings = 1;
|
||||||
|
int retval;
|
||||||
|
uint16_t q;
|
||||||
|
|
||||||
|
retval = rte_eth_dev_configure(0, rx_rings, tx_rings, &port_conf);
|
||||||
|
if (retval != 0)
|
||||||
|
return retval;
|
||||||
|
|
||||||
|
/* Allocate and set up 1 RX queue per Ethernet port. */
|
||||||
|
for (q = 0; q < rx_rings; q++)
|
||||||
|
{
|
||||||
|
retval = rte_eth_rx_queue_setup(0, q, RX_RING_SIZE, rte_eth_dev_socket_id(0), NULL, mbuf_pool);
|
||||||
|
if (retval < 0)
|
||||||
|
return retval;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Allocate and set up 1 TX queue per Ethernet port. */
|
||||||
|
for (q = 0; q < tx_rings; q++)
|
||||||
|
{
|
||||||
|
retval = rte_eth_tx_queue_setup(0, q, TX_RING_SIZE, rte_eth_dev_socket_id(0), NULL);
|
||||||
|
if (retval < 0)
|
||||||
|
return retval;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Start the Ethernet port. */
|
||||||
|
retval = rte_eth_dev_start(0);
|
||||||
|
if (retval < 0)
|
||||||
|
return retval;
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
int main(int argc, char *argv[])
|
||||||
|
{
|
||||||
|
struct rte_mempool *mbuf_pool;
|
||||||
|
|
||||||
|
int ret = rte_eal_init(argc, argv);
|
||||||
|
if (ret < 0)
|
||||||
|
rte_exit(EXIT_FAILURE, "initlize fail!");
|
||||||
|
|
||||||
|
argc -= ret;
|
||||||
|
argv += ret;
|
||||||
|
|
||||||
|
/* Creates a new mempool in memory to hold the mbufs. */
|
||||||
|
mbuf_pool = rte_pktmbuf_pool_create("MBUF_POOL", NUM_MBUFS, MBUF_CACHE_SIZE, 0, RTE_MBUF_DEFAULT_BUF_SIZE, rte_socket_id());
|
||||||
|
|
||||||
|
if (mbuf_pool == NULL)
|
||||||
|
rte_exit(EXIT_FAILURE, "Cannot create mbuf pool\n");
|
||||||
|
|
||||||
|
/* Initialize all ports. */
|
||||||
|
if (port_init(mbuf_pool) != 0)
|
||||||
|
rte_exit(EXIT_FAILURE, "Cannot init port %" PRIu8 "\n", 0);
|
||||||
|
|
||||||
|
struct Message
|
||||||
|
{
|
||||||
|
char data[10];
|
||||||
|
};
|
||||||
|
struct ether_hdr *eth_hdr;
|
||||||
|
struct Message obj = {{'H', 'e', 'l', 'l', 'o', '2', '0', '1', '8'}};
|
||||||
|
struct Message *msg;
|
||||||
|
struct ether_addr s_addr = {{0x14, 0x02, 0xEC, 0x89, 0x8D, 0x24}};
|
||||||
|
struct ether_addr d_addr = {{0x14, 0x02, 0xEC, 0x89, 0xED, 0x54}};
|
||||||
|
uint16_t ether_type = 0x0a00;
|
||||||
|
|
||||||
|
struct rte_mbuf *pkt[BURST_SIZE];
|
||||||
|
int i;
|
||||||
|
for (i = 0; i < BURST_SIZE; i++)
|
||||||
|
{
|
||||||
|
pkt[i] = rte_pktmbuf_alloc(mbuf_pool);
|
||||||
|
eth_hdr = rte_pktmbuf_mtod(pkt[i], struct ether_hdr *);
|
||||||
|
eth_hdr->d_addr = d_addr;
|
||||||
|
eth_hdr->s_addr = s_addr;
|
||||||
|
eth_hdr->ether_type = ether_type;
|
||||||
|
msg = (struct Message *)(rte_pktmbuf_mtod(pkt[i], char *) + sizeof(struct ether_hdr));
|
||||||
|
*msg = obj;
|
||||||
|
int pkt_size = sizeof(struct Message) + sizeof(struct ether_hdr);
|
||||||
|
pkt[i]->data_len = pkt_size;
|
||||||
|
pkt[i]->pkt_len = pkt_size;
|
||||||
|
}
|
||||||
|
|
||||||
|
uint16_t nb_tx = rte_eth_tx_burst(0, 0, pkt, BURST_SIZE);
|
||||||
|
printf("nb_tx: ", nb_tx);
|
||||||
|
|
||||||
|
for (i = 0; i < BURST_SIZE; i++)
|
||||||
|
rte_pktmbuf_free(pkt[i]);
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
3
examples/send/meson.build
Normal file
3
examples/send/meson.build
Normal file
@ -0,0 +1,3 @@
|
|||||||
|
sources = files(
|
||||||
|
'main.cpp'
|
||||||
|
)
|
Loading…
Reference in New Issue
Block a user