• DPDK RX / TX Callbacks 源码阅读


    这个sample是基于basicfw的。basicfw就是一个网口收到的包立即从另一个网口转发出去,非常简洁明了的程序,可以通过basicfw学习基础的DPDK发包API。RX / TX Callbacks 演示在接收和传输的数据包上使用用户定义的回调函数。

    /* SPDX-License-Identifier: BSD-3-Clause
     * Copyright(c) 2010-2015 Intel Corporation
     */
    
    #include <stdint.h>
    #include <inttypes.h>
    #include <rte_eal.h>
    #include <rte_ethdev.h>
    #include <rte_cycles.h>
    #include <rte_lcore.h>
    #include <rte_mbuf.h>
    
    #define RX_RING_SIZE 1024
    #define TX_RING_SIZE 1024
    
    #define NUM_MBUFS 8191
    #define MBUF_CACHE_SIZE 250
    #define BURST_SIZE 32
    
    static const struct rte_eth_conf port_conf_default = {
    	.rxmode = {
    		.max_rx_pkt_len = ETHER_MAX_LEN,
    		.ignore_offload_bitfield = 1,
    	},
    };
    
    static struct {
    	uint64_t total_cycles;
    	uint64_t total_pkts;
    } latency_numbers;
    
    /* 回调函数的函数指针的格式设定:
    一、rx
    typedef uint16_t(* rte_rx_callback_fn)(uint16_t port_id, uint16_t queue, struct rte_mbuf *pkts[], uint16_t nb_pkts, uint16_t max_pkts, void *user_param)
    	参数:
    	1. port id 
    	2. queue index
    	3. 接收的 burst pkt 所存放的 rte_mbuf 的数组
    	4. burst 中数据包的数量
    	5. 可以存储在pkts数组中的最大数据包数。
    	6. 最初配置回调时应用程序传入的任意用户参数
    	
    二、tx
    typedef uint16_t(* rte_tx_callback_fn)(uint16_t port_id, uint16_t queue, struct rte_mbuf *pkts[], uint16_t nb_pkts, void *user_param)
    	参数:
    	1. port id 
    	2. queue index 
    	3. rte_mbuf的数组,里面的pkt即将被发送
    	4. burst 中数据包的数量
    	5. 最初配置回调时应用程序传入的任意用户参数
    */
    
    // rx 队列的回调函数,添加接收时刻的时间戳
    static uint16_t
    add_timestamps(uint16_t port __rte_unused, uint16_t qidx __rte_unused,
    		struct rte_mbuf **pkts, uint16_t nb_pkts,
    		uint16_t max_pkts __rte_unused, void *_ __rte_unused)
    {
    	unsigned i;
    	uint64_t now = rte_rdtsc(); // 用来获取时间戳计数器。
    
    	for (i = 0; i < nb_pkts; i++)
    		pkts[i]->udata64 = now; // 8字节用户数据
    	return nb_pkts;
    }
    
    // tx 队列的回调函数,发送时计算时延
    static uint16_t
    calc_latency(uint16_t port __rte_unused, uint16_t qidx __rte_unused,
    		struct rte_mbuf **pkts, uint16_t nb_pkts, void *_ __rte_unused)
    {
    	uint64_t cycles = 0;
    	uint64_t now = rte_rdtsc();
    	unsigned i;
    
    	for (i = 0; i < nb_pkts; i++)
    		cycles += now - pkts[i]->udata64; // 在main.c中的全局struct中记录收到的包数量和总时延
    	latency_numbers.total_cycles += cycles;
    	latency_numbers.total_pkts += nb_pkts;
    
    	if (latency_numbers.total_pkts > (100 * 1000 * 1000ULL)) { // 每十亿个包计算平均时延
    		printf("Latency = %"PRIu64" cycles
    ",
    		latency_numbers.total_cycles / latency_numbers.total_pkts);
    		latency_numbers.total_cycles = latency_numbers.total_pkts = 0;
    	}
    	return nb_pkts;
    }
    
    /*
     * Initialises a given port using global settings and with the rx buffers
     * coming from the mbuf_pool passed as parameter
     */
    static inline int
    port_init(uint16_t port, struct rte_mempool *mbuf_pool)
    {
    	/*......*/
    	/*上面的部分和basicfw是一摸一样的*/
    
    
    	/* rte_eth_add_rx_callback() 这个API设定一个回调函数,特定 port id 和 rx queue index上每个收到的pkt(burst)都会进行突发调用。
    
    	参数四个:
    		1. port id
    		2. queue index
    		3. 回调函数的函数指针
    		4. 传递给回调函数的参数指针
    
    	返回值是一个指针,可以用于删除回调的API
    
    	rte_eth_add_tx_callback()就是为 tx queue 上的发包配置回调函数。
    	*/
    
    	// 回调函数指针有统一的 typedef
    
    	rte_eth_add_rx_callback(port, 0, add_timestamps, NULL);
    	rte_eth_add_tx_callback(port, 0, calc_latency, NULL);
    
    	return 0;
    }
    
    /*
     * Main thread that does the work, reading from INPUT_PORT
     * and writing to OUTPUT_PORT
     */
    
    // lcore_main 与 basicfw 完全一样。
    static  __attribute__((noreturn)) void
    lcore_main(void)
    {
    	/*......*/
    }
    
    /* Main function, does initialisation and calls the per-lcore functions */
    
    // main 函数也与 basicfw 一样。
    int
    main(int argc, char *argv[])
    {
    	/*......*/
    }
    

    执行情况

    开了之后运行了一会,得到了输出。应该开一个外部的发包器比较好。

    root@ubuntu:/home/chang/dpdk/examples/rxtx_callbacks/build# ./rxtx_callbacks -l 1 -n 4 
    EAL: Detected 8 lcore(s)
    EAL: No free hugepages reported in hugepages-1048576kB
    EAL: Multi-process socket /var/run/.rte_unix
    EAL: Probing VFIO support...
    EAL: PCI device 0000:02:01.0 on NUMA socket -1
    EAL:   Invalid NUMA socket, default to 0
    EAL:   probe driver: 8086:100f net_e1000_em
    EAL: PCI device 0000:02:02.0 on NUMA socket -1
    EAL:   Invalid NUMA socket, default to 0
    EAL:   probe driver: 8086:100f net_e1000_em
    EAL: PCI device 0000:02:03.0 on NUMA socket -1
    EAL:   Invalid NUMA socket, default to 0
    EAL:   probe driver: 8086:100f net_e1000_em
    EAL: PCI device 0000:02:04.0 on NUMA socket -1
    EAL:   Invalid NUMA socket, default to 0
    EAL:   probe driver: 8086:100f net_e1000_em
    Port 0 MAC: 00 0c 29 f7 4d 25
    Port 1 MAC: 00 0c 29 f7 4d 2f
    
    Core 1 forwarding packets. [Ctrl+C to quit]
    Latency = 629 cycles
    Latency = 787 cycles
    ^C
    

    参考

    sample guide:https://doc.dpdk.org/guides/sample_app_ug/rxtx_callbacks.html
    API:ethdev, mbuf

  • 相关阅读:
    无法嵌入互操作类型“-----”。请改用适用的接口
    DataGridView 控件用法(可能不是很全面,因为这是自己常常用到的一些小总结):
    实例化新的一个(new)
    用户 'sa' 登录失败。 (Microsoft SQL Server,错误: 18456)
    开始安装 ASP.NET (4.0.30319.18408)。 出现了错误: 0x8007b799 必须具有此计算机的管理员权限才能运行此工具
    Web 应用程序项目 MvcApplication1 已配置为使用 IIS。
    命名空间中的“MvcBuildViews”。 无效
    SQLServer存储过程入门
    golang fmt格式“占位符”
    go语言基本运算符
  • 原文地址:https://www.cnblogs.com/ZCplayground/p/9323907.html
Copyright © 2020-2023  润新知