KNI(Kernel NIC Interface,内核网卡接口)是 DPDK 提供的一套机制,用于让 DPDK 用户态应用程序与 Linux 内核网络协议栈之间交换数据包。
我们可以只用dpdk解析特定的协议,然后把其他的协议写回内核中,交由内核处理,实现把数据写回内核的就是kni,也可以通过kni从内核中读取到数据。
dpdk会虚拟化一个eth,称之为veth,这个veth在内核中也有一个相应的结构体net_device。
把数据写回到veth的net device这样内核就可以通过这个结构体来读取网卡中的数据了。
查看kni设备,这个是在./usertools/dpdk-setup.sh中45 Insert KNI module开启的
root@ubuntu:/home/king/share/dpdk/dpdk-stable-19.08.2# ls /dev/kni -l
这个设备就是往内核写数据所使用的设备。
dpdk也提供了一套api接口来操作kni。
这个虚拟化的veth与其他eth有区别,veth有两个功能,
-
像其他eth一样,在内核中有net device,可以供内核使用,内核协议栈可以像普通网卡一样用它收发。
-
dpdk中有操作veth的kni,可以把数据读取到dpdk中。
// 注册的回调函数
// 当ifconfig up/down时,会触发
static int fun_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("kni dev port start fail. port=%d\n",port_id); return ret; } return 0;}
// 初始化kni
struct rte_kni *fun_alloc_kni(struct rte_mempool *mbuf_pool){struct rte_kni *kni_hanlder = NULL; struct rte_kni_conf conf; memset(&conf,0,sizeof(struct rte_kni_conf)); // 网卡名字 snprintf(conf.name, RTE_KNI_NAMESIZE, "vEth2"); // 绑定的dpdk端口 conf.group_id = gDpdkPortId; // kni内存池单个包的大小 conf.mbuf_size = MAX_PACKET_SIZE; // 绑定网口的mac地址 rte_eth_macaddr_get(gDpdkPortId, (struct rte_ether_addr *)conf.mac_addr); // 配置mtu rte_eth_dev_get_mtu(gDpdkPortId, &conf.mtu); print_ethaddr("kni alloc init mac: ",(struct rte_ether_addr *)conf.mac_addr); struct rte_kni_ops ops; memset(&ops,0,sizeof(struct rte_kni_ops)); ops.port_id = gDpdkPortId; // 注册启停回调 ops.config_network_if = fun_config_network_if; kni_hanlder = rte_kni_alloc(mbuf_pool, &conf, &ops); if(kni_hanlder == NULL){ rte_exit(EXIT_FAILURE,"kni hanlder malloc fail\n"); } return kni_hanlder;}
开启混杂模式:
rte_eth_promiscuous_enable(gDpdkPortId);
接收所有经过网卡的数据包,而不是只接收目的mac是本机地址的数据包。
如果在
ifconfig vEth2 192.168.222.134 up
时提示超时,是因为没有执行这两个函数
rte_kni_tx_burst()
rte_kni_handle_request()
在插入arp table时候如果插入的是相同的结点,那么这个结点next和recv都会指向自己,查找时候就进入死锁。
所以添加len进行限制查找次数,再对添加时候进行加锁。
可以把数据的解析和打包都交给sever线程去实现,pktprocess只负责协议的分发。
查看kni设备,这个是在./usertools/dpdk-setup.sh中45 Insert KNI module开启的
root@ubuntu:/home/king/share/dpdk/dpdk-stable-19.08.2# ls /dev/kni -l
ifconfig vEth2 192.168.222.134 up
启动程序,udp process 可以正常收发。
但是tcp 连接不上。
ifconfig vEth2 192.168.222.134 up
tcp客户端可以连接222.134但是信息一直发送不出去。
启动程序,有时候udp process 可以正常收发。tcp process 可以正常收发。有时候都不能正常收发。
ifconfig vEth2 192.168.222.134 up
tcp客户端可以连接222.134但是信息一直发送不出去,提示发送失败。
udp 可以正常收发。
tcp process中处理了很多 222.128的数据,所以把tcp process的打印关掉了,用客户端连接222.134,没有反应,怀疑tcp process一直在处理222.128,处理不过来222.134的数据。
udp process可以正常收发。
只要
ifconfig vEth2 192.168.222.134 up
tcp客户端可以连接222.134,但是信息就发送不出去。
UDP客户端可以正常收发。
pkt process
rte_cpu_to_be_16
我写成了
if(ehdr->ether_type == rte_cpu_to_le_16(RTE_ETHER_TYPE_IPV4))
释放mbuf
rte_pktmbuf_free(tcpmbuf);
写成了
rte_free(tcpmbuf);
文章参考<零声教育>的C/C++linux服务期高级架构系统教程学习:0voice · GitHub