pci probe

RTE_PMD_REGISTER_PCI(net_ixgbe, rte_ixgbe_pmd); 宏注册了net_ixgbe driver到pci bus

rte_ixgbe_pmd 的定义如下

static struct rte_pci_driver rte_ixgbe_pmd = {.id_table = pci_id_ixgbe_map,.drv_flags = RTE_PCI_DRV_NEED_MAPPING | RTE_PCI_DRV_INTR_LSC,.probe = eth_ixgbe_pci_probe,.remove = eth_ixgbe_pci_remove,
};

当扫描到到的device 能和pci_id_ixgbe_map 里的id 匹配上时就表示这个device和net_ixgbe 这个driver相匹配,接着便会调用.probe = eth_ixgbe_pci_probe指定的probe函数,这里我们关注下probe 函数对收发报函数的设置

static int
->eth_ixgbe_pci_probe(struct rte_pci_driver *pci_drv __rte_unused,struct rte_pci_device *)->retval = rte_eth_dev_create(&pci_dev->device, pci_dev->device.name,sizeof(struct ixgbe_adapter),eth_dev_pci_specific_init, pci_dev,eth_ixgbe_dev_init, NULL);->eth_ixgbe_dev_init(struct rte_eth_dev *, void *init_params )

eth_ixgbe_dev_init 中会完成driver的初始化,其中就包括了调用 ixgbe_set_tx_function、ixgbe_set_rx_function根据情况设置对应的收发函数

static int
eth_ixgbe_dev_init(struct rte_eth_dev *eth_dev, void *init_params __rte_unused)
{/*省略*/eth_dev->dev_ops = &ixgbe_eth_dev_ops;eth_dev->rx_pkt_burst = &ixgbe_recv_pkts;eth_dev->tx_pkt_burst = &ixgbe_xmit_pkts;eth_dev->tx_pkt_prepare = &ixgbe_prep_pkts;/*省略*/if (rte_eal_process_type() != RTE_PROC_PRIMARY) {struct ixgbe_tx_queue *txq;/* TX queue function in primary, set by last queue initialized* Tx queue may not initialized by primary process*/if (eth_dev->data->tx_queues) {txq = eth_dev->data->tx_queues[eth_dev->data->nb_tx_queues-1];ixgbe_set_tx_function(eth_dev, txq);} else {/* Use default TX function if we get here */PMD_INIT_LOG(NOTICE, "No TX queues configured yet. ""Using default TX function.");}ixgbe_set_rx_function(eth_dev);return 0;   //对于从核只会执行到这里}/*省略*/return 0;
}

设置收发函数

  1. tx函数设置

    • 发送队列offloads为0时

      • 未启用向量 tx_pkt_burst = ixgbe_xmit_pkts_simple
      • 启用向量 dev->tx_pkt_burst = ixgbe_xmit_pkts_vec;
    • 发送队列offloads非0
      • dev->tx_pkt_burst = ixgbe_xmit_pkts
  2. rx函数设置
    • if dev->data->lro设置时

      • adapter->rx_bulk_alloc_allowed 设置,允许bulk时dev->rx_pkt_burst = ixgbe_recv_pkts_lro_bulk_alloc;
      • dev->rx_pkt_burst = ixgbe_recv_pkts_lro_single_alloc;
    • else if dev->data->scattered_rx 设置时
      • dev->data->scattered_rx 设置,支持向量时 dev->rx_pkt_burst = ixgbe_recv_scattered_pkts_vec;
      • adapter->rx_bulk_alloc_allowed 设置支持bulk时 dev->rx_pkt_burst = ixgbe_recv_pkts_lro_bulk_alloc;
      • dev->rx_pkt_burst = ixgbe_recv_pkts_lro_single_alloc;
    • else ifadapter->rx_vec_allowed 设置时
      • dev->rx_pkt_burst = ixgbe_recv_pkts_vec;
    • else if adapter->rx_bulk_alloc_allowed 设置时
      • dev->rx_pkt_burst = ixgbe_recv_pkts_bulk_alloc;
    • else dev->rx_pkt_burst = ixgbe_recv_pkts;

启动网卡及配置收发队列

下面是以L2FWD为例,总结了下dpdk对网卡配置、收发队列配置的API。以下代码做了省略,删除了返回判断代码

int
main(int argc, char **argv)
{   struct lcore_queue_conf *qconf;int ret;uint16_t nb_ports;uint16_t nb_ports_available = 0;uint16_t portid, last_port;unsigned lcore_id, rx_lcore_id;unsigned nb_ports_in_mask = 0;unsigned int nb_lcores = 0;unsigned int nb_mbufs;/* init EAL */ret = rte_eal_init(argc, argv);if (ret < 0)rte_exit(EXIT_FAILURE, "Invalid EAL arguments\n");argc -= ret;argv += ret;force_quit = false;signal(SIGINT, signal_handler);signal(SIGTERM, signal_handler);/* 解析传入的参数 (after the EAL ones) */ret = l2fwd_parse_args(argc, argv);if (ret < 0)rte_exit(EXIT_FAILURE, "Invalid L2FWD arguments\n");printf("MAC updating %s\n", mac_updating ? "enabled" : "disabled");nb_ports = rte_eth_dev_count_avail();if (nb_ports == 0)rte_exit(EXIT_FAILURE, "No Ethernet ports - bye\n");/* check port mask to possible port mask */if (l2fwd_enabled_port_mask & ~((1 << nb_ports) - 1))rte_exit(EXIT_FAILURE, "Invalid portmask; possible (0x%x)\n",(1 << nb_ports) - 1);/*计算所需的mbuf个数*/nb_mbufs = RTE_MAX(nb_ports * (nb_rxd + nb_txd + MAX_PKT_BURST +nb_lcores * MEMPOOL_CACHE_SIZE), 8192U);/* 创建内存池 */l2fwd_pktmbuf_pool = rte_pktmbuf_pool_create("mbuf_pool", nb_mbufs,MEMPOOL_CACHE_SIZE, 0, RTE_MBUF_DEFAULT_BUF_SIZE,rte_socket_id());/* Initialise each port */RTE_ETH_FOREACH_DEV(portid) {struct rte_eth_rxconf rxq_conf;struct rte_eth_txconf txq_conf;struct rte_eth_conf local_port_conf = port_conf;struct rte_eth_dev_info dev_info;/* skip ports that are not enabled */if ((l2fwd_enabled_port_mask & (1 << portid)) == 0) {printf("Skipping disabled port %u\n", portid);continue;}nb_ports_available++;/* init port */printf("Initializing port %u... ", portid);fflush(stdout);rte_eth_dev_info_get(portid, &dev_info);if (dev_info.tx_offload_capa & DEV_TX_OFFLOAD_MBUF_FAST_FREE)local_port_conf.txmode.offloads |=DEV_TX_OFFLOAD_MBUF_FAST_FREE;ret = rte_eth_dev_configure(portid, 1, 1, &local_port_conf);ret = rte_eth_dev_adjust_nb_rx_tx_desc(portid, &nb_rxd,&nb_txd);rte_eth_macaddr_get(portid,&l2fwd_ports_eth_addr[portid]);/* init one RX queue */fflush(stdout);rxq_conf = dev_info.default_rxconf;rxq_conf.offloads = local_port_conf.rxmode.offloads;ret = rte_eth_rx_queue_setup(portid, 0, nb_rxd,rte_eth_dev_socket_id(portid),&rxq_conf,l2fwd_pktmbuf_pool);if (ret < 0)rte_exit(EXIT_FAILURE, "rte_eth_rx_queue_setup:err=%d, port=%u\n",ret, portid);/* init one TX queue on each port */fflush(stdout);txq_conf = dev_info.default_txconf;txq_conf.offloads = local_port_conf.txmode.offloads;ret = rte_eth_tx_queue_setup(portid, 0, nb_txd,rte_eth_dev_socket_id(portid),&txq_conf);/* Initialize TX buffers */tx_buffer[portid] = rte_zmalloc_socket("tx_buffer",RTE_ETH_TX_BUFFER_SIZE(MAX_PKT_BURST), 0,rte_eth_dev_socket_id(portid));if (tx_buffer[portid] == NULL)rte_exit(EXIT_FAILURE, "Cannot allocate buffer for tx on port %u\n",portid);rte_eth_tx_buffer_init(tx_buffer[portid], MAX_PKT_BURST);/*设置错误统计回调函数*/ret = rte_eth_tx_buffer_set_err_callback(tx_buffer[portid],rte_eth_tx_buffer_count_callback,&port_statistics[portid].dropped);/* Start device */ret = rte_eth_dev_start(portid);rte_eth_promiscuous_enable(portid);}if (!nb_ports_available) {rte_exit(EXIT_FAILURE,"All available ports are disabled. Please set portmask.\n");}check_all_ports_link_status(l2fwd_enabled_port_mask);ret = 0;/* launch per-lcore init on every lcore */rte_eal_mp_remote_launch(l2fwd_launch_one_lcore, NULL, CALL_MASTER);RTE_LCORE_FOREACH_SLAVE(lcore_id) {if (rte_eal_wait_lcore(lcore_id) < 0) {ret = -1;break;}}RTE_ETH_FOREACH_DEV(portid) {if ((l2fwd_enabled_port_mask & (1 << portid)) == 0)continue;printf("Closing port %d...", portid);rte_eth_dev_stop(portid);rte_eth_dev_close(portid);printf(" Done\n");}printf("Bye...\n");return ret;
}

rte_eth_dev_configure

rte_eth_dev_configure是EAL对外提供的api(lib/librte_ethdev/rte_ethdev.c),下面分析下dpdk中对网卡设备的配置

rte_eth_rx_queue_setup

rte_eth_rx_queue_setup是EAL对外提供的api(lib/librte_ethdev/rte_ethdev.c),下面分析下dpdk中对队列的配置

  • 在rte_eth_dev_configure中设置的offload属性会被设置到每个队列
  • 调用调用eth_dev_ops中的rx_queue_setup回调函数
    在ixgbe网卡中,对应的rx_queue_setup回调函数是ixgbe_dev_rx_queue_setup


rte_eth_rx_queue_setup就完成了

下面就是启动网卡设备了:

dpdk18.11 收发包流程分析相关推荐

  1. Linux 网络层收发包流程及 Netfilter 框架浅析

    本文作者:sivenzhang,腾讯 IEG 测试开发工程师 1. 前言 本文主要对 Linux 系统内核协议栈中网络层接收,发送以及转发数据包的流程进行简要介绍,同时对 Netfilter 数据包过 ...

  2. 网卡收包流程分析(一)

    由于本人工作内容主要集中于kernel的网络子系统,刚接触这个模块,于是想梳理一下网卡驱动的收包过程,以下内容为个人理解,如有不对,希望大家能够多多指正,相互成长~ 后续会持续更新有关kernel网络 ...

  3. Linux网络层收发包流程及Netfilter框架浅析

    1. 前言 本文主要对 Linux 系统内核协议栈中网络层接收,发送以及转发数据包的流程进行简要介绍,同时对 Netfilter 数据包过滤框架的基本原理以及使用方式进行简单阐述. 内容如有理解错误而 ...

  4. linux 内核vxlan收发包流程

    1.vxlan口收包处理流程 前面几章详细介绍了vxlan接口的使用,而且已经知道vxlan是 MAC IN UDP中的封装,因此,在解封装之前,一切按照原有流程走,在此复习一下内核收发包流程(驱动层 ...

  5. 【无线】【流程】QCA无线驱动收包流程分析

    概述: 无线驱动的收包过程是基于中断的处理方式.在准备接收数据之前,驱动需要先进行初始化接收数据使用到的相关结构( sc_rxbuf和rxfifo ).当数据包到达时,硬件会首先进行 DMA,完成以后 ...

  6. ixgbe网卡驱动 Ⅳ----收发包流程详解

    目录 1 网卡队列收包流程概述 2 ixgbe_ring 结构 3 ixgbe 驱动收包流程 3.1 硬件中断入口 ixgbe_msix_clean_rings/ixgbe_intr 3.2 软中断入 ...

  7. Android 11 热点(softap)流程分析

    最近在做Android 11中热点的功能,主要是网络共享,一个是usb网络共享,一个是热点网络共享,本文只是记录热点分享的流程. 一. settings 里面打开热点的接口跟原来类似 packages ...

  8. Android 11 热点(softap)流程分析(二) WifiManager--AIDL

    Android 10以后引入了stable aidl方法,结合上一篇中WifiManager类中通过aidl调用到WifiServiceImpl类中方法,做个详细的记录. 一.frameworks/b ...

  9. DPDK 网卡收包流程

    Table of Contents 1.Linux网络收发包流程 1.1 网卡与liuux驱动交互 1.2  linux驱动与内核协议栈交互 题外1: 中断处理逻辑 题外2:中断的弊端 2.linux ...

最新文章

  1. java jdbc效率_Java JDBC效率:连接需要多长时间?
  2. Max Sum(经典DP)
  3. 2018年超大规模数据中心总数达到430个
  4. vmware中centos6.4突然无法进入图形界面解决方法
  5. “阿基里斯与乌龟”的终结性思考
  6. h.264并行解码算法分析
  7. iOS:segment对齐原则
  8. TA进阶实例36(MMD pmx导入Unreal流程)
  9. Linux的shell脚本教程(一)
  10. 如何搭建百度离线地图服务
  11. 正则表达式详解及示例
  12. bugku never_give_up file_get_contents()有php://input漏洞 eregi \x00绕过
  13. 【19/04/18 膜赛】土豪聪要请客(stol)
  14. linux命令pp,linux命令 $- 是什么意思
  15. 一堆小众实用工具网站,建议收藏!
  16. 高并发网络服务器设计
  17. 【渗透实战】日常挖洞第二期_旁站注入“花式”漏洞拿下大型服务器
  18. 搜索引擎中输入检索词到返回十条结果,发生了哪些事情
  19. python查看电脑配置_怎么查看电脑配置
  20. 利尔达芯智行:破解两轮出行行业智能化难题

热门文章

  1. matlab张量工具初步
  2. 2017-2018-1 20155301 《信息安全系统设计基础》第7周学习总结
  3. C#:Dockpanel的一些入门的基本操作
  4. 庖丁解牛-----Live555源码彻底解密(根据MediaServer讲解Rtsp的建立过程)
  5. HALCON示例程序sequence_diff.hdev通过两张连续图像进行车辆流量监控
  6. HALCON示例程序color_fuses_lut_trans.hdev通过颜色对保险丝进行分类
  7. HALCON示例程序color_fuses.hdev通过颜色对保险丝进行分类
  8. 做演员是圆梦 做生意学会面对现实
  9. C++ vector.insert的用法
  10. c++分治法求最大最小值实现_程序员:算法导论,分治法、归并排序,伪代码和Java实现...