dpdk kni代码示例
时间: 2023-07-02 13:13:38 浏览: 216
以下是一个使用DPDK KNI的简单代码示例,该代码示例将从一个物理端口接收数据包并将其发送回同一端口,同时使用KNI将数据包从内核接收并发送到用户空间,以便进一步处理或分析:
```c
#include <stdio.h>
#include <string.h>
#include <errno.h>
#include <unistd.h>
#include <signal.h>
#include <stdint.h>
#include <inttypes.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <sys/queue.h>
#include <arpa/inet.h>
#include <netinet/in.h>
#include <rte_eal.h>
#include <rte_common.h>
#include <rte_ethdev.h>
#include <rte_kni.h>
#include <rte_malloc.h>
#define RX_RING_SIZE 1024
#define TX_RING_SIZE 1024
#define NUM_MBUFS 8191
#define MBUF_CACHE_SIZE 250
#define BURST_SIZE 32
#define KNI_PORT_ID 1
#define KNI_RX_QUEUE_ID 0
#define KNI_TX_QUEUE_ID 0
static volatile bool force_quit;
static void
signal_handler(int signum)
{
if (signum == SIGINT || signum == SIGTERM) {
printf("signal %d received, preparing to exit...\n", signum);
force_quit = true;
}
}
static int
init_kni(uint16_t port_id, struct rte_mempool *mbuf_pool, struct rte_kni **kni)
{
struct rte_kni_conf conf;
struct rte_kni_ops ops;
int ret;
memset(&conf, 0, sizeof(conf));
memset(&ops, 0, sizeof(ops));
snprintf(conf.name, RTE_KNI_NAMESIZE, "kni%d", port_id);
conf.core_id = rte_lcore_id();
conf.force_bind = 1;
conf.group_id = (uint16_t)rte_eth_dev_socket_id(port_id);
ops.port_id = port_id;
ops.change_mtu = NULL;
ops.config_network_if = NULL;
ops.config_mac_address = NULL;
*kni = rte_kni_alloc(mbuf_pool, &conf, &ops);
if (*kni == NULL) {
printf("Failed to create kni for port %u: %s\n", port_id, strerror(errno));
return -1;
}
ret = rte_kni_tx_burst(*kni, NULL, 0);
if (ret < 0) {
printf("Failed to send kni request for port %u: %s\n", port_id, strerror(errno));
rte_kni_release(*kni);
return -1;
}
return 0;
}
static int
init_port(uint16_t port_id, struct rte_mempool *mbuf_pool)
{
struct rte_eth_conf port_conf = {
.rxmode = {
.max_rx_pkt_len = RTE_ETHER_MAX_LEN,
.split_hdr_size = 0,
.header_split = 0,
.hw_ip_checksum = 0,
.hw_vlan_filter = 0,
.hw_vlan_strip = 0,
.hw_vlan_extend = 0,
.jumbo_frame = 0,
.hw_strip_crc = 0,
.hw_fcs_strip = 0,
},
.txmode = {
.mq_mode = ETH_MQ_TX_NONE,
},
};
const uint16_t rx_rings = 1, tx_rings = 1;
struct rte_eth_dev_info dev_info;
struct rte_eth_txconf txconf;
int ret;
uint16_t q;
struct rte_eth_rxconf rxconf;
if (!rte_eth_dev_is_valid_port(port_id)) {
printf("Invalid port id %u\n", port_id);
return -1;
}
rte_eth_dev_info_get(port_id, &dev_info);
if (dev_info.tx_offload_capa & DEV_TX_OFFLOAD_MBUF_FAST_FREE)
port_conf.txmode.offloads |= DEV_TX_OFFLOAD_MBUF_FAST_FREE;
ret = rte_eth_dev_configure(port_id, rx_rings, tx_rings, &port_conf);
if (ret != 0) {
printf("Failed to configure port %u: %s\n", port_id, strerror(-ret));
return ret;
}
ret = rte_eth_dev_adjust_nb_rx_tx_desc(port_id, RX_RING_SIZE, TX_RING_SIZE);
if (ret != 0) {
printf("Failed to adjust number of rx/tx descriptors for port %u: %s\n", port_id, strerror(-ret));
return ret;
}
rxconf = dev_info.default_rxconf;
rxconf.offloads = port_conf.rxmode.offloads;
for (q = 0; q < rx_rings; q++) {
ret = rte_eth_rx_queue_setup(port_id, q, RX_RING_SIZE, rte_eth_dev_socket_id(port_id), &rxconf, mbuf_pool);
if (ret < 0) {
printf("Failed to setup rx queue %u for port %u: %s\n", q, port_id, strerror(-ret));
return ret;
}
}
txconf = dev_info.default_txconf;
txconf.offloads = port_conf.txmode.offloads;
for (q = 0; q < tx_rings; q++) {
ret = rte_eth_tx_queue_setup(port_id, q, TX_RING_SIZE, rte_eth_dev_socket_id(port_id), &txconf);
if (ret < 0) {
printf("Failed to setup tx queue %u for port %u: %s\n", q, port_id, strerror(-ret));
return ret;
}
}
ret = rte_eth_dev_start(port_id);
if (ret < 0) {
printf("Failed to start port %u: %s\n", port_id, strerror(-ret));
return ret;
}
rte_eth_promiscuous_enable(port_id);
return 0;
}
static void
handle_packet(uint16_t port_id, struct rte_mbuf *mbuf, struct rte_kni *kni)
{
struct rte_mbuf *pkts_burst[1];
uint16_t nb_rx, nb_tx;
struct rte_mbuf *bufs[BURST_SIZE];
unsigned i;
if (mbuf == NULL) {
return;
}
nb_tx = rte_kni_tx_burst(kni, &mbuf, 1);
if (nb_tx == 0) {
rte_pktmbuf_free(mbuf);
return;
}
nb_rx = rte_kni_rx_burst(kni, bufs, BURST_SIZE);
if (nb_rx > 0) {
printf("Received %u packets from KNI for port %u\n", nb_rx, port_id);
for (i = 0; i < nb_rx; i++) {
pkts_burst[0] = bufs[i];
nb_tx = rte_eth_tx_burst(port_id, 0, pkts_burst, 1);
if (nb_tx == 0) {
rte_pktmbuf_free(pkts_burst[0]);
}
}
}
rte_pktmbuf_free(mbuf);
}
static int
lcore_main(void *arg)
{
uint16_t port_id = *(uint16_t *)arg;
struct rte_mbuf *bufs[BURST_SIZE];
struct rte_kni *kni;
unsigned i, nb_rx, nb_tx;
if (init_kni(port_id, rte_pktmbuf_pool_create("KNI_MBUF_POOL", NUM_MBUFS, MBUF_CACHE_SIZE, 0, RTE_MBUF_DEFAULT_BUF_SIZE, rte_socket_id()), &kni) != 0) {
return -1;
}
if (init_port(port_id, rte_pktmbuf_pool_create("MBUF_POOL", NUM_MBUFS, MBUF_CACHE_SIZE, 0, RTE_MBUF_DEFAULT_BUF_SIZE, rte_socket_id())) != 0) {
return -1;
}
printf("Core %u processing packets for port %u...\n", rte_lcore_id(), port_id);
while (!force_quit) {
nb_rx = rte_eth_rx_burst(port_id, 0, bufs, BURST_SIZE);
if (nb_rx > 0) {
printf("Received %u packets from port %u\n", nb_rx, port_id);
for (i = 0; i < nb_rx; i++) {
handle_packet(port_id, bufs[i], kni);
}
}
nb_tx = rte_eth_tx_burst(port_id, 0, NULL, 0);
if (nb_tx > 0) {
printf("Sent %u packets to port %u\n", nb_tx, port_id);
}
}
rte_kni_release(kni);
return 0;
}
int
main(int argc, char **argv)
{
int ret;
uint16_t port_id;
uint16_t nb_ports;
uint16_t port_ids[RTE_MAX_ETHPORTS];
unsigned lcore_id;
unsigned nb_lcores;
ret = rte_eal_init(argc, argv);
if (ret < 0) {
printf("Failed to initialize EAL: %s\n", rte_strerror(-ret));
return -1;
}
argc -= ret;
argv += ret;
if (argc != 1) {
printf("Invalid arguments\n");
printf("Usage: %s <port_id>\n", argv[0]);
return -1;
}
port_id = atoi(argv[1]);
if (port_id >= RTE_MAX_ETHPORTS) {
printf("Invalid port id %u\n", port_id);
return -1;
}
signal(SIGINT, signal_handler);
signal(SIGTERM, signal_handler);
nb_ports = rte_eth_dev_count_avail();
if (nb_ports == 0) {
printf("No Ethernet ports available\n");
return -1;
}
rte_eth_dev_info_get(port_id, &dev_info);
nb_lcores = rte_lcore_count();
if (nb_lcores < 2) {
printf("Insufficient number of lcores: %u\n", nb_lcores);
return -1;
}
printf("Initializing port %u...\n", port_id);
ret = rte_eth_dev_get_port_by_name(dev_info.driver_name, dev_info.device->name, &port_id);
if (ret != 0) {
printf("Failed to get port id for %s: %s\n", dev_info.device->name, strerror(-ret));
return -1;
}
rte_eth_macaddr_get(port_id, &dev_info.default_mac_addr);
RTE_ETH_FOREACH_DEV(port_id) {
port_ids[nb_ports++] = port_id;
}
for (lcore_id = 1; lcore_id < nb_lcores; lcore_id++) {
rte_eal_remote_launch(lcore_main, &port_ids[port_id], lcore_id);
}
lcore_id = 0;
lcore_main(&port_ids[port_id]);
rte_eal_mp_wait_lcore();
return 0;
}
```
这个示例程序使用DPDK KNI将数据包从内核接收并发送到用户空间进行处理,并将处理后的数据包发送回同一物理端口。在实际应用中,可以根据需要对代码进行修改和优化,以满足不同的需求。
阅读全文