DPDKアプリをビルドする自前Makefile
DPDKどドキュメントによると、DPDKを使用したアプリケーションでは用意された雛形のMakefileを 一部変更することでビルド環境を提供しているが、自分で何かをつくりたいときにそんなことを やってられない。
ここでは自分で作成したMakefileでDPDKのアプリケーションをビルドする方法をまとめていく。
答えを見つけるまでのアプローチ方法
以下のアプローチで進めていけば一応絶対わかる。
- オリジナルのビルド手順をすべて確認する
- makeにnオプションを与えて実行されるコマンドを確認する
- そのコマンドから少しずついらないオプションを減らしていく
- どんなDPDKアプリでもビルドできる状態で限界まで減らす
- 完成
模範解答的Makefile?
一応以上のことからこんなMakefileが一般的だとわかった。
DPDKPATH=$(RTE_SDK)/$(RTE_TARGET)
CXXFLAGS = -I$(DPDKPATH)/include -include $(DPDKPATH)/include/rte_config.h
LIBS = \
-m64 -pthread -march=native \
-Wl,--no-as-needed \
-Wl,-export-dynamic \
-L$(DPDKPATH)/lib \
-lpthread -ldl -lrt -lm -lpcap \
-Wl,--whole-archive \
-Wl,--start-group \
-ldpdk \
-Wl,--end-group \
-Wl,--no-whole-archive
all:
g++ $(CXXFLAGS) main.cc $(LIBS)
実行用のサンプルアプリケーション
#include <stdio.h>
#include <string.h>
#include <stdint.h>
#include <inttypes.h>
#include <rte_config.h>
#include <rte_version.h>
#include <rte_eal.h>
#include <rte_ethdev.h>
#include <rte_ether.h>
#include <rte_cycles.h>
#include <rte_lcore.h>
#include <rte_mbuf.h>
#include <rte_hexdump.h>
#define RX_RING_SIZE 128
#define TX_RING_SIZE 512
#define NUM_MBUFS 8191
#define MBUF_CACHE_SIZE 250
#define BURST_SIZE 32
static __attribute((noreturn)) void lcore_main(void)
{
class test {
public:
int a;
int b;
void print()
{
printf("HELLO DPDK with C++!!!\n");
}
};
test a;
a.print();
const uint8_t num_ports = rte_eth_dev_count();
uint8_t port;
for (port = 0; port < num_ports; 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());
for (;;) {
for (port=0; port<num_ports; port++) {
struct rte_mbuf* bufs[BURST_SIZE];
const uint16_t num_rx = rte_eth_rx_burst(port, 0, bufs, BURST_SIZE);
if (unlikely(num_rx == 0))
continue;
uint16_t i;
for (i=0; i<num_rx; i++) {
rte_pktmbuf_dump(stdout, bufs[i], sizeof(struct rte_mbuf));
/* rte_hexdump(stdout, "recv packet", */
/* rte_pktmbuf_mtod(bufs[i], void*) , */
/* rte_pktmbuf_data_len(bufs[i]) ); */
uint8_t* head = rte_pktmbuf_mtod(bufs[i], uint8_t*);
memset(head , 0xee, 6);
}
const uint16_t num_tx = 0;
/* const uint16_t num_tx = rte_eth_tx_burst(port, 0, bufs, num_rx); */
/* printf("Reflect %d packet !! \n", num_rx); */
if (unlikely(num_tx < num_rx)) {
uint16_t buf;
for (buf=num_tx; buf<num_rx; buf++)
rte_pktmbuf_free(bufs[buf]);
}
printf("\n\n");
}
}
}
static int port_init(uint8_t port, struct rte_mempool* mbuf_pool)
{
struct rte_eth_rxmode rxmode;
memset(&rxmode, 0, sizeof rxmode);
rxmode.max_rx_pkt_len = ETHER_MAX_LEN;
struct rte_eth_conf port_conf_default;
memset(&port_conf_default, 0, sizeof(port_conf_default));
port_conf_default.rxmode = rxmode;
struct rte_eth_conf port_conf = port_conf_default;
int ret;
uint16_t q;
if (port >= rte_eth_dev_count())
return -1;
const uint16_t rx_rings = 1;
const uint16_t tx_rings = 1;
ret = rte_eth_dev_configure(port, rx_rings, tx_rings, &port_conf);
if (ret != 0)
return ret;
for (q=0; q < rx_rings; q++) {
ret = rte_eth_rx_queue_setup(port, q, RX_RING_SIZE,
rte_eth_dev_socket_id(port), NULL, mbuf_pool);
if (ret < 0)
return ret;
}
for (q=0; q < tx_rings; q++) {
ret = rte_eth_tx_queue_setup(port, q, TX_RING_SIZE,
rte_eth_dev_socket_id(port), NULL);
if (ret < 0)
return ret;
}
ret = rte_eth_dev_start(port);
if (ret < 0)
return ret;
struct ether_addr addr;
rte_eth_macaddr_get(port, &addr);
printf("Port %u MAC: %02" PRIx8 " %02" PRIx8 " %02" PRIx8
" %02" PRIx8 " %02" PRIx8 " %02" PRIx8 "\n",
(unsigned)port,
addr.addr_bytes[0], addr.addr_bytes[1],
addr.addr_bytes[2], addr.addr_bytes[2],
addr.addr_bytes[3], addr.addr_bytes[4]);
rte_eth_promiscuous_enable(port);
return 0;
}
int main(int argc, char** argv)
{
int ret = rte_eal_init(argc, argv);
if (ret < 0)
rte_exit(EXIT_FAILURE, "rte_eal_init() failed\n");
uint32_t num_ports = rte_eth_dev_count();
printf("%d ports found \n", num_ports);
if (num_ports < 1)
rte_exit(EXIT_FAILURE, "rte_eth_dev_count()");
struct rte_mempool* mbuf_pool = rte_pktmbuf_pool_create(
"MBUF_POOL_SLANK", NUM_MBUFS * num_ports,
MBUF_CACHE_SIZE, 0, RTE_MBUF_DEFAULT_BUF_SIZE, rte_socket_id());
if (mbuf_pool == NULL)
rte_exit(EXIT_FAILURE, "rtembuf_pool_create()");
uint8_t portid;
for (portid=0; portid < num_ports; portid++) {
if (port_init(portid, mbuf_pool) != 0)
rte_exit(EXIT_FAILURE, "Cannot init port %"PRIu8 "\n", portid);
}
if (rte_lcore_count() > 1)
printf("WARNING: Too many lcores enabled. Only 1 used. \n");
lcore_main();
}