概览
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
发送报文。