实验二 利用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. */
版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系QQ:729038198,我们将在24小时内删除。
发表评论