DPU网络开发SDK——DPDK(十四)

继续接之前的内容分析ethtool,分析setup_ports()中对网卡的初始化操作,包括几个重要的接口函数。

rte_eth_rx_queue_setup()完成之后是rte_eth_tx_queue_setup(),该func中,首先检查device和queue_id的合法性,然后调用rte_eth_dev_info_get()获取到设备的信息,之后检查传入的tx描述符的数量是否合法,device是否处于忙碌状态,队列是否处于停止状态,只有device不在忙碌状态且队列是通知状态时,才可以继续队列的setup。如果device中tx队列信息不为空的话,先调用dev->dev_ops->tx_queue_release()将队列释放,最后调用dev->dev_ops->tx_queue_setup()进行队列的初始化。

在初始化之前,需要对一些配置进行决策。如果传入rte_eth_rx_queue_setup()的tx_conf的值是空的,则读取dev_info中的默认的txconf配置。对tx_conf中的offloads成员需要重点做检查,如果在调用rte_eth_dev_configure()对网卡进行配置时,已经设置了offloading为开启状态,那么这个状态就是对全部队列有效的,就不需要在tx_conf->offloads中对该队列单独设置卸载了,tx_conf->offloads中的设置只针对该队列是tx卸载的而不是网卡所有的队列都是tx卸载的情况。针对该队列新添加的offloadings状态要求rte_eth_dev_configure()是没有开启的,也就是说必须是单队列特性,而单网卡offloading特性不能实现某个队列开启了卸载而另外一个没有开启卸载,另外单网卡offloading特性如果在rte_eth_dev_configure()中没有使能,那么任何新添加的队列也不会开启卸载。这些需要在调用tx_queue_setup()之前做好检查工作。

tx_queue_setup()以ixgbe_dev_tx_queue_setup()为例,该func中,需要确定一些值,如offload是否开启,tx描述符的数量以及tx释放门限tx_free_thresh和tx重置门限tx_rs_thresh,这两个值是用来控制tx描述符上的rs标志的设置的,具体的规则为:

  • 当tx_rs_thresh个描述符被使用之后,所有tx描述符的rs标志全部置位

  • 存储tx描述符的ring结构在以下两种情况下被清理:1. tx_free_thresh个描述符被使用。2. 发送一个包所需的描述符数量比空闲的tx描述符数量多

tx_free_thresh和tx_rs_thresh的值可以通过调用func时传入的tx_conf参数指定,未设置时选择默认值(不同设备值不同,ixgbe的默认值均为32),且设置的值有一定的限制条件。

  • 两者之和不能超过tx描述符的数量

  • tx_rs_thresh的值必须小于tx描述符数量-2,且不可大于默认值(ixgbe的默认值为32)

  • tx_free_thresh的值必须小于tx描述符数量-3

  • tx_rs_thresh不得大于tx_free_thresh

  • tx描述符数量必须是tx_rs_thresh的整数倍

  • 如果配置了tx_rs_thresh,那么写回门限wthresh则不能再设置

以上提到的值,在创建了struct ixgbe_tx_queue类型的对象txq之后都会赋值给txq对应的成员,tx_free_thresh和tx_rs_thresh的具体作用在后续分析发包时会有相关解释。

接下来分配txq对象,该结构最终存储在dev->data->tx_queues[]数组当中,分配之前首先检查数组中对应的元素如果不为空的话,需要首先调用ixgbe_tx_queue_release()进行释放。

接下来调用rte_eth_dma_zone_reserve(),在dma区域上分配一块连续的内存,用来存储多个高级tx描述符,这块内存地址赋值给txq->tx_ring。在这里分配的高级tx描述符数量是固定的,固定为4096,这个数量要设置的足够大,要满足最大的ring的大小的要求,使得在之后的队列初始化调用func的扩缩容操作能够进行。

接下来将描述符的数量,tx_free_thresh,tx_rs_thresh和三个门限值记录到txq当中,这三个门限值是:预获取门限,主机门限,写回门限。此外还有网卡和队列的ID,offload开启情况,队列的注册ID等,队列注册ID在网卡没有开启sriov时就是队列的ID,否则队列注册ID需要加上网卡的默认队列池的起始队列的ID。最后将类型为struct ixgbe_txq_ops结构赋值给txq->ops,该结构体包含了一些对队列的操作的func。

接下来设置队列和硬件相关的内容,硬件相关结构体存储在dev->data->data_private当中,类型为struct ixgbe_hw。主要是设置txq中TDT(Transmit Descriptor Tail)寄存器的地址,根据不同的硬件类型寄存器地址读取的方式也不相同。

接下来分配软件队列txq->sw_ring,队列中元素类型为struct ixgbe_tx_entry,数量为tx描述符的数量。最后,根据txq中的特性,调用ixgbe_set_tx_function()给网卡设置dev->tx_pkt_burst()和dev->tx_pkt_prepare()这两个函数指针,指明网卡发送数据包时的具体方式。有三种发送方式:分别是ixgbe_xmit_pkts_simple(),ixgbe_xmit_pkts_vec()和ixgbe_xmit_pkts()。具体使用哪种方式,与txq的特性相关。在没有开启offload,且tx_rs_thresh不小于RTE_PMD_IXGBE_TX_MAX_BURST(默认为32)时,使用ixgbe_xmit_pkts_simple(),在此基础上开启了vector TX的话(ixgbe开启条件严格,一般不会用到),使用ixgbe_xmit_pkts_vec(),除此之外的情况,使用ixgbe_xmit_pkts(),具体发送行为在分析包发送阶段相关内容时再做分析。

在rx和tx队列初始化完成之后,即可对网卡进行开启处理,调用的接口是rte_eth_dev_start()。在rte_eth_dev_start()中,首先检查dev->data->dev_started状态是否正确。接下来如果网卡不支持实时mac地址,则需要将网卡mac地址恢复。之后调用dev->dev_ops->dev_start对设备进行开启操作。

以ixgbe_dev_start()为例,最开始从dev->data->dev_private中获取多个配置信息,包括硬件配置信息hw,流量控制信息tm,macsec(media access control security)。接下来调用rte_intr_disable()关闭uio/vfio的中断或者是事件通知文件(eventfd),调用ixgbe_stop_adaptor()关闭,该func最终调用的是hw->mac.ops.stop_adaptor()。

在此我们回顾一下,hw->mac.ops可以认为是对实际硬件的操作,ops的赋值是在ixgbe_init_ops_X540/82598/82599()进行的,即针对不同型号的网卡分别对ops中的函数指针赋予不同的值;ixgbe_init_ops_generic()可以认为是默认的函数指针,各型号网卡首先赋予ops的函数指针默认值,然后再替换ops中一些特定的函数指针;ops赋值func的调用点在eth_ixgbe_pci_probe()->eth_ixgbe_dev_init()->ixgbe_init_shared_code(),eth_ixgbe_pci_probe()我们在第十二节中提到过其调用的位置。在ixgbe驱动中ops.stop_adaptor()被赋值的内容为ixgbe_stop_adapter_generic(),其中的大部分操作都是通过对设备寄存器的读写实现网络适配器的停止,此处涉及较多硬件特性,在此不做特定分析。

stop_adaptor()之后,便是ixgbe_pf_reset_hw(),以及接下来的hw->mac.ops.start_hw(),ixgbe_pf_host_configure()和ixgbe_dev_phy_intr_setup(),之后还有大量对寄存器的读写,包含设置offload,硬件回调函数,rx和tx队列,设置链路状态,链路速率,调用rte_intr_enable()开启中断等,都是通过设定寄存器的方式实现对网络适配器的读写,在此一笔带过,我们只需要知道DPDK作为一个用户态的驱动,基本上仿照Linux驱动模型实现的。实际硬件的操作,则是通过读写寄存器的方式进行,由于不同设备硬件的寄存器布局不同,故各设备的驱动理论上都需要单独编写。此处提到的寄存器,则是第十一节提到的bar空间在用户内存空间上的映射,通过对特定内存地址的读写实现对寄存器的读写,具体寄存器在内存空间上的分配,则需要查看各网络设备的手册。

dev->dev_ops->dev_start网卡开启之后,调用eth_dev_config_restore()设置网卡特性,特性是在开启之前调用rte_eth_dev_info_get()获取的,是我们需要网卡配置成的最终状态;由于开启过程中可能将特性重置,所以在开启之后需要对网卡特性重新进行设置。如果设置失败,则需要停止网卡。涉及到的网卡特性包括mac地址,开启/关闭混杂模式,开启/关闭全多播

最后如果没有开启lsc(link status)中断的话,则需要调用dev->dev_ops->link_update()更新链路状态。

setup_ports()中的最后一个操作是rte_eth_macaddr_get(),直接从dev->data->mac_addrs获取mac地址即可。

至此,ethtool中setup_ports()的主要过程基本分析完毕,后续围绕几个收发包时的func进行分析,未完待续……

你可能感兴趣的:(DPU,DPDK)