IT数码 购物 网址 头条 软件 日历 阅读 图书馆
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
图片批量下载器
↓批量下载图片,美女图库↓
图片自动播放器
↓图片自动播放器↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁
 
   -> 网络协议 -> 【dpdk】9.KNI学习笔记 -> 正文阅读

[网络协议]【dpdk】9.KNI学习笔记

基于之前实现的UDP/TCP Server代码,直接添加KNI部分


前言

DPDK提供了一系列对网卡的操作,包括rte_ether_hdrrte_ipv4_hdrrte_udp_hdr等,需要自己进行协议栈的解析处理。但是在应用开发的过程中,有很多部分是不需要DPDK做这种处理的,比如:DNS仅处理所有协议中UDP部分的数据,而其他类型的数据DPDK不做处理,还是写回内核,交给内核协议栈去做。对于需要写回内核的数据,DPDK提供了一组接口——Kernel Network Interface,简称KNI

DPDK开启了一个线程,不断地取数据,通过KNI往内核里面送,内核协议栈处理完后,再交给应用程序。这个过程中,KNI会在内核中生成一个net device,例如:veth0。与eth0、eth1一样,DPDK通过这个虚拟的veth0送数据,对应内核协议栈接管这个数据。DPDK能够通过修改生成的映射文件dev/kni对它进行操作。

一、KNI启动

在运行DPDK时,需要选择“45”选项,插入KNI模块。

1.先初始化KNI

在初始化端口时,初始化KNI并分配内存。

struct rte_kni *global_kni = NULL;
if (-1 == rte_kni_init(gDpdkPortId)) {
	rte_exit(EXIT_FAILURE, "kni init failed\n");
}
init_port(mbuf_pool);
// kni_alloc
global_kni = alloc_kni(mbuf_pool);

2.分配一个KNI

创建kni函数定义:

static struct rte_kni *alloc_kni(struct rte_mempool *mbuf_pool);

所需的参数:

  • mbuf_pool,dpdk为kni提供了一个线程,线程分配了一块内存,接收数据就需要内存池;
  • conf:配置kni的一些参数,包括配置名字、绑定的ID、包的大小等;
  • ops:表示操作,比如 :更改IP地址,更改MAC地址,down掉网卡等。

1)初始化conf

struct rte_kni_conf conf;
memset(&conf, 0, sizeof(conf));

snprintf(conf.name, RTE_KNI_NAMESIZE, "vEth%u", gDpdkPortId);
conf.group_id = gDpdkPortId;
conf.mbuf_size = MAX_PACKET_SIZE;
rte_eth_macaddr_get(gDpdkPortId, (struct rte_ether_addr *)conf.mac_addr);
rte_eth_dev_get_mtu(gDpdkPortId, &conf.mtu);

print_ethaddr("alloc_kni: ", (struct rte_ether_addr *)conf.mac_addr);

2)初始化ops

struct rte_kni_ops ops;
memset(&ops, 0, sizeof(ops));

ops.port_id = gDpdkPortId;
ops.config_network_if = config_network_if;

这里ops.config_network_if设置的处理函数如下:

// config_network_if
// rte_kni_handle_request
static int config_network_if(uint16_t port_id, uint8_t if_up) {

	if (!rte_eth_dev_is_valid_port(port_id)) {
		return -EINVAL;
	}

	int ret = 0;
	if (if_up) {
		rte_eth_dev_stop(port_id);
		ret = rte_eth_dev_start(port_id);
	} else {
		rte_eth_dev_stop(port_id);
	}

	if (ret < 0) {
		printf("Failed to start port : %d\n", port_id);
	}

	return 0;
}

3)初始化ops

创建kni_hanlder 后,作为函数返回值

kni_hanlder = rte_kni_alloc(mbuf_pool, &conf, &ops);	
if (!kni_hanlder) {
	rte_exit(EXIT_FAILURE, "Failed to create kni for port : %d\n", gDpdkPortId);
}

return kni_hanlder;

3.开启混杂模式

init_port函数中开启混杂模式

rte_eth_promiscuous_enable(gDpdkPortId);

二、重构网络协议分发流程

将UDP/TCP以外的所有协议,交给KNI处理。其中,保留一部分ARP功能,在协议栈层处理UDP/TCP报文时,判断IP与MAC信息是否在ARP表中,若没有则添加进去。

1.插入ARP信息

插入ARP信息实现函数如下:

static int arp_entry_insert(uint32_t ip, uint8_t *mac) {
	struct arp_table *table = arp_table_instance();
	uint8_t *hwaddr = get_dst_macaddr(ip);
	if (hwaddr == NULL) {
		struct arp_entry *entry = rte_malloc("arp_entry",sizeof(struct arp_entry), 0);
		if (entry) {
			memset(entry, 0, sizeof(struct arp_entry));

			entry->ip = ip;
			rte_memcpy(entry->hwaddr, mac, RTE_ETHER_ADDR_LEN);
			entry->type = 0;

			pthread_spin_lock(&table->spinlock);
			LL_ADD(entry, table->entries);
			table->count ++;
			pthread_spin_unlock(&table->spinlock);		
		}
		return 1; //
	}
	return 0;
}

2.流程重构

将其他报文交给KNI,在pkt_process函数中,添加以下代码:
在这里插入图片描述
rte_kni_tx_burstrte_kni_handle_request函数是配套使用的,如果不执行rte_kni_handle_request函数,一旦执行ifconfig vEth0 192.168.0.119 up,是不会有反应的,因为config_network_if没有回调。

3.报错

执行ifconfig vEth0 192.168.0.119 up出现:

SIOCSIFFLAGS: Timer expired

原因是UDP Server在处理时,定时器会发送ARP请求,ARP send时进入了死循环。

  • ARP Timer超时
  • arptable没有加速

这里对ARP表优化,进行加速:

struct arp_table {

	struct arp_entry *entries;
	int count;

	pthread_spinlock_t spinlock;
};

在每次添加ARP结点时加锁:

pthread_spin_lock(&table->spinlock);
LL_ADD(entry, table->entries);
table->count ++;
pthread_spin_unlock(&table->spinlock);

三、tcpdump抓包调试KNI

对虚拟网卡vEth0抓包:

tcpdump -i vEth0

tcpdump 是一个运行在命令行下的抓包工具。
例:

  • 在ens33网卡上监听100个目标端口是443端口的数据包,并保存到/root/1.cap,可再用wireshark打开并分析数据包
tcpdump -i ens33 -c 100 ‘dst port 443’ -w /root/1.cap
  • 在ens33网卡上监听5个目标主机是192.168.146.131的不是tcp协议的数据包:
tcpdump -i ens33 -c 5 dst host 192.168.146.131 and ‘not tcp’

四、总结

KNI主要是DPDK用于对内核的补充,不需要处理的信息,写入到KNI,让内核协议栈处理。可以让内核协议栈与DPDK用户态协议栈同时存在运行。
另外,代码运行时可能会出现内存泄漏的现象,就需要在使用完或者未生成时释放TCP/UDP数据 对应的内存。

  网络协议 最新文章
使用Easyswoole 搭建简单的Websoket服务
常见的数据通信方式有哪些?
Openssl 1024bit RSA算法---公私钥获取和处
HTTPS协议的密钥交换流程
《小白WEB安全入门》03. 漏洞篇
HttpRunner4.x 安装与使用
2021-07-04
手写RPC学习笔记
K8S高可用版本部署
mySQL计算IP地址范围
上一篇文章      下一篇文章      查看所有文章
加:2022-03-12 17:57:52  更:2022-03-12 17:59:45 
 
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁

360图书馆 购物 三丰科技 阅读网 日历 万年历 2024年11日历 -2024/11/26 6:46:36-

图片自动播放器
↓图片自动播放器↓
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
图片批量下载器
↓批量下载图片,美女图库↓
  网站联系: qq:121756557 email:121756557@qq.com  IT数码