From de2cfbde735ef0b8ae02238aa3c32b0640b726d3 Mon Sep 17 00:00:00 2001 From: Robert Jeutter Date: Sun, 24 Oct 2021 13:19:14 +0200 Subject: [PATCH] add examples --- examples/basicfwd/main.c | 164 ++++++++++++++++++++++++++++++++ examples/basicfwd/meson.build | 5 + examples/helloworld/main.c | 81 ++++++++++++++++ examples/helloworld/main.cpp | 112 ++++++++++++++++++++++ examples/helloworld/meson.build | 5 + examples/meson.build | 62 ++++++++++++ examples/receive/main.cpp | 152 +++++++++++++++++++++++++++++ examples/receive/meson.build | 3 + examples/send/main.cpp | 151 +++++++++++++++++++++++++++++ examples/send/meson.build | 3 + 10 files changed, 738 insertions(+) create mode 100644 examples/basicfwd/main.c create mode 100644 examples/basicfwd/meson.build create mode 100644 examples/helloworld/main.c create mode 100644 examples/helloworld/main.cpp create mode 100644 examples/helloworld/meson.build create mode 100644 examples/meson.build create mode 100644 examples/receive/main.cpp create mode 100644 examples/receive/meson.build create mode 100644 examples/send/main.cpp create mode 100644 examples/send/meson.build diff --git a/examples/basicfwd/main.c b/examples/basicfwd/main.c new file mode 100644 index 0000000..b445b56 --- /dev/null +++ b/examples/basicfwd/main.c @@ -0,0 +1,164 @@ +/* SPDX-License-Identifier: BSD-3-Clause + * Copyright(c) 2010-2015 Intel Corporation + */ +#include +#include +#include +#include +#include +#include +#include +#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; +} \ No newline at end of file diff --git a/examples/basicfwd/meson.build b/examples/basicfwd/meson.build new file mode 100644 index 0000000..bce90db --- /dev/null +++ b/examples/basicfwd/meson.build @@ -0,0 +1,5 @@ +project('dpdk-app', 'c') + +dpdk = dependency('libdpdk') +sources = files('main.c') +executable('dpdk-app', sources, dependencies: dpdk) \ No newline at end of file diff --git a/examples/helloworld/main.c b/examples/helloworld/main.c new file mode 100644 index 0000000..2bb04b4 --- /dev/null +++ b/examples/helloworld/main.c @@ -0,0 +1,81 @@ + +/* SPDX-License-Identifier: BSD-3-Clause + * Copyright(c) 2010-2014 Intel Corporation + */ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +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; +} \ No newline at end of file diff --git a/examples/helloworld/main.cpp b/examples/helloworld/main.cpp new file mode 100644 index 0000000..ad3c6aa --- /dev/null +++ b/examples/helloworld/main.cpp @@ -0,0 +1,112 @@ + +/* 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 + +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 start, end; + + start = std::chrono::system_clock::now(); + end = std::chrono::system_clock::now(); + std::chrono::duration 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; +} \ No newline at end of file diff --git a/examples/helloworld/meson.build b/examples/helloworld/meson.build new file mode 100644 index 0000000..0b0b719 --- /dev/null +++ b/examples/helloworld/meson.build @@ -0,0 +1,5 @@ +project('dpdk-app', 'cpp') + +dpdk = dependency('libdpdk') +sources = files('main.cpp') +executable('dpdk-app', sources, dependencies: dpdk) \ No newline at end of file diff --git a/examples/meson.build b/examples/meson.build new file mode 100644 index 0000000..ae9ae7e --- /dev/null +++ b/examples/meson.build @@ -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 diff --git a/examples/receive/main.cpp b/examples/receive/main.cpp new file mode 100644 index 0000000..431f11e --- /dev/null +++ b/examples/receive/main.cpp @@ -0,0 +1,152 @@ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#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; +} diff --git a/examples/receive/meson.build b/examples/receive/meson.build new file mode 100644 index 0000000..7cbc995 --- /dev/null +++ b/examples/receive/meson.build @@ -0,0 +1,3 @@ +sources = files( + 'main.cpp' +) \ No newline at end of file diff --git a/examples/send/main.cpp b/examples/send/main.cpp new file mode 100644 index 0000000..6ad79ae --- /dev/null +++ b/examples/send/main.cpp @@ -0,0 +1,151 @@ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#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; +} diff --git a/examples/send/meson.build b/examples/send/meson.build new file mode 100644 index 0000000..7cbc995 --- /dev/null +++ b/examples/send/meson.build @@ -0,0 +1,3 @@ +sources = files( + 'main.cpp' +) \ No newline at end of file