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

rte_eth_dev_info_get()

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

rte_eth_dev_info_get()中,根据port_id,进行一些必要信息的填充,要填充的结构为struct rte_eth_dev_info。该结构中,包含了一些网卡必要的信息,如最大rx,tx队列数,MTU的范围,rx,tx描述符的限制,另外还包含指向rte_device的指针。

int rte_eth_dev_info_get(uint16_t port_id, struct rte_eth_dev_info *dev_info) {
   struct rte_eth_dev *dev;
   const struct rte_eth_desc_lim lim = {
      .nb_max = UINT16_MAX,
      .nb_min = 0,
      .nb_align = 1,
      .nb_seg_max = UINT16_MAX,
      .nb_mtu_seg_max = UINT16_MAX,
   };
   int diag;
   ……
   memset(dev_info, 0, sizeof(struct rte_eth_dev_info));
   dev_info->switch_info.domain_id = RTE_ETH_DEV_SWITCH_DOMAIN_ID_INVALID;

   RTE_ETH_VALID_PORTID_OR_ERR_RET(port_id, -ENODEV);
   dev = &rte_eth_devices[port_id];

   dev_info->rx_desc_lim = lim;
   dev_info->tx_desc_lim = lim;
   dev_info->device = dev->device;
   dev_info->min_mtu = RTE_ETHER_MIN_MTU;
   dev_info->max_mtu = UINT16_MAX;

   RTE_FUNC_PTR_OR_ERR_RET(*dev->dev_ops->dev_infos_get, -ENOTSUP);
   diag = (*dev->dev_ops->dev_infos_get)(dev, dev_info);
   if (diag != 0) {
      memset(dev_info, 0, sizeof(struct rte_eth_dev_info));
      return eth_err(port_id, diag);
   }

   /* Maximum number of queues should be <= RTE_MAX_QUEUES_PER_PORT */
   dev_info->max_rx_queues = RTE_MIN(dev_info->max_rx_queues,
         RTE_MAX_QUEUES_PER_PORT);
   dev_info->max_tx_queues = RTE_MIN(dev_info->max_tx_queues,
         RTE_MAX_QUEUES_PER_PORT);

   dev_info->driver_name = dev->device->driver->name;
   dev_info->nb_rx_queues = dev->data->nb_rx_queues;
   dev_info->nb_tx_queues = dev->data->nb_tx_queues;
   dev_info->dev_flags = &dev->data->dev_flags;

   return 0;
}

rte_eth_dev_info_get()中,首先初始化一个struct rte_eth_desc_lim,将其赋值给dev_info中对应的项。接下来最主要的调用dev->dev_ops->dev_infos_get(),以ixgbe设备为例,对应的接口函数为ixgbe_dev_info_get()。该func中,从rte_eth_dev的指针找到rte_pci_device的指针,然后从eth_dev和pci_device的data字段中获取到填充dev_info的必要信息,另外对dev_info的某些信息填充直接采用的是某些默认值。

rte_pktmbuf_pool_create()

之后是创建一个packet pool内存池用于数据包的分配,调用rte_pktmbuf_pool_create()创建一个内存池,这个内存池是用于收发数据包时对数据包进行缓存的,单位缓存的大小在此处设置为RTE_MBUF_DEFAULT_BUF_SIZE,该值为RTE_MBUF_DEFAULT_DATAROOM + RTE_PKTMBUF_HEADROOM,其中RTE_MBUF_DEFAULT_DATAROOM值为2048,用于存储数据包,RTE_PKTMBUF_HEADROOM值为128,用于存储数据包的解析信息。数据包的数量为rx tx的最大描述符的数量之和再加上PKTPOOL_EXTRA_SIZE(值为512)。

rte_pktmbuf_pool_create()最终调用的是rte_pktmbuf_pool_create_by_ops()

struct rte_mempool *
rte_pktmbuf_pool_create_by_ops(const char *name, unsigned int n,
   unsigned int cache_size, uint16_t priv_size, uint16_t data_room_size,
   int socket_id, const char *ops_name) {
   struct rte_mempool *mp;
   struct rte_pktmbuf_pool_private mbp_priv;
   const char *mp_ops_name = ops_name;
   unsigned elt_size;
   int ret;

   if (RTE_ALIGN(priv_size, RTE_MBUF_PRIV_ALIGN) != priv_size) {
       ……
   }
   elt_size = sizeof(struct rte_mbuf) + (unsigned)priv_size +
      (unsigned)data_room_size;
   memset(&mbp_priv, 0, sizeof(mbp_priv));
   mbp_priv.mbuf_data_room_size = data_room_size;
   mbp_priv.mbuf_priv_size = priv_size;

   mp = rte_mempool_create_empty(name, n, elt_size, cache_size,
       sizeof(struct rte_pktmbuf_pool_private), socket_id, 0);
   ……
   if (mp_ops_name == NULL)
      mp_ops_name = rte_mbuf_best_mempool_ops();
   ret = rte_mempool_set_ops_byname(mp, mp_ops_name, NULL);
   ……
   rte_pktmbuf_pool_init(mp, &mbp_priv);
   ret = rte_mempool_populate_default(mp);
   ……
   rte_mempool_obj_iter(mp, rte_pktmbuf_init, NULL);

   return mp;
}

该func中,首选确认private data的大小对齐到RTE_MBUF_PRIV_ALIGN(大小为8),接下来指定在mempool中的每个元素的大小,即为上面提到的缓冲区大小加上private data的大小再加上struct rte_mbuf结构的大小。然后调用rte_mempool_create_empty()创建内存池,该func中,会进行一系列计算,将元素大小对齐的cache,并作一系列检查操作,接下来调用rte_memzone_reserve()和rte_mempool_trace_create_empty()从memzone中分配内存,然后做完成对mempool的trace的创建操作。

内存池创建完成之后,接下来需要对网卡进行配置,调用rte_eth_dev_configure()来进行,主要是通过struct rte_eth_conf这个数据结构进行。配置包括以下内容:

struct rte_eth_conf {
   uint32_t link_speeds;
   struct rte_eth_rxmode rxmode; /**< Port RX configuration. */
   struct rte_eth_txmode txmode; /**< Port TX configuration. */
   uint32_t lpbk_mode; 
   struct {
      struct rte_eth_rss_conf rss_conf; /**< Port RSS configuration */
      struct rte_eth_vmdq_dcb_conf vmdq_dcb_conf;
      /**< Port vmdq+dcb configuration. */
      struct rte_eth_dcb_rx_conf dcb_rx_conf;
      /**< Port dcb RX configuration. */
      struct rte_eth_vmdq_rx_conf vmdq_rx_conf;
      /**< Port vmdq RX configuration. */
   } rx_adv_conf; /**< Port RX filtering configuration. */
   union {
      struct rte_eth_vmdq_dcb_tx_conf vmdq_dcb_tx_conf;
      /**< Port vmdq+dcb TX configuration. */
      struct rte_eth_dcb_tx_conf dcb_tx_conf;
      /**< Port dcb TX configuration. */
      struct rte_eth_vmdq_tx_conf vmdq_tx_conf;
      /**< Port vmdq TX configuration. */
   } tx_adv_conf; /**< Port TX DCB configuration (union). */
   uint32_t dcb_capability_en;
   struct rte_fdir_conf fdir_conf; /**< FDIR configuration. DEPRECATED */
   struct rte_intr_conf intr_conf; /**< Interrupt mode configuration. */
};

主要的内容有对链路速率的配置,rx tx模式的配置,rx方向一些必要的收包策略,tx方向的发包策略,flow director(流引导)策略,中断配置等。

rte_eth_rx_queue_setup()

配置完网卡之后,接下来配置网卡的rx tx队列,首先调用rte_eth_dev_adjust_nb_rx_tx_desc()来确定允许的rx tx的队列的大小不超过限制值,然后分别调用rte_eth_rx_queue_setup()和rte_eth_tx_queue_setup()来配置网卡的收发队列,ethtool例子中,目前只配置队列0。

rte_eth_rx_queue_setup()中,首先根据传入的mempool的信息,最终确定一个单位缓存的大小;另外需要检查rx队列索引的是否符合dev_info中获取到的对rx队列的限制条件;接下来检查队列的状态,是否是运行状态。之后分别调用dev->dev_ops->rx_queue_release()先将队列信息进行释放,然后再调用dev->dev_ops->rx_queue_setup()进行队列的初始化,最后调用rte_ethdev_trace_rxq_setup()对rx队列的跟踪信息初始化。

首先看一下rx_queue_setup(),以ixgbe_dev_rx_queue_setup()为例,首先要确保传入的dev设备的data->rx_queues[queue_id]指向的空间是空的,如果不为空需要先释放。接下来为这个rx_queues[queue_id]分配一块空间,并为其中的成员进行赋值,主要成员包括指向mempool的指针,最大描述符数量等。接下来调用rte_eth_dma_zone_reserve(),在dma区域上分配内存用于rx ring中描述符的分配,并将相关的地址信息存储在rx_queues[queue_id]->rx_ring中;然后为software ring分配空间,并将相关地址存储到rx_queues[queue_id]->sw_ring中;最后为software scatterd ring分配空间,并将相关地址存储到rx_queues[queue_id]->sw_sc_ring中。分配完空间之后,调用ixgbe_reset_rx_queue()对分配的空间进行一些初始化操作。

接下来看一下rx_queue_release(),以ixgbe_dev_rx_queue_release()为例,实现的是ixgbe_rx_queue_release(),该func主要的工作就是释放rx_queues[queue_id]中各指针指向的缓存。

后面介绍rte_eth_tx_queue_setup()的实现细节,未完待续……

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