目录
1、加载kni驱动
cd /root/dpdk-stable-19.08.2
./usertools/dpdk-setup.sh 然后执行45
插入kni驱动后可以看到如下文件
2、kni初始化
进程启动时执行:
rte_kni_init(参数)//该参数任意,用不到,可以填port id,然后执行:
static struct rte_kni *ng_alloc_kni(struct rte_mempool *mbuf_pool) {
struct rte_kni *kni_handle = NULL;
struct rte_kni_conf conf = {0};
snprintf(conf.name, RTE_KNI_NAMESIZE, "vEth%d", gDpdkPortId);
conf.group_id = gDpdkPortId;
conf.mbuf_size = MAX_PACKET_SIZE;
rte_memcpy(conf.mac_addr, gSrcMac, RTE_ETHER_ADDR_LEN);
rte_eth_dev_get_mtu(gDpdkPortId, &conf.mtu);
struct rte_kni_ops ops = {0};
ops.port_id = gDpdkPortId;
ops.config_network_if = ng_config_network_if;
kni_handle = rte_kni_alloc(mbuf_pool, &conf, &ops);
if (kni_handle == NULL) {
rte_exit(EXIT_FAILURE, "Failed to create kni for port:%d\n", gDpdkPortId);
}
return kni_handle;
}
初始化完成后,运行程序可以看到,新增网卡,网卡名称在上述ng_alloc_kni中设置
如果网卡 处于down状态,需要ifconfig up,然后添加ip,ip和dpdk绑定的网卡ip相同
3、运行
1、kni回发报文给dpdk的三种方法(kni默认不回包给dpdk)
1.1)sudo echo 1 > /sys/devices/virtual/net/vEth0/carrier,这样内核收到dpdk的报文后才会回包。
1.2)进程启动时调用rte_kni_update_link函数,也是设置该内核参数
1.3)
2、对于dpdk不需要处理的报文送入内核协议栈:rte_kni_tx_burst(global_kni, &mbufs[i], 1);
注:rte_kni_tx_burst函数会对传入的mbufs[i]进行内存释放
3、rte_kni_handle_request
应用层操作的接口:rte_kni_handle_request; 该函数用于处理请求队列中的请求,因此这个函数需要周期性的执行,以免请求得不到处理,超时导致配置失败。可以放在定时任务或者主循环中调用。
注:每个kni设备本身,都有一个独占的发送队列、接收队列、分配队列、释放队列、请求队列、响应队列
rte_kni_tx_burst将mbuf存到接收队列kni->rx_q
4、dpdk读取内核协议栈回包,然后将报文送入网卡:
struct rte_mbuf *pkts_burst[BURST_SIZE];
unsigned num_rx_recvd = rte_kni_rx_burst(global_kni, pkts_burst, BURST_SIZE);
if (unlikely(num_rx_recvd > BURST_SIZE)) {
printf("Error receiving from KNI\n");
continue;
}
unsigned nb_tx = rte_eth_tx_burst(gDpdkPortId, 0, pkts_burst, (uint16_t)num_rx_recvd);
//if (unlikely(nb_tx < num_rx_recvd)) {
burst_free_mbufs(pkts_burst, num_rx_recvd);
注:rte_kni_tx_burst和rte_kni_rx_burst没有将mbuf在内核态和用户态之间进行数据拷贝,它们共用同一个mbuf