DPDK中断机制简析

 DPDK 通过在线程中使用 epoll 模型,监听 UIO 设备的事件,来模拟操作系统的中断处理。


一、中断初始化

在 rte_eal_intr_init() 函数中初始化中断。具体如下:


1、首先初始化 intr_sources 链表。所有 UIO 设备的中断都挂在这个链表上,中断处理线程通过遍历这个链表,来执行设备的中断。

2、创建 intr_pipe 管道,用于 epoll 模型的消息通知。

3、创建线程 intr_thread,线程的执行体是 eal_intr_thread_main() 函数,创建 epoll 模型,遍历 intr_sources 链表,监听已注册的所有 UIO 设备的中断事件,并调用对应 UIO 设备的中断处理函数。

 

int

rte_eal_intr_init(void)

{

  int ret = 0;

 

  /* init the global interrupt source head */

  TAILQ_INIT(&intr_sources);

  /*

   * create a pipe which will be waited byepoll and notified to

   * rebuild the wait list of epoll.

  */

  if (pipe(intr_pipe.pipefd) < 0)

    return -1;


  /* create the host thread to wait/handlethe interrupt */

  ret = pthread_create(&intr_thread,NULL, eal_intr_thread_main, NULL);

    if (ret != 0)

      RTE_LOG(ERR, EAL, "Failed to create thread forinterrupt handling\n");

  return -ret;

}

 

中断线程执行主体 eal_intr_thread_main() 函数具体如下:

1、epoll_create() 创建 epoll 模型。

2、将 intr_pipe 管道加入到 epoll 中。

3、遍历 intr_sources 链表,将所有 UIO 设备加入到 epoll 中。

4、在eal_intr_handle_interrupts() 函数中,在一个 for(;;) 死循环中,调用 epoll_wait() 阻塞模式监听事件。如果有事件发生,则调用 eal_intr_process_interrupts() 函数,最终会调用到相应 UIO 设备注册的中断处理函数。

 

static __attribute__((noreturn)) void *

eal_intr_thread_main(__rte_unused void*arg)

{

  struct epoll_event ev;


  /* host thread, never break out */

  for (;;)  {

    /* build up the epoll fd with all descriptors we are to

     * wait on then pass it to the handle_interrupts function

    */

    static struct epoll_event pipe_event = {

       .events = EPOLLIN | EPOLLPRI,

    };

    struct rte_intr_source *src;

    unsigned numfds = 0;

 

    /* create epoll fd */

    int pfd = epoll_create(1);

    if (pfd < 0)

      rte_panic("Cannot create epoll instance\n");


    pipe_event.data.fd = intr_pipe.readfd;

    /*

     * add pipe fd into wait list, this pipe is used to

     * rebuild the wait list.

    */

    if (epoll_ctl(pfd, EPOLL_CTL_ADD, intr_pipe.readfd, &pipe_event) <0)  {

      rte_panic("Error adding fd to %d epoll_ctl, %s\n", intr_pipe.readfd,strerror(errno));

    }

    numfds++;


    rte_spinlock_lock(&intr_lock);


    TAILQ_FOREACH(src, &intr_sources, next)  {

      if (src->callbacks.tqh_first == NULL)

        continue; /* skip those with nocallbacks */


     ev.events = EPOLLIN | EPOLLPRI;

     ev.data.fd = src->intr_handle.fd;


      /*

       * add all the uio device filedescriptor

        * into wait list.

     */

     if (epoll_ctl(pfd, EPOLL_CTL_ADD, src->intr_handle.fd,&ev) < 0) {

       rte_panic("Error adding fd%d epoll_ctl, %s\n", src->intr_handle.fd,strerror(errno));

     }

     else

        numfds++;

  }   // end  TAILQ_FOREACH(src, &intr_sources, next) 

  rte_spinlock_unlock(&intr_lock);

  /* serve the interrupt */

  eal_intr_handle_interrupts(pfd, numfds);

 

  /*

   * when we return, we need to rebuild the

   * list of fds to monitor.

  */

  close(pfd);

  } // end for(;;)

}

 

二、中断注册

以 e1000 网卡为例说明。在网卡初始化的时候,会调用 rte_eth_dev_init() ---> eth_igb_dev_init() ---> rte_intr_callback_register() 注册中断处理函数。

 

rte_intr_callback_register(&(pci_dev->intr_handle),

eth_igb_interrupt_handler, (void*)eth_dev);

 

rte_intr_callback_register() 函数,主要工作如下:

1、首先申请一个 structrte_intr_source 变量。


struct rte_intr_source {

  TAILQ_ENTRY(rte_intr_source) next;

  struct rte_intr_handle intr_handle; /**<interrupt handle */

  struct rte_intr_cb_list callbacks;  /**< user callbacks */

  uint32_t active;

};

 

2、将中断处理函数 eth_igb_interrupt_handler,添加到 rte_intr_source->callbacks 链表中。

3、再将该 rte_intr_source 挂到全局 intr_sources 链表中,方便中断处理线程遍历调用。


文章来源

http://www.cnblogs.com/MerlinJ/p/4104039.html

 

### 问题分析 在 DPDK 的 testpmd 应用程序中,中断错误可能由多种原因引起。常见的问题包括硬件兼容性、驱动配置不当、内存分配问题以及 NUMA 架构下的资源分配错误等。testpmd 是一个用于测试和验证 DPDK 功能的示例应用程序,广泛用于调试网络接口卡(NIC)与 DPDK 的交互过程。因此,解决中断错误需要从多个方面入手。 ### 常见原因及解决方法 #### 1. **检查网卡驱动支持情况** 确保使用的 NIC 被 DPDK 支持,并且正确加载了相应的 PMD(Poll Mode Driver)。DPDK 提供了对 Intel、Mellanox 等厂商网卡的支持[^2]。如果驱动未正确加载,可能会导致中断处理失败。 ```bash dpdk-devbind.py --status ``` 上述命令可以查看当前设备是否被正确绑定到 `igb_uio` 或 `vfio-pci` 驱动上。若未绑定,可使用以下命令进行绑定: ```bash dpdk-devbind.py -b igb_uio <device_bus_id> ``` #### 2. **检查 EAL 初始化参数** EAL(Environment Abstraction Layer)是 DPDK 的核心组件之一,负责初始化底层资源。中断错误可能源于 EAL 参数设置不正确,例如内存通道数、NUMA 节点分配等。 启动 testpmd 时应指定合适的 EAL 参数,例如: ```bash ./testpmd -l 0-3 -n 4 --socket-mem=1024,1024 -- -i --portmask=0x3 ``` 其中: - `-l` 指定逻辑核心; - `-n` 指定内存通道数; - `--socket-mem` 分配每个 NUMA 节点的内存大小; - `--portmask` 指定启用的端口。 确保内存分配合理,避免因内存不足导致中断异常。 #### 3. **检查中断模式配置** DPDK 默认采用轮询模式(Poll Mode),但在某些场景下仍需启用中断机制,如收包中断触发异步事件处理。可以通过以下方式切换中断模式: ```c rte_eth_dev_info_get(port_id, &dev_info); dev_info.default_rxconf.offloads |= RTE_ETH_RX_OFFLOAD_SCATTER; ``` 此外,在调用 `rte_eth_dev_configure()` 时,需确认是否启用了中断功能: ```c port_conf.intr_conf.lsc = 1; // 启用链路状态中断 ``` 若中断未启用而程序依赖中断通知,则可能导致错误。 #### 4. **检查 VFIO 权限配置** 如果使用 VFIO 驱动,需确保非 root 用户具有访问 `/dev/vfio/vfio` 的权限。可通过以下方式设置: ```bash sudo usermod -a -G vfio <username> ``` 同时,确保 IOMMU 已启用,否则可能导致中断无法正常传递。 #### 5. **查看系统日志进行调试** 使用 `dmesg` 或 `journalctl` 查看内核日志,有助于定位中断错误的根本原因: ```bash dmesg | grep -i dpdk ``` 日志中可能包含中断请求失败、内存映射错误等关键信息。 #### 6. **使用 GDB 调试** 若上述方法无法解决问题,可以使用 GDB 对 testpmd 进行调试: ```bash gdb ./testpmd run -l 0-3 -n 4 --socket-mem=1024,1024 -- -i --portmask=0x3 ``` 在发生中断错误时,GDB 可以捕获堆栈信息并帮助定位出错函数。 ### 示例:testpmd 中断使能代码片段 以下是一个典型的中断使能配置示例: ```c struct rte_eth_conf port_conf = { .rxmode = { .mq_mode = RTE_ETH_MQ_RX_RSS, }, .intr_conf = { .lsc = 1, // 启用链路状态中断 }, }; rte_eth_dev_configure(port_id, 1, 1, &port_conf); ``` 该配置启用链路状态中断(Link Status Change Interrupt),适用于监控物理连接状态变化。 ---
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值