DPDK内核模块KNI

2023-12-19 10:32
文章标签 内核模块 dpdk kni

本文主要是介绍DPDK内核模块KNI,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!


DPDK Kernel NIC Interface (KNI)接口允许DPDK用户程序访问Linux控制平面。

使用DPDK KNI的有点如下:

相较现存的Linux TUN/TAP接口更快的速度(消除了系统调用以及copy_to_user()/copy_from_user()内存拷贝的消耗)
允许标准Linux网络工具管理DPDK接口,如ethtool, ifconfig 和 tcpdump
提供到内核协议栈接口

使用DPDK的内核KNI虚拟接口的应用程序组件如下图所示。

 

DPDK KNI内核模块


KNI内核可加载模块rte_kni为DPDK应用提供内核接口。

当rte_kni模块加载时,创建/dev/kni设备节点(rte_kni模块创建kni杂项设备,文件系统节点/dev/kni需要手动或者通过udev机制创建),藉此节点,DPDK KNI应用可控制和与内核rte_kni模块交互。

在内核模块rte_kni加载时,可指定一些可选的参数以控制其行为:

# modinfo rte_kni.ko
lo_mode:        KNI loopback mode (default=lo_mode_none):lo_mode_none        Kernel loopback disabledlo_mode_fifo        Enable kernel loopback with fifolo_mode_fifo_skb    Enable kernel loopback with fifo and skb bufferkthread_mode:   Kernel thread mode (default=single):single    Single kernel thread mode enabled.multiple  Multiple kernel thread mode enabled.carrier:        Default carrier state for KNI interface (default=off):off   Interfaces will be created with carrier state set to off.on    Interfaces will be created with carrier state set to on.

 

典型的情况是,在加载rte_kni模块时不指定任何参数,DPDK应用可由内核网络协议栈获取和向其发送报文。不指定任何参数,意味着仅创建一个内核线程处理所有的KNI虚拟设备在内核侧的报文接收,并且禁用回环模式,KNI接口的默认链路状态为关闭off。

# insmod kmod/rte_kni.ko

 

回环模式


以测试为目的,在加载rte_kni模块式可指定lo_mode参数:

# insmod kmod/rte_kni.ko lo_mode=lo_mode_fifo
lo_mode_fifo回环模式将在内核空间中操作FIFO环队列,由函数kni_fifo_get(kni->rx_q,...)和kni_fifo_put(kni->tx_q,...)实现从rx_q接收队列读取报文,再写入发送队列tx_q来实现回环操作。


# insmod kmod/rte_kni.ko lo_mode=lo_mode_fifo_skb

lo_mode_fifo_skb回环模式在以上lo_mode_fifo的基础之上,增加了sk_buff缓存的相关拷贝操作。具体包括将rx_q接收队列的数据拷贝到分配的接收skb缓存中。以及分配发送skb缓存,将之前由rx_q队列接收数据拷贝到发送skb缓存中,使用函数kni_net_tx(skb, dev)发送skb缓存数据。最终将数据报文拷贝到mbuf结构中,使用kni_fifo_put函数加入到tx_q发送队列。可见此回环测试模式,更加接近真实的使用场景。


如果没有指定lo_mode参数,回环模式将禁用。


内核线程模式


为了提供性能的灵活性,内核模块rte_kni在加载时刻指定kthread_mode参数。rte_kni模块支持两个选项:单内核线程模式和多内核线程模式。


如下,使能单内核线程模式:

# insmod kmod/rte_kni.ko kthread_mode=single

此模式为所有的KNI虚拟接口创建唯一的内核线程在内核侧接收数据。默认情况下,此内核线程不绑定在特定的核心上,但是,用户可在创建第一个KNI虚拟接口时通过指定结构体rte_kni_conf的core_id和force_bind成员参数,设置此线程的亲核性。


为达到更高性能,内核线程绑定的核心应当与应用中DPDK的核心在同一个socket上。

KNI内核模块也可配置成为每个DPDK应用创建的KNI虚拟接口启动一个单独的内核线程。以下,使能多内核线程模式:

# insmod kmod/rte_kni.ko kthread_mode=multiple

此模式为每个KNI虚拟接口创建一个单独的内核线程在内核侧接收数据。内核线程的亲核性通过每个KNI虚拟接口创建时的结构体rte_kni_conf成员core_id和force_bind变量参数指定。


如果系统中由足够的未使用核心,多内核线程模式可提供具有扩展性的高性能。

如果kthread_mode参数未指定,使用单内核线程模式。


默认链路状态


内核模块rte_kni创建的KNI虚拟接口的链路状态,可通过模块加装时的carrier选项控制。


如果指定了carrier=off,当接口管理使能时,内核模块将接口的链路状态设置为关闭。DPDK应用可通过函数rte_kni_update_link设置KNI虚拟接口的链路状态。这对于需要KNI虚拟接口状态与对应的物理接口实际状态一致的应用是有用的。


如果指定了carrier=on,当接口管理使能时,内核模块将自动设置接口的链路状态为启用。这对于仅将KNI接口作为纯虚拟接口,而不对应任何物理硬件;或者并不想通过rte_kni_update_link函数显示设置接口链路状态的DPDK应用是有用的。对于物理口为连接任何链路而进行的回环模式测试也是有用的。


以下,设置默认的链路状态为启用:

# insmod kmod/rte_kni.ko carrier=on

以下,设置默认的链路状态为关闭:

# insmod kmod/rte_kni.ko carrier=off

如果carrier参数没有指定,KNI虚拟接口的默认链路状态为关闭。


KNI创建和删除


在任何KNI虚拟接口创建之前,rte_kni内核模块必须加装到内核,并且经由rte_kni_init函数配置(获取/dev/kni设备节点文件句柄)。

int rte_kni_init(unsigned int max_kni_ifaces __rte_unused)
{/* Check FD and open */if (kni_fd < 0) {kni_fd = open("/dev/" KNI_DEVICE, O_RDWR);if (kni_fd < 0) {RTE_LOG(ERR, KNI,"Can not open /dev/%s\n", KNI_DEVICE);return -1;}
}

KNI虚拟接口由DPDK应用通过rte_kni_alloc函数动态的创建。


结构体rte_kni_conf包含的成员字段,允许用户指定KNI虚拟接口的名称、设置MTU值大小、设置明确的或者随机的MAC地址,以及控制内核接收线程的亲核性(单线程和多线程模式)。默认情况下,KNI示例程序由对应的物理接口获取MTU值,但是对于KNI PMD程序,其由mbuf的缓存长度决定MTU值。

struct rte_kni_conf {/** KNI name which will be used in relevant network device. Let the name as short as possible, as it will be part of memzone name.*/char name[RTE_KNI_NAMESIZE];uint32_t core_id;   /* Core ID to bind kernel thread on */uint16_t group_id;  /* Group ID */unsigned mbuf_size; /* mbuf size */struct rte_pci_addr addr;struct rte_pci_id id;__extension__uint8_t force_bind : 1; /* Flag to bind kernel thread */char mac_addr[ETHER_ADDR_LEN]; /* MAC address assigned to KNI */uint16_t mtu;
};


结构体rte_kni_ops包含的指针,执行处理来自rte_kni内核模块请求的函数。当KNI虚拟接口被一些控制命令(工具如ifconfig或者ethtool等)或者应用之外的函数操作时,这些rte_kni_ops指针函数允许DPDK应用执行一些注册好的操作。

struct rte_kni_ops {uint16_t port_id; /* Port ID *//* Pointer to function of changing MTU */int (*change_mtu)(uint16_t port_id, unsigned int new_mtu);/* Pointer to function of configuring network interface */int (*config_network_if)(uint16_t port_id, uint8_t if_up);/* Pointer to function of configuring mac address */int (*config_mac_address)(uint16_t port_id, uint8_t mac_addr[]);/* Pointer to function of configuring promiscuous mode */int (*config_promiscusity)(uint16_t port_id, uint8_t to_on);
};

 
例如,当DPDK应用想在用户通过ip link set [up|down] dev <ifaceX>命令使能或者禁用KNI虚拟接口时,同时使能或者禁止对应的物理网口。DPDK应用可注意一个config_network_if的回调函数,以便在接口管理状态改变时调用执行。


当前有4个回调可供用户注册应用函数:


config_network_if:

当KNI虚拟接口的管理状态改变时调用。例如,用户运行命令ip link set [up|down] dev <ifaceX>。


change_mtu:

当用户改变KNI虚拟接口的MTU值时调用。例如,当用户运行命令ip link set mtu <size> dev <ifaceX>时。


config_mac_address:

当用户改变KNI虚拟接口的MAC地址时调用。例如,当用户执行命令ip link set address <MAC> dev <ifaceX>时。当用户设置此回调指针为NULL空时,如果port_id不等于-1,rte_kni库中的默认回调函数kni_config_mac_address()将被调用,其使用指定的port_id参数调用rte_eth_dev_default_mac_addr_set()处理。


config_promiscusity:

当用户修改KNI虚拟接口的混杂模式时调用。例如,当用户运行命令ip link set promisc [on|off] dev <ifaceX>时。如果用户指定此回调函数为空,但是调用时指定的port_id不为空时,rte_kni库中的默认回调函数kni_config_promiscusity()将被调用,其使用指定的port_id参数调用函数rte_eth_promiscuous_<enable|disable>()处理。


为了处理这些回调,DPDK应用必须周期性的运行rte_kni_handle_request()函数。由于注册的用户回调函数直接由rte_kni_handle_request()调用,所以必须注意避免死锁,以及避免阻塞DPDK快速路径的任务。典型的,使用这些回调的DPDK应用需要创建单独的线程或者子进程去定期调用rte_kni_handle_request()函数。


DPDK应用可使用函数rte_kni_release()删除KNI虚拟接口。所有没有被显示删除的kNI虚拟接口在/dev/kni节点关闭的时候一同被删除,可以显示的由rte_kni_close函数触发,或者当DPDK应用关闭时。

void rte_kni_close(void)
{if (kni_fd < 0)return;close(kni_fd);kni_fd = -1;
}


DPDK的mbuf流程

为最大限度的减小在内核空间运行的DPDK代码,mbuf内存池仅在用户空间管理。内核模块知道mbuf的存在,但是所有mbuf的分配和释放操作都仅由DPDK应用程序处理。


下图显示了典型的报文在两个方向的发送情况:


用例:输入


在DPDK接收侧,mbuf由PMD在接收线程上下文分配。此线程将mbuf加入对接收FIFO队列rx_q中。内核KNI线程poll轮询所有的活动KNI虚拟接口的接收队列rx_q。如果将mbuf移出队列,需要将其转换成sk_buff结构,通过netif_rx发送到Linux网络协议栈。出队列的mbuf必须被释放,所以其被发送回free_q释放队列的FIFO中,最终由DPDK应用释放。


DPDK接收线程中,位于相同的主循环中,轮询释放队列free_q FIFO,在mbuf移出队列后,进行释放。 

用例:输出


为实现报文发送,DPDK应用必须先行入队列一些mbuf,以便内核侧获得mbuf缓存。


通过调用kni_net_tx函数,内核将报文发送出去。mbuf由alloc_q队列移出(由于之前的mbuf缓存此处无需等待),填充上sk_buff中的数据。sk_buff结构随后被释放,而mbuf缓存通过tx_q表示的FIFO队列发送到DPDK应用。


DPDK发送线程将mbuf移出队列,通过rte_eth_tx_burst()函数发送给PMD。随后,将mbuf回送到alloc_q中,以供内核侧发送使用。

Ethtool


Ethtool是Linux特有的工具,需要内核中每个网络设备注册自身的回调以支持其相应的操作。当前的ethtool实现使用了修改过的igb/ixgbe内核驱动。i40e网卡和VM(VF或者EM设备)不支持Ethtool工具。

 

END

 

这篇关于DPDK内核模块KNI的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/511857

相关文章

DPDK基础入门(三):并行计算

CPU亲和性 CPU亲和性(CPU Affinity)是指将特定的进程或线程绑定到特定的CPU核心或一组核心上运行。这样做的目的是提高性能和效率,避免由于线程在不同核心间频繁迁移而导致的缓存失效(cache misses)和上下文切换(context switching)开销。通过CPU亲和性,可以更好地利用CPU缓存,提高数据处理速度,特别是在高负载的环境中。 Linux内核API提供了一些

Linux内核模块调试一

接下来写个专栏专门讲我们写的linux内核模块出现异常时如何定位和调试。我们先构造一个最简单的内核空指针玩玩。 #include <linux/kernel.h>#include <linux/module.h>#include <linux/init.h>struct __ops_dev{char dev_name[64];}ops_dev_t;int __init oops_

DPDK简介及相关资料整理

DPDK全称为Date planedevelopment kit,是一个用来进行包数据处理加速的软件库。与传统的数据包处理相比,DPDK具有以下特点: 1) 轮询:在包处理时避免中断上下文切换的开销, 2) 用户态驱动:规避不必要的内存拷贝和系统调用,便于快速迭代优化 3) 亲和性与独占:特定任务可以被指定只在某个核上工作,避免线程在不同核间频繁切换,保证更多的cache命中 4) 降低访

小白也能懂的DPDK技术解析

点击上方“朱小厮的博客”,选择“设为星标” 后台回复"书",获取 后台回复“k8s”,可领取k8s资料 一、网络IO的处境和趋势 从我们用户的使用就可以感受到网速一直在提升,而网络技术的发展也从1GE/10GE/25GE/40GE/100GE的演变,从中可以得出单机的网络IO能力必须跟上时代的发展。 1. 传统的电信领域 IP层及以下,例如路由器、交换机、防火墙、基站等设备都是采用硬件解决方案。

驱动开发系列16 - Linux Graphics DRM和KMS内核模块介绍

一:概述         “直接渲染管理器”(DRM)和“内核模式设置”(KMS)API 是 Linux 图形系统的重要组成部分。然而,关于它们具体是什么的文档非常难以找到——而谷歌搜索到的大部分内容都是完全过时的。看起来在这个领域工作的人们太忙了,无法进行文档编写。这篇文章提供了关于 DRM 内核模块内部实现细节的更详细信息。 二:DRI、DRM和KMS的目的         一开始,所有

内核模块编译

Linux内核的整体结构非常庞大,其包含的组件也非常多,如何使用需要的组件: 方法一:把所有的组件都编译进内核文件,即:zImage或bzImage,但这样会导致两个问题:一是生成的内核文件过大;二是如果要添加或删除某个组件,需要重新编译整个内核。 有没有一种机制能让内核文件(zImage或bzImage)本身并不包含某个组件,而是在该组件需要被使用的时候,动态地添加到正在运行的内核中呢?Li

dpdk解析报文协议-基于l2fwd

dpdk解析报文协议-基于l2fwd 0 前置条件 1、这里需要两台虚拟机,配置了相同的虚拟网络,可以通过tcpreplay在一台虚拟机回放报文,在另一台虚拟机通过tcpdump -i 网卡名 捕获到。 具体配置可参考https://www.jb51.net/server/2946942fw.htm 2、需要dpdk环境配置完成 3、大致了解计算机网络的以太网层、ip层、tcp/u

DPDK:中断处理流程

本文基于DPDK17.11版本源码分析。主要分析一下DPDK的中断处理流程。         网卡支持的中断有多种类型,比如收发包,LSC(链路状态变化),mailbox等,但是DPDK使用PMD来收发包,不用处理收发包中断。         将网卡绑定到igb_uio时会注册uio,生成/dev/uiox字符设备。DPDK初始化时会open /dev/uiox设备,对应到ke

Linux内核开发-编写一个内核模块

0.前言 上一章(点击返回上一章)已经完成了将ubuntu原始内核替换成了自己编好的内核。本章开始编写一个内核模块。 1.内核模块 1.1 什么是内核模块 Linux内核模块可独立于内核之外进行编译,可以在内核运行时动态加载、卸载。内核模块以.ko为后缀。 1.2 操作内核模块常用的指令 # 查看当前正在运行的模块lsmod#插入一个模块insmod module_name# 卸载

内核模块相关命令:lsmod,depmod,m…

lsmod 功能:列出内核已载入模块的状态 用法:lsmod 描述: lsmod 以美观的方式列出/proc/modules的内容。 输出为: Module(模块名)    Size(模块大小)   Used by(被...使用) eg. ne2k_pci           8928               0 8390                 9472