DPDK网卡PMD驱动

/home/user/dpdk-stable-18.11.11/drivers/net/i40e目录下的驱动为例

源代码文件有

# ls
base           i40e_ethdev_vf.c  i40e_logs.h  i40e_regs.h  i40e_rxtx_vec_altivec.c  i40e_rxtx_vec_neon.c  i40e_vf_representor.c  rte_pmd_i40e.c
i40e_ethdev.c  i40e_fdir.c       i40e_pf.c    i40e_rxtx.c  i40e_rxtx_vec_avx2.c     i40e_rxtx_vec_sse.c   Makefile               rte_pmd_i40e.h
i40e_ethdev.h  i40e_flow.c       i40e_pf.h    i40e_rxtx.h  i40e_rxtx_vec_common.h   i40e_tm.c             meson.build            rte_pmd_i40e_version.map
# ls base/
i40e_adminq.c      i40e_alloc.h   i40e_dcb.h     i40e_diag.h  i40e_lan_hmc.c  i40e_osdep.h      i40e_status.h  README
i40e_adminq_cmd.h  i40e_common.c  i40e_devids.h  i40e_hmc.c   i40e_lan_hmc.h  i40e_prototype.h  i40e_type.h    virtchnl.h
i40e_adminq.h      i40e_dcb.c     i40e_diag.c    i40e_hmc.h   i40e_nvm.c      i40e_register.h   meson.build

从Makefile可以看出PMD驱动最终编译生成librte_pmd_i40e.a静态链接库文件,依赖的静态库有librte_eal.a, librte_mbuf.a, librte_mempool.a, librte_ring.a, librte_ethdev.a, librte_net.a, librte_kvargs.a, librte_hash.a, librte_bus_pci.a 。

# SPDX-License-Identifier: BSD-3-Clause
# Copyright(c) 2010-2017 Intel Corporation

include $(RTE_SDK)/mk/rte.vars.mk

#
# library name
#
LIB = librte_pmd_i40e.a

CFLAGS += -O3
CFLAGS += $(WERROR_FLAGS) -DPF_DRIVER -DVF_DRIVER -DINTEGRATED_VF
CFLAGS += -DX722_A0_SUPPORT
CFLAGS += -DALLOW_EXPERIMENTAL_API

LDLIBS += -lrte_eal -lrte_mbuf -lrte_mempool -lrte_ring
LDLIBS += -lrte_ethdev -lrte_net -lrte_kvargs -lrte_hash
LDLIBS += -lrte_bus_pci

EXPORT_MAP := rte_pmd_i40e_version.map

LIBABIVER := 2

librte_pmd_i40e.a的入口函数为

static struct rte_pci_driver rte_i40e_pmd = {
        .id_table = pci_id_i40e_map,
        .drv_flags = RTE_PCI_DRV_NEED_MAPPING | RTE_PCI_DRV_INTR_LSC |
                     RTE_PCI_DRV_IOVA_AS_VA,
        .probe = eth_i40e_pci_probe,
        .remove = eth_i40e_pci_remove,
};

RTE_PMD_REGISTER_PCI(net_i40e, rte_i40e_pmd);
RTE_PMD_REGISTER_PCI_TABLE(net_i40e, pci_id_i40e_map);
RTE_PMD_REGISTER_KMOD_DEP(net_i40e, "* igb_uio | uio_pci_generic | vfio-pci");

/* i40e_ethdev.c */

eth_i40e_pci_probe->rte_eth_dev_create->eth_i40e_dev_init

static int
eth_i40e_pci_probe(struct rte_pci_driver *pci_drv __rte_unused,
        struct rte_pci_device *pci_dev)
{
        char name[RTE_ETH_NAME_MAX_LEN];
        struct rte_eth_devargs eth_da = { .nb_representor_ports = 0 };
        int i, retval;

        if (pci_dev->device.devargs) {
                retval = rte_eth_devargs_parse(pci_dev->device.devargs->args,
                                &eth_da);
                if (retval)
                        return retval;
        }

        retval = rte_eth_dev_create(&pci_dev->device, pci_dev->device.name,
                sizeof(struct i40e_adapter),
                eth_dev_pci_specific_init, pci_dev,
                eth_i40e_dev_init, NULL);

        if (retval || eth_da.nb_representor_ports < 1)
                return retval;

        /* probe VF representor ports */
        struct rte_eth_dev *pf_ethdev = rte_eth_dev_allocated(
                pci_dev->device.name);

        if (pf_ethdev == NULL)
                return -ENODEV;

        for (i = 0; i < eth_da.nb_representor_ports; i++) {
                struct i40e_vf_representor representor = {
                        .vf_id = eth_da.representor_ports[i],
                        .switch_domain_id = I40E_DEV_PRIVATE_TO_PF(
                                pf_ethdev->data->dev_private)->switch_domain_id,
                        .adapter = I40E_DEV_PRIVATE_TO_ADAPTER(
                                pf_ethdev->data->dev_private)
                };

                /* representor port net_bdf_port */
                snprintf(name, sizeof(name), "net_%s_representor_%d",
                        pci_dev->device.name, eth_da.representor_ports[i]);


                retval = rte_eth_dev_create(&pci_dev->device, name,
                        sizeof(struct i40e_vf_representor), NULL, NULL,
                        i40e_vf_representor_init, &representor);

                if (retval)
                        PMD_DRV_LOG(ERR, "failed to create i40e vf "
                                "representor %s.", name);
        }

        return 0;
}

static int
eth_i40e_dev_init(struct rte_eth_dev *dev, void *init_params __rte_unused)
{
        struct rte_pci_device *pci_dev;
        struct rte_intr_handle *intr_handle;
        struct i40e_pf *pf = I40E_DEV_PRIVATE_TO_PF(dev->data->dev_private);
        struct i40e_hw *hw = I40E_DEV_PRIVATE_TO_HW(dev->data->dev_private);
        struct i40e_vsi *vsi;
        int ret;
        uint32_t len, val;
        uint8_t aq_fail = 0;

        PMD_INIT_FUNC_TRACE();

        dev->dev_ops = &i40e_eth_dev_ops;
        dev->rx_pkt_burst = i40e_recv_pkts;
        dev->tx_pkt_burst = i40e_xmit_pkts;
        dev->tx_pkt_prepare = i40e_prep_pkts;

        /* for secondary processes, we don't initialise any further as primary
         * has already done this work. Only check we don't need a different
         * RX function */
        if (rte_eal_process_type() != RTE_PROC_PRIMARY){
                i40e_set_rx_function(dev);
                i40e_set_tx_function(dev);
                return 0;
        }
        i40e_set_default_ptype_table(dev);
        pci_dev = RTE_ETH_DEV_TO_PCI(dev);
        intr_handle = &pci_dev->intr_handle;

        rte_eth_copy_pci_info(dev, pci_dev);

        pf->adapter = I40E_DEV_PRIVATE_TO_ADAPTER(dev->data->dev_private);
        pf->adapter->eth_dev = dev;
        pf->dev_data = dev->data;

        ........
}

比如收包函数

static inline uint16_t
rte_eth_rx_burst(uint16_t port_id, uint16_t queue_id,
                 struct rte_mbuf **rx_pkts, const uint16_t nb_pkts)

实际调用了

        nb_rx = (*dev->rx_pkt_burst)(dev->data->rx_queues[queue_id],
                                     rx_pkts, nb_pkts);

发包函数

static inline uint16_t
rte_eth_tx_burst(uint16_t port_id, uint16_t queue_id,
                 struct rte_mbuf **tx_pkts, uint16_t nb_pkts)

实际调用了

(*dev->tx_pkt_burst)(dev->data->tx_queues[queue_id], tx_pkts, nb_pkts);

参考资料:

DPDK总结(网卡初始化)_hz5034的博客-CSDN博客

dpdk添加设备基本流程_zhenghuaduo的博客-CSDN博客_local_dev_probe

dpdk PMD_51CTO博客_vpp dpdk

DPDK收发包流程分析(一)_confirmwz的博客-CSDN博客

dpdk + ixgbe adater _ hw 通过pci_map_resource 读写dma寄存器 + 总线地址 + dma读写地址 - tycoon3 - 博客园 (cnblogs.com)

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
DPDK(Data Plane Development Kit)是一个开源的软件开发工具包,用于加速数据平面应用程序的性能。它提供了一组优化的库和驱动程序,可以直接操作网络接口卡(NIC),绕过操作系统内核,实现高性能的数据包处理。 在传统的网络数据包处理中,数据包需要经过操作系统内核的网络协议栈进行处理,这会引入较大的延迟和性能损耗。而使用DPDK,应用程序可以直接访问和操作网络接口卡,绕过内核,从而实现更低的延迟和更高的吞吐量。 DPDK网卡驱动性能提升的主要原因有以下几点: 1. 零拷贝技术:DPDK使用了零拷贝技术,即数据包在内存中的传递过程中避免了不必要的数据拷贝操作。传统的网络数据包处理需要多次数据拷贝,而DPDK通过使用大页内存和直接内存访问(DMA)技术,实现了数据包在内存中的直接传递,减少了数据拷贝带来的性能损耗。 2. 多队列技术:DPDK支持多队列技术,即将网络流量分发到多个队列中进行处理。每个队列都可以由独立的处理核心进行处理,从而实现并行处理,提高了系统的吞吐量和并发性能。 3. 用户态驱动程序:DPDK驱动程序运行在用户态,而不是内核态。这样可以避免用户态和内核态之间的上下文切换,减少了系统调用的开销,提高了数据包处理的性能。 4. 轮询模式:DPDK使用轮询模式来处理数据包,而不是中断模式。传统的网络数据包处理需要通过中断来通知应用程序有新的数据包到达,而DPDK通过轮询方式主动检查网络接口卡上是否有新的数据包到达,减少了中断处理的开销,提高了系统的响应速度和吞吐量。 5. 内存管理:DPDK使用了自己的内存管理机制,通过预先分配大页内存和使用内存池技术,减少了内存分配和释放的开销,提高了系统的性能和稳定性。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值