dpdk 将arp和icmp数据包交给kni 实现ping
kni
dpdk在收到数据包之后,对于我们不想处理的包,可以将数据包交给kni,kni会将数据包交由内核协议栈处理,内核协议栈处理完数据包后会再次将数据包交给kni,然后我们把数据包从kni设备读出来即可。
本案例中,将ping过程中需要的arp包和icmp包交由kni处理,借此实现ping(好像arp包在开发中也是常常不被处理的 )。
初始化环境
和之前差不多,初始化eal环境、注册终止信号、初始化内存池、初始化各设备等。
因为需要用到kni,所以还需要配置kni
1.初始化kni
rte_kni_init(0);
// 老师说这个参数没用 QAQ
dpdk为我们提供了操作kni的接口,我习惯称之为句柄。现在需要获取操作kni的句柄。
rte_kni_alloc(rte_mempool *pktmbuf_pool, const rte_kni_conf *conf, rte_kni_ops *ops);
// 该函数可以获取一个kni句柄
第一个参数是内存池,第二个参数是kni的配置项,第三个参数是操作配置项。这里将它封装成一个函数。
static struct rte_kni *ng_alloc_kni(struct rte_mempool *mbuf_p, uint16_t port) {
struct rte_kni_conf kconf;
struct rte_kni_ops kops;
memset(&kconf, 0, sizeof(kconf));
memset(&kops, 0, sizeof(kops));
snprintf(kconf.name, RTE_KNI_NAMESIZE, "vEth%u", port);
kconf.group_id = port;
kconf.mbuf_size = 1024;
rte_eth_macaddr_get(port, (struct rte_ether_addr *)&kconf.mac_addr);
rte_eth_dev_get_mtu(port, &kconf.mtu);
kops.config_network_if = ng_config_net_ifup;
// config_network_if是一个函数指针
return rte_kni_alloc(mbuf_p, &kconf, &kops);
}
外部通过这个函数的调用就可以获得操作这个kni设备的句柄。
2.获取操作kni的句柄
handlers[port_id] = ng_alloc_kni(mem_pool, port_id);
3.主循环
while (!quit) {
struct rte_mbuf *mbuf[MAX_PKT_BURST];
struct rte_ether_hdr *hdr;
uint j;
uint16_t port_id;
RTE_ETH_FOREACH_DEV(port_id) {
struct rte_ether_hdr *ether_hdr;
struct rte_ipv4_hdr *ip_hdr;
struct rte_icmp_hdr *icmp_hdr;
struct rte_arp_hdr *arp_hdr;
rte_kni_handle_request(handlers[port_id]);
// 从网卡读数据
sz = rte_eth_rx_burst(port_id, 0, mbuf, MAX_PKT_BURST);
FOR (k, 0, sz) {
ether_hdr = rte_pktmbuf_mtod(mbuf[k], struct rte_ether_hdr *);
if (ether_hdr->ether_type == rte_cpu_to_be_16(RTE_ETHER_TYPE_ARP)) {
if (rte_kni_tx_burst(handlers[port_id], &mbuf[k], 1) <= 0) {
rte_pktmbuf_free(mbuf[k]);
// 写到kni
}
}
else if (ether_hdr->ether_type == rte_cpu_to_be_16(RTE_ETHER_TYPE_IPV4)) {
ip_hdr = rte_pktmbuf_mtod_offset(mbuf[k], struct rte_ipv4_hdr *, sizeof(struct rte_ether_hdr));
if (ip_hdr->dst_addr == LOCAL_IP && ip_hdr->next_proto_id == IPPROTO_ICMP) {
rte_kni_tx_burst(handlers[port_id], &mbuf[k], 1);
}
else rte_pktmbuf_free(mbuf[k]);
}
else rte_pktmbuf_free(mbuf[k]);
}
sz = rte_kni_rx_burst(handlers[port_id], mbuf, MAX_PKT_BURST);
// 从kni拿数据
FOR (k, 0, sz) {
ether_hdr = rte_pktmbuf_mtod(mbuf[k], struct rte_ether_hdr *);
if (ether_hdr->ether_type == rte_cpu_to_be_16(RTE_ETHER_TYPE_ARP)) {
if (rte_eth_tx_burst(port_id, 0, &mbuf[k], 1) <= 0) {
rte_pktmbuf_free(mbuf[k]);
// 写回网卡
}
}
else if (ether_hdr->ether_type == rte_cpu_to_be_16(RTE_ETHER_TYPE_IPV4)) {
ip_hdr = rte_pktmbuf_mtod_offset(mbuf[k], struct rte_ipv4_hdr *,
sizeof(struct rte_ether_hdr));
if (ip_hdr->src_addr == LOCAL_IP && ip_hdr->next_proto_id == IPPROTO_ICMP) {
rte_eth_tx_burst(port_id, 0, &mbuf[k], 1);
}
else rte_pktmbuf_free(mbuf[k]);
}
else rte_pktmbuf_free(mbuf[k]);
}
}
4.程序启动后,kni会产生一个名为 {vEth+网卡编号} 的虚拟网卡,需要为其配置ip
ifconfig vEth0 192.168.13.144 netmask 255.255.255.0 broadcast 192.168.13.255
#我的是vEth0
上述代码只处理了arp和icmp。
问题
调试的时候,主循环内是空的,依然ping通了
1.同一台机器上ping的时候可能不会走这个网卡
2.从另一台机器ping的时候,依然可以ping通,把另一个同一网段的NAT网卡停了恢复正常(终于ping不通了)
一开始可以ping通,过一小会儿就ping不通了
抓包后看到是icmp包收不到应答,于是又看了以下ip配置,发现ip地址没了
学长说是因为我开了dhcp,然后dhcp又被拦截了,时间到期后又没办法重新获取,所以ping不通。将dhcp改为静态(手动),把ip写死即可。
完整代码
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <stdint.h>
#include <sys/types.h>
#include <signal.h>
#include <stdbool.h>
#include <unistd.h>
#include <fcntl.h>
#include <rte_common.h>
#include <rte_memcpy.h>
#include <rte_eal.h>
#include <rte_lcore.h>
#include <rte_interrupts.h>
#include <rte_ether.h>
#include <rte_ethdev.h>
#include <rte_mempool.h>
#include <rte_mbuf.h>
#include <rte_kni.h>
#define RTE_EXIT(x) rte_exit(EXIT_FAILURE, "error at %s\n", x)
#define MEM_CACHE_SIZE 256
#define MAX_PKT_BURST 32
#define MAX_PORTS 32
#define MAX_CORES 8
uint16_t IP_TYPE;
uint16_t ARP_TYPE;
int enable_cores = 1;
const int nb_rxq = 1;
const int nb_txq = 1;
#define ERROR 1
#define EN_CS enable_cores
static struct rte_kni *handlers[MAX_PORTS];
const char *local_ip_str = "192.168.13.144";
static struct in_addr local;
// 本机IP的字节码
long lip;
//#define LOCAL_IP inet_addr(local_ip_str)
#define LOCAL_IP lip
// 启用混杂模式
#define promiscuous_on
/**
* @brief for loop range of [begin, end - 1]
*/
#define FOR(idx, begin, end) for (int idx = begin; idx < end; idx++)
/**
* @brief reverse for range of [begin + 1, end]
*/
#define ROF(i, end, begin) for (int i = end; i > begin; i--)
#define enable_kni 1
static bool quit = false;
static uint8_t default_rss_key_40bytes[] = {
0xd1, 0x81, 0xc6, 0x2c, 0xf7, 0xf4, 0xdb, 0x5b,
0x19, 0x83, 0xa2, 0xfc, 0x94, 0x3e, 0x1a, 0xdb,
0xd9, 0x38, 0x9e, 0x6b, 0xd1, 0x03, 0x9c, 0x2c,
0xa7, 0x44, 0x99, 0xad, 0x59, 0x3d, 0x56, 0xd9,
0xf3, 0x25, 0x3c, 0x06, 0x2a, 0xdc, 0x1f, 0xfc
};
static uint8_t rss_intel_key[] = {
0x6D, 0x5A, 0x6D, 0x5A, 0x6D, 0x5A, 0x6D, 0x5A,
0x6D, 0x5A, 0x6D, 0x5A, 0x6D, 0x5A, 0x6D, 0x5A,
0x6D, 0x5A, 0x6D, 0x5A, 0x6D, 0x5A, 0x6D, 0x5A,
0x6D, 0x5A, 0x6D, 0x5A, 0x6D, 0x5A, 0x6D, 0x5A,
0x6D, 0x5A, 0x6D, 0x5A, 0x6D, 0x5A, 0x6D, 0x5A
};
static uint8_t default_rss_key_52bytes[] = {
0x44, 0x39, 0x79, 0x6b, 0xb5, 0x4c, 0x50, 0x23,
0xb6, 0x75, 0xea, 0x5b, 0x12, 0x4f, 0x9f, 0x30,
0xb8, 0xa2, 0xc0, 0x3d, 0xdf, 0xdc, 0x4d, 0x02,
0xa0, 0x8c, 0x9b, 0x33, 0x4a, 0xf6, 0x4a, 0x4c,
0x05, 0xc6, 0xfa, 0x34, 0x39, 0x58, 0xd8, 0x55,
0x7d, 0x99, 0x58, 0x3a, 0xe1, 0x38, 0xc9, 0x2e,
0x81, 0x15, 0x03, 0x66
};
static uint16_t nb_rxd = 1024;
static uint16_t nb_txd = 1024;
int core_to_rx_queue[MAX_CORES];
int core_to_tx_queue[MAX_CORES];
static struct rte_eth_conf port_conf = {
.rxmode = {
.mq_mode = ETH_MQ_RX_RSS,
.split_hdr_size = 0,
},
.txmode = {
.mq_mode = RTE_ETH_MQ_TX_NONE,
},
.rx_adv_conf = {
.rss_conf = {
.rss_key = default_rss_key_40bytes,
.rss_key_len = 40,
.rss_hf = RTE_ETH_RSS_PROTO_MASK,
},
},
};
// 每个设备对应的MAC地址
static struct rte_ether_addr ether_address[MAX_PORTS];
// 注册了一些终止信号
static void signal_handler(int num) {
if (num == SIGINT || num == SIGTERM) {
printf("\n\nSignal %d received, preparing to exit...\n", num);
quit = true;
}
}
static uint16_t checksum(uint16_t *addr, int count) {
long sum = 0;
while (count > 1) {
sum += *(ushort *)addr++;
count -= 2;
}
if (count > 0) sum += *(u_char *)addr;
while (sum >> 16) sum = (sum & 0xffff) + (sum >> 16);
return ~sum;
}
#if enable_kni
static int ng_config_net_ifup(uint16_t port_id, uint8_t if_up) {
if (!rte_eth_dev_is_valid_port(port_id)) return -EINVAL;
int ret;
if (if_up) {
rte_eth_dev_stop(port_id);
ret = rte_eth_dev_start(port_id);
}
else {
ret = rte_eth_dev_stop(port_id);
}
return ret;
}
static struct rte_kni *ng_alloc_kni(struct rte_mempool *mbuf_p, uint16_t port) {
struct rte_kni_conf kconf;
struct rte_kni_ops kops;
memset(&kconf, 0, sizeof(kconf));
memset(&kops, 0, sizeof(kops));
snprintf(kconf.name, RTE_KNI_NAMESIZE, "vEth%u", port);
kconf.group_id = port;
kconf.mbuf_size = 1024;
rte_eth_macaddr_get(port, (struct rte_ether_addr *)&kconf.mac_addr);
rte_eth_dev_get_mtu(port, &kconf.mtu);
kops.config_network_if = ng_config_net_ifup;
return rte_kni_alloc(mbuf_p, &kconf, &kops);
}
#endif
static void *keep_watch_on_mem_pool_status(void *arg) {
uint avail = 0;
uint in_use = 0;
struct rte_mempool *mp = (struct rte_mempool *)arg;
while (!quit) {
avail = rte_mempool_avail_count(mp);
in_use = rte_mempool_in_use_count(mp);
printf("\n\n***********************************\n");
printf("mempool avail count is %d\n", avail);
printf("mempool in_use is %d\n", in_use);
printf("***********************************\n\n");
sleep(1);
}
return NULL;
}
static int create_a_new_thread(struct rte_mempool *mp) {
pthread_t pid;
return rte_ctrl_thread_create(&pid, "kp_wch_on_s", NULL, keep_watch_on_mem_pool_status, mp);
}
static int task_per_logical_core(void *args) {
uint lcore_id = rte_lcore_id();
struct rte_mempool *mem_pool = (struct rte_mempool *)args;
int ret;
uint16_t sz;
while (!quit) {
struct rte_mbuf *mbuf[MAX_PKT_BURST];
struct rte_ether_hdr *hdr;
uint j;
uint16_t port_id;
RTE_ETH_FOREACH_DEV(port_id) {
struct rte_ether_hdr *ether_hdr;
struct rte_ipv4_hdr *ip_hdr;
struct rte_icmp_hdr *icmp_hdr;
struct rte_arp_hdr *arp_hdr;
rte_kni_handle_request(handlers[port_id]);
sz = rte_eth_rx_burst(port_id, 0, mbuf, MAX_PKT_BURST);
FOR (k, 0, sz) {
ether_hdr = rte_pktmbuf_mtod(mbuf[k], struct rte_ether_hdr *);
if (ether_hdr->ether_type == rte_cpu_to_be_16(RTE_ETHER_TYPE_ARP)) {
if (rte_kni_tx_burst(handlers[port_id], &mbuf[k], 1) <= 0) {
rte_pktmbuf_free(mbuf[k]);
}
}
else if (ether_hdr->ether_type == rte_cpu_to_be_16(RTE_ETHER_TYPE_IPV4)) {
ip_hdr = rte_pktmbuf_mtod_offset(mbuf[k], struct rte_ipv4_hdr *, sizeof(struct rte_ether_hdr));
if (ip_hdr->dst_addr == LOCAL_IP && ip_hdr->next_proto_id == IPPROTO_ICMP) {
rte_kni_tx_burst(handlers[port_id], &mbuf[k], 1);
}
else rte_pktmbuf_free(mbuf[k]);
}
else rte_pktmbuf_free(mbuf[k]);
}
sz = rte_kni_rx_burst(handlers[port_id], mbuf, MAX_PKT_BURST);
FOR (k, 0, sz) {
ether_hdr = rte_pktmbuf_mtod(mbuf[k], struct rte_ether_hdr *);
if (ether_hdr->ether_type == rte_cpu_to_be_16(RTE_ETHER_TYPE_ARP)) {
if (rte_eth_tx_burst(port_id, 0, &mbuf[k], 1) <= 0) {
rte_pktmbuf_free(mbuf[k]);
}
}
else if (ether_hdr->ether_type == rte_cpu_to_be_16(RTE_ETHER_TYPE_IPV4)) {
ip_hdr = rte_pktmbuf_mtod_offset(mbuf[k], struct rte_ipv4_hdr *,
sizeof(struct rte_ether_hdr));
if (ip_hdr->src_addr == LOCAL_IP && ip_hdr->next_proto_id == IPPROTO_ICMP) {
rte_eth_tx_burst(port_id, 0, &mbuf[k], 1);
}
else rte_pktmbuf_free(mbuf[k]);
}
else rte_pktmbuf_free(mbuf[k]);
}
}
}
return 0;
}
int main(int argc, char **argv) {
setbuf(stdout, NULL);
IP_TYPE = rte_cpu_to_be_16(RTE_ETHER_TYPE_IPV4);
ARP_TYPE = rte_cpu_to_be_16(RTE_ETHER_TYPE_ARP);
lip = inet_addr(local_ip_str);
int ret;
local.s_addr = LOCAL_IP;
uint16_t nb_ports_avail, port_id;
// TODO
static struct rte_mempool *mem_pool;
ret = rte_eal_init(argc, argv);
if (ret < 0) RTE_EXIT("rte_eal_init()");
signal(SIGINT, signal_handler);
signal(SIGTERM, signal_handler);
nb_ports_avail = rte_eth_dev_count_avail();
if (nb_ports_avail <= 0) RTE_EXIT("rte_eth_dev_count_avail");
uint nb_mbuf = RTE_MAX(EN_CS * (nb_rxd + nb_txd + MAX_PKT_BURST + 1 * MEM_CACHE_SIZE),
8192U);
mem_pool = NULL;
mem_pool = rte_pktmbuf_pool_create("mbuf", nb_mbuf, MEM_CACHE_SIZE, 0,
RTE_MBUF_DEFAULT_BUF_SIZE, (int)rte_socket_id());
if (mem_pool == NULL) {
RTE_EXIT("rte_pktmbuf_pool_create");
}
rte_kni_init(0);
RTE_ETH_FOREACH_DEV(port_id) {
struct rte_eth_dev_info dev_info;
struct rte_eth_conf local_conf = port_conf;
struct rte_eth_rxconf rxconf;
struct rte_eth_txconf txconf;
struct rte_ether_addr *addr;
ret = rte_eth_macaddr_get(port_id, ðer_address[port_id]);
if (ret) RTE_EXIT("rte_eth_macaddr_get");
addr = (struct rte_ether_addr *)malloc(sizeof(struct rte_ether_addr));
ret = rte_eth_dev_info_get(port_id, &dev_info);
if (ret < 0) RTE_EXIT("rte_eth_dev_info_get");
// TODO
if (dev_info.tx_offload_capa & RTE_ETH_TX_OFFLOAD_MBUF_FAST_FREE)
local_conf.txmode.offloads |= RTE_ETH_TX_OFFLOAD_MBUF_FAST_FREE;
local_conf.rx_adv_conf.rss_conf.rss_hf &=
dev_info.flow_type_rss_offloads;
ret = rte_eth_dev_configure(port_id, nb_rxq, nb_txq, &local_conf);
if (ret) RTE_EXIT("rte_eth_dev_configure");
ret = rte_eth_dev_adjust_nb_rx_tx_desc(port_id, &nb_rxd, &nb_txd);
if (ret) RTE_EXIT("rte_eth_dev_adjust_nb_rx_tx_desc");
ret = rte_eth_macaddr_get(port_id, addr);
if (ret) RTE_EXIT("rte_eth_macaddr_get");
fflush(stdout);
rxconf = dev_info.default_rxconf;
rxconf.offloads = local_conf.rxmode.offloads;
for (int i = 0; i < nb_rxq; i++) {
fflush(stdout);
rxconf = dev_info.default_rxconf;
rxconf.offloads = local_conf.rxmode.offloads;
ret = rte_eth_rx_queue_setup(port_id, i, nb_rxd, rte_eth_dev_socket_id(port_id), &rxconf, mem_pool);
if (ret) rte_exit(EXIT_FAILURE, "the %dth core occurs an error during its rx_queue setting up", i);
}
fflush(stdout);
txconf = dev_info.default_txconf;
txconf.offloads = local_conf.txmode.offloads;
for (int i = 0; i < nb_txq; i++) {
fflush(stdout);
txconf = dev_info.default_txconf;
txconf.offloads = local_conf.txmode.offloads;
ret = rte_eth_tx_queue_setup(port_id, i, nb_txd, rte_eth_dev_socket_id(port_id), &txconf);
if (ret) rte_exit(EXIT_FAILURE, "the %dth core occurs an error during its tx_queue setting up\n", i);
}
#ifdef promiscuous_on
rte_eth_promiscuous_enable(port_id);
#endif
ret = rte_eth_dev_start(port_id);
if (ret) RTE_EXIT("rte_eth_dev_start");
handlers[port_id] = ng_alloc_kni(mem_pool, port_id);
if (handlers[port_id] == NULL) rte_exit(EXIT_FAILURE, "error on ng_alloc_kni\n\n");
}
// system("clear");
#ifdef enable_guard
ret = create_a_new_thread(mem_pool);
if (ret) RTE_EXIT("create a new thread");
#endif
uint lcore_id = 0;
memset(core_to_rx_queue, -1, sizeof(core_to_rx_queue));
memset(core_to_tx_queue, -1, sizeof(core_to_tx_queue));
uint nb_rx_queues = 0;
uint nb_tx_queues = 0;
while (lcore_id < EN_CS) {
if (rte_lcore_is_enabled(lcore_id)) {
if ((nb_rx_queues < nb_rxq) && (!(~core_to_rx_queue[lcore_id])))core_to_rx_queue[lcore_id] = nb_rx_queues++;
if ((nb_tx_queues < nb_txq) && (!(~core_to_tx_queue[lcore_id])))core_to_tx_queue[lcore_id] = nb_tx_queues++;
}
lcore_id++;
}
// TODO
void *args;
args = (void *)mem_pool;
// printf("main core is %u\n\n", rte_get_main_lcore());
//rte_eal_mp_remote_launch(task_per_logical_core, args, CALL_MAIN);
// for (int k = 0; k < 4; k++) {
// if (k == rte_get_main_lcore()) continue;
// rte_eal_remote_launch(task_per_logical_core, args, k);
// }
create_a_new_thread(mem_pool);
task_per_logical_core(args);
// RTE_LCORE_FOREACH_WORKER(lcore_id) {
// if (lcore_id >= 4) continue;
// if (rte_eal_wait_lcore(lcore_id)) {
// ret = -1;
// break;
// }
// }
RTE_ETH_FOREACH_DEV(port_id) {
ret = rte_eth_dev_stop(port_id);
if (ret) RTE_EXIT("rte_eth_dev_stop");
ret = rte_eth_dev_close(port_id);
if (ret) RTE_EXIT("rte_eth_dev_close");
}
ret = rte_eal_cleanup();
if (ret) RTE_EXIT("rte_eal_cleanup");
return ret;
}
本文来自博客园,作者:correct,转载请注明原文链接:https://www.cnblogs.com/correct/p/16548376.html