以/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,
ð_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收发包流程分析(一)_confirmwz的博客-CSDN博客
dpdk + ixgbe adater _ hw 通过pci_map_resource 读写dma寄存器 + 总线地址 + dma读写地址 - tycoon3 - 博客园 (cnblogs.com)