概览
KNI(Kernel NIC Interface)是指被DPDK绑定端口之后,希望(一部分)报文走kernel的网络协议栈而开发的。
优势:
- 比 Linux TUN/TAP interfaces的操作快(通过取消系统调用copy_to_user()/copy_from_user())。
- 允许使用Linux标准网络工具ethtool, ifconfig和tcpdump管理DPDK端口。
- 允许端口使用内核网络协议栈。
KNI 启动
dpdk 2.2 example/kni/main.c的main-->main_loop,它是dpdk启动kni应用时的应用。
- 获取配置,lcore是负责rx还是tx。
- 如果当前的lcore是负责rx,则死循环调用接口kni_ingress进行报文的收取。
- 如果当前的lcore是负责tx,则死循环调用接口kni_egress进行报文的发送。
- 因为一个lcore只能负责一个死循环,所以rx和tx必须至少每个安排一个lcore去操作,不然容易出问题。
- 以上的两个死循环中有原子操作的标志读取,为了判定循环是否退出。退出表示靠signal_handler信号触发。
报文的接收
应用层
kni_ingress:
- rte_eth_rx_burst直接从接口读取数据。
- rte_kni_tx_burst将报文放在- kni->rx_q fifo的buffer区域。
- rte_kni_handle_request从- kni->req_q拿到request,然后根据修改mtu或者设置接口的命令做相应的操作,最后将response放回- kni->resp_q。
内核
应用层调用内核的open(main-->init_kni-->rte_kni_init-->open-->kni_open)创建线程kni_thread_single:
- 线程包含三个循环,第一层循环是判定线程是否要结束,第二层循环是接收循环,默认1000次,第三层循环是所有的kni设备。
- 如果是kni host则调用kni_chk_vhost_rx。
- 其他情况调用kni_net_rx-->kni_net_rx_func-->kni_net_rx_normal。
kni_net_rx_normal:
- 调用kni_fifo_get从kni-->rx_q fifo的buffer区域获取报文。
- 根据上面拿到的报文数,进行循环。
- 申请skb,申请失败则drop,申请成功,将rte_mbuf的报文填充到skb,调用netif_rx。
- 将buffer放入kni->free_q,以备后期释放。
报文的发送
内核
kni设备的ndo_start_xmit为kni_net_tx:
- 如果是RTE_KNI_VHOST,则丢掉。
- 从kni->alloc_q fifo拿到buffer。
- 将skb填充到rte_mbuf。
- 放入kni->tx_q。
应用层
- 循环从不同的kni收取报文。
- rte_kni_rx_burst从- kni->tx_q fifo拿取报文。
- 调用rte_eth_tx_burst发送报文。
