-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathecho_server.patch
More file actions
219 lines (208 loc) · 8.28 KB
/
Copy pathecho_server.patch
File metadata and controls
219 lines (208 loc) · 8.28 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
diff --git a/src/example/01_recv/recv.c b/src/example/01_recv/recv.c
index 9e4fd33..cdac4bf 100644
--- a/src/example/01_recv/recv.c
+++ b/src/example/01_recv/recv.c
@@ -1,21 +1,62 @@
-
-
#include <rte_eal.h>
#include <rte_ethdev.h>
#include <rte_mbuf.h>
#include <stdio.h>
-#include <arpa/inet.h>
+#include <netinet/in.h>
#define NUM_MBUFS (4096-1)
#define BURST_SIZE 32
+/* utils */
+#define rte_htons rte_cpu_to_be_16
+#define rte_htonl rte_cpu_to_be_32
+
+#define rte_ntohs rte_be_to_cpu_16
+#define rte_ntohl rte_be_to_cpu_32
+
+/* IP network to ascii representation */
+const char *
+inet_ntop2(uint32_t ip)
+{
+ static char buf[16];
+ const unsigned char *bytep;
+
+ bytep = (const unsigned char *)&ip;
+ sprintf(buf, "%d.%d.%d.%d", bytep[0], bytep[1], bytep[2], bytep[3]);
+ return buf;
+}
+
+/*
+ * IP network to ascii representation. To use
+ * for multiple IP address convertion into the same call.
+ */
+char *
+inet_ntoa2(uint32_t ip, char *buf)
+{
+ const unsigned char *bytep;
+
+ bytep = (const unsigned char *)&ip;
+ sprintf(buf, "%d.%d.%d.%d", bytep[0], bytep[1], bytep[2], bytep[3]);
+ return buf;
+}
+/* end of utils */
+
int g_dpdk_port_id = 0; // 端口id
// 端口默认信息
static const struct rte_eth_conf port_conf_default = {
.rxmode = {.max_rx_pkt_len = RTE_ETHER_MAX_LEN }
};
+// 点分十进制ipv4地址变为数字ipv4地址
+#define MAKE_IPV4_ADDR(a, b, c, d) (a + (b<<8) + (c<<16) + (d<<24))
+// 本地ip,即dpdk端口的ip(由于dpdk绕过了内核协议栈所以需要自己设置)
+static uint32_t g_local_ip = MAKE_IPV4_ADDR(10, 66 ,24, 68);
+// 六元组sip,dip,smac,dmac,sport,dport用来发送数据包,由于本项目只用于实验所以以全局变量形式
+static uint32_t g_src_ip;
+static uint32_t g_dst_ip;
+
+static uint8_t g_src_mac[RTE_ETHER_ADDR_LEN];
+static uint8_t g_dst_mac[RTE_ETHER_ADDR_LEN];
+
+static uint16_t g_src_port;
+static uint16_t g_dst_port;
// 绑定网卡,初始化dpdk端口
static void ht_init_port(struct rte_mempool *mbuf_pool) {
@@ -28,21 +69,99 @@ static void ht_init_port(struct rte_mempool *mbuf_pool) {
rte_eth_dev_info_get(g_dpdk_port_id, &dev_info);
// 3. 配置rx队列和tx队列的数量
const int num_rx_queues = 1; // 最多8个
- const int num_tx_queues = 0;
+ const int num_tx_queues = 1; // 写队列设置为1
struct rte_eth_conf port_conf = port_conf_default;
rte_eth_dev_configure(g_dpdk_port_id, num_rx_queues, num_tx_queues, &port_conf);
- // 4. 设置哪一个队列去接收数据, 128是队列承载的数据包最大数量
- if (rte_eth_rx_queue_setup(g_dpdk_port_id, 0 , 128,
+ // 4. 设置哪一个队列去接收数据, 1024是队列承载的数据包最大数量(程序员配置的)
+ if (rte_eth_rx_queue_setup(g_dpdk_port_id, 0 , 1024,
rte_eth_dev_socket_id(g_dpdk_port_id),NULL, mbuf_pool) < 0) {
rte_exit(EXIT_FAILURE, "Could not setup RX queue\n");
}
- // 5. 启动接收队列(在这里只有接收队列,其实是启动g_dpdk_port_id这个端口)
+ // 5. 设置tx队列,tx队列初始化
+ struct rte_eth_txconf txq_conf = dev_info.default_txconf;
+ txq_conf.offloads = port_conf.rxmode.offloads; // 上面的设置:即接收的包多大就发多大的数据包
+ if (rte_eth_tx_queue_setup(g_dpdk_port_id, 0 , 1024, // 参数为: 对应网口,对应的队列,队列最大包数量,socket id,send的配置
+ rte_eth_dev_socket_id(g_dpdk_port_id), &txq_conf) < 0) {
+ rte_exit(EXIT_FAILURE, "Could not setup TX queue\n");
+ }
+
+ // 6. 其实是启动g_dpdk_port_id这个端口,有发送也有接收
if (rte_eth_dev_start(g_dpdk_port_id) < 0 ) {
rte_exit(EXIT_FAILURE, "Could not start\n");
}
}
+// 构建一个最简单的udp包,data参数是要发送的udp的payload
+static int ht_encode_udp_packet(uint8_t *msg, unsigned char *data, uint16_t total_len)
+{
+ // encode 构建udp包
+
+ // 1. ethernet头,以太网头
+ struct rte_ether_hdr *eth = (struct rte_ether_hdr *)msg;
+ rte_memcpy(eth->s_addr.addr_bytes, g_src_mac, RTE_ETHER_ADDR_LEN);
+ rte_memcpy(eth->d_addr.addr_bytes, g_dst_mac, RTE_ETHER_ADDR_LEN);
+ eth->ether_type = rte_htons(RTE_ETHER_TYPE_IPV4);
+
+ // 2 iphdr 设置ip头
+ // msg + sizeof(struct rte_ether_hdr) 相当于eth+1
+ struct rte_ipv4_hdr *ip = (struct rte_ipv4_hdr *)(msg + sizeof(struct rte_ether_hdr));
+ ip->version_ihl = 0x45;
+ ip->type_of_service = 0; // ip的类型
+ ip->total_length = rte_htons(total_len - sizeof(struct rte_ether_hdr)); // 转成网络字节序(大端序)
+ ip->packet_id = 0;
+ ip->fragment_offset = 0;
+ ip->time_to_live = 64; // ttl = 64
+ ip->next_proto_id = IPPROTO_UDP; // ip头要标识下一部分是什么协议
+ ip->src_addr = g_src_ip;
+ ip->dst_addr = g_dst_ip;
+
+ ip->hdr_checksum = 0; // 一开始置0防止checksum计算出错
+ ip->hdr_checksum = rte_ipv4_cksum(ip);
+
+ // 3 udphdr
+ struct rte_udp_hdr *udp = (struct rte_udp_hdr *)(msg + sizeof(struct rte_ether_hdr) + sizeof(struct rte_ipv4_hdr));
+ udp->src_port = g_src_port;
+ udp->dst_port = g_dst_port;
+ uint16_t udplen = total_len - sizeof(struct rte_ether_hdr) - sizeof(struct rte_ipv4_hdr);
+ udp->dgram_len = rte_htons(udplen);
+ // 数据放到udp头之下(udp payload),udp+1为即是以udp hdr为一单位偏移.实为偏移到udp hdr末尾
+ rte_memcpy((uint8_t*)(udp+1), data, udplen);
+
+ udp->dgram_cksum = 0;
+ udp->dgram_cksum = rte_ipv4_udptcp_cksum(ip, udp);
+
+ char ip_buf[16] = {0};
+ printf(" --> src: %s:%d, ", inet_ntoa2(g_src_ip, ip_buf), rte_ntohs(g_src_port)); // 网络字节序大端序转为主机字节序小端序
+
+ printf("dst: %s:%d\n", inet_ntoa2(g_dst_ip, ip_buf), rte_ntohs(g_dst_port));
+
+ return 0;
+
+}
+
+// 发送数据包,参数分别为:内存buffer,payload,length(payload)长度
+static struct rte_mbuf * ht_send_udp(struct rte_mempool *mbuf_pool, uint8_t *data, uint16_t length) {
+
+ // mempool --> mbuf(从mempool里获取数据buffer流)
+
+ const unsigned total_len = length + 42; // 42是eth header + ip hdr + udp hdr
+
+ struct rte_mbuf *mbuf = rte_pktmbuf_alloc(mbuf_pool);
+ if (!mbuf) {
+ rte_exit(EXIT_FAILURE, "rte_pktmbuf_alloc\n");
+ }
+
+ mbuf->pkt_len = total_len; // 包的长度
+ mbuf->data_len = total_len; // 数据的长度
+ // 偏移uint8_t也就是一个字节一个字节处理
+ uint8_t *pktdata = rte_pktmbuf_mtod(mbuf, uint8_t*);
+
+ ht_encode_udp_packet(pktdata, data, total_len);
+
+ return mbuf;
+}
+
int main(int argc, char *argv[]) {
// dpdk环境初始化,巨页,内存,cpu亲和等的设置
@@ -82,17 +201,31 @@ int main(int argc, char *argv[]) {
// udp的头
struct rte_udp_hdr *udphdr = (struct rte_udp_hdr *)(iphdr + 1);
- uint16_t length = ntohs(udphdr->dgram_len); // 两个字节以上都要转换ntohs
+ // 发送包所需要的六元组dmac,sip,dip,sport,dport获取并填充
+ // 由于是发echo reply所以需要交换。比如dmac是取获取到的包的smac
+ rte_memcpy(g_dst_mac, ehdr->s_addr.addr_bytes, RTE_ETHER_ADDR_LEN);
+
+ rte_memcpy(&g_src_ip, &iphdr->dst_addr, sizeof(uint32_t));
+ rte_memcpy(&g_dst_ip, &iphdr->src_addr, sizeof(uint32_t));
+
+ rte_memcpy(&g_src_port, &udphdr->dst_port, sizeof(uint16_t));
+ rte_memcpy(&g_dst_port, &udphdr->src_port, sizeof(uint16_t));
+
+ uint16_t length = rte_ntohs(udphdr->dgram_len); // 两个字节以上都要转换ntohs
*((char*)udphdr + length) = '\0'; // 最后一段置为0
// 打印接收到的udp数据
- struct in_addr addr;
- addr.s_addr = iphdr->src_addr;
- printf("src: %s:%d, ", inet_ntoa(addr), udphdr->src_port);
+ char ip_buf[16] = {0};
+ printf("src: %s:%d, ", inet_ntoa2(iphdr->src_addr, ip_buf), udphdr->src_port);
+
+ printf("dst: %s:%d, %s\n", inet_ntoa2(iphdr->src_addr, ip_buf), udphdr->src_port, (char *)(udphdr+1));
+
+ // 发送udp echo
+ struct rte_mbuf *txbuf = ht_send_udp(mbuf_pool, (uint8_t *)(udphdr+1), length);
+ rte_eth_tx_burst(g_dpdk_port_id, 0, &txbuf, 1);// rte_eth_rx_burst发送数据
+ rte_pktmbuf_free(txbuf); // 发送用的mbuf同样放回到内存池中
- addr.s_addr = iphdr->dst_addr;
- printf("dst: %s:%d, %s\n", inet_ntoa(addr), udphdr->src_port, (char *)(udphdr+1));
rte_pktmbuf_free(mbufs[i]); // 放回内存池
}
}
}
-}
\ No newline at end of file
+}