实验二 利用DPDK构造并发送数据包
一、实验目的
1.学会编写和测试DPDK发包程序
2.理解DPDK实现高性能收发包的原理
二、实验内容
1.编写一个DPDK程序,实现如下功能:直接构造一个数据包(内容任意),要求数据包的协议头符合UDP/IP/Ethernet协议规范,并将其发送出去。该程序基于skeleton程序修改得到,附录中给出一个供参考的编程框架。
2.使用tcpdump命令,抓取数据包,观察各协议头的字段值,确认实际输出与程序意图是否一致。
过程举例:
1.//在命令行窗口运行如下命令 
2.//抓取经过指定网卡含有特定端口号的数据包 
3.sudo tcpdump -vv -A -e -i <网卡名称> port <端口号> 
4.//然后在另一窗口运行DPDK程序 
5. 
6.//注意:tcpdump只能在内核驱动网卡上抓取数据包 
7.//tcpdump的更多用法可参阅相关资料 
三、回答问题
官方文档:DPDK documentation, DPDK API
注意:不同版本DPDK对应的文档内容也不完全一样,应对应查看
1.UDP协议头的cksum是必须的吗?不是的话应当如何设置
2.DPDK为IP协议头的cksum计算提供了专用函数,请在相关文档中到它,并应用在程序中,调用该函数的注意事项是什么?
3.DPDK实现高性能收发包的原理是什么?
四、思考题
参照本实验,一个接收数据包并处理其中数据的DPDK程序应该如何实现?
五、进展报告
本实验的完成情况以及对以上3个问题的回答作为第二阶段的进展报告,于 11 月 2日23:59之前上传到202.38.75.243:5050/。11月5日课堂讨论。
进展报告中需注明小组成员(组长排在第一个),以及每位成员对该报告的贡献比例。上课前各小组做好PPT,以备报告。文件命名及格式:第二阶段_组长姓名.pdf。
实验过程中遇到任何问题,请及时发邮件给助教(linfei@mail.ustc.edu),并抄送一份给主讲老师。
六、附录
首先在example目录下新建一个目录用于本实验。可以看到,example/skeleton目录中有Makefile和meson.build这两个文件,各拷贝一份到新建的目录中,将其中的文件名修改为你的主程序文件名。
注意:
1)主机字节顺序和网络字节顺序的转换
2)某些字段值可使用宏定义,如IPVERSION
3)可以使用的常用函数如inet_addr()
4)各协议头对应的结构体有不同的版本,既可以使用经典版本(如Ethernut),也可以使用DPDK自带的版本(DPDK_Data_Structure),结构体中包含的数据项可以参阅相关文档
以下程序代码基于skeleton修改得来,主要是增加了一个build_udp_packet函数,并需要在其中补充相关代码。
1./* SPDX-License-Identifier: BSD-3-Clause  
2. * Copyright(c) 2010-2015 Intel Corporation  
3. */ 
4. 
5.#include <stdint.h> 
6.#include <unistd.h> 
7.#include <stdbool.h> 
8.#include <inttypes.h> 
9.#include <rte_eal.h> 
10.#include <rte_ethdev.h> 
11.#include <rte_cycles.h> 
12.#include <rte_lcore.h> 
13.#include <rte_mbuf.h> 
14.#include <rte_ip.h> 
15. 
16.#include <pcap/pcap.h> 
17.#include <netinet/ip.h> 
18.#include <netinet/in.h> 
19.#include <rte_ether.h> 
20.#include <rte_udp.h> 
21.#include <arpa/inet.h> 
22. 
23.#define RX_RING_SIZE 1024 
24.#define TX_RING_SIZE 1024 
25. 
26.#define NUM_MBUFS 8191 
27.#define MBUF_CACHE_SIZE 250 
28.#define BURST_SIZE 32 
29. 
30.struct rte_mempool *mbuf_pool; 
31. 
32.static const struct rte_eth_conf port_conf_default = { 
33.    .rxmode = { 
34.        .max_rx_pkt_len = ETHER_MAX_LEN, 
35.    }, 
36.}; 
37. 
38.static inline int 
39.port_init(uint16_t port, struct rte_mempool *mbuf_pool) 
40.
41.    struct rte_eth_conf port_conf = port_conf_default; 
42.    const uint16_t rx_rings = 1, tx_rings = 1; 
43.    uint16_t nb_rxd = RX_RING_SIZE; 
44.    uint16_t nb_txd = TX_RING_SIZE; 
45.    int retval; 
46.    uint16_t q; 
47.    struct rte_eth_dev_info dev_info; 
48.    struct rte_eth_txconf txconf; 
49. 
50.    if (!rte_eth_dev_is_valid_port(port)) 
51.        returnconf -1; 
52. 
53.    rte_eth_dev_info_get(port, &dev_info); 
54.    if (_offload_capa & DEV_TX_OFFLOAD_MBUF_FAST_FREE) 
55.        de.offloads |= 
56.            DEV_TX_OFFLOAD_MBUF_FAST_FREE; 
57. 
58.    /* Configure the Ethernet device. */ 
59.    retval = rte_eth_dev_configure(port, rx_rings, tx_rings, &port_conf); 
60.    if (retval != 0) 
61.        return retval; 
62. 
63.    retval = rte_eth_dev_adjust_nb_rx_tx_desc(port, &nb_rxd, &nb_txd); 
64.    if (retval != 0) 
65.        return retval; 
66. 
67.    /* Allocate and set up 1 RX queue per Ethernet port. */ 
68.    for (q = 0; q < rx_rings; q++) { 
69.        retval = rte_eth_rx_queue_setup(port, q, nb_rxd, 
70.                rte_eth_dev_socket_id(port), NULL, mbuf_pool); 
71.        if (retval < 0) 
72.            return retval; 
73.    } 
74. 
75.    txconf = dev_info.default_txconf; 
76.    txconf.offloads = de.offloads; 
77.    /* Allocate and set up 1 TX queue per Ethernet port. */ 
78.    for (q = 0; q < tx_rings; q++) { 
79.        retval = rte_eth_tx_queue_setup(port, q, nb_txd, 
80.                rte_eth_dev_socket_id(port), &txconf); 
81.        if (retval < 0) 
82.            return retval; 
83.    } 
84. 
85.    /* Start the Ethernet port. */ 
86.    retval = rte_eth_dev_start(port); 
87.    if (retval < 0) 
88.        return retval; 
89. 
90.    /* Display the port MAC address. */ 
91.    struct ether_addr addr; 
92.    rte_eth_macaddr_get(port, &addr); 
93.    printf("Port %u MAC: %02" PRIx8 " %02" PRIx8 " %02" PRIx8 
94.               " %02" PRIx8 " %02" PRIx8 " %02" PRIx8 "\n"
95.            port, 
96.            addr.addr_bytes[0], addr.addr_bytes[1], 
97.            addr.addr_bytes[2], addr.addr_bytes[3], 
98.            addr.addr_bytes[4], addr.addr_bytes[5]); 
99. 
100.    /* Enable RX in promiscuous mode for the Ethernet device. */