Line data Source code
1 :
2 : #include <string.h>
3 : #include <stdbool.h>
4 : #include <limits.h>
5 : #include <time.h>
6 : #include <unistd.h>
7 :
8 : #include <libxml/xmlmemory.h>
9 : #include <libxml/parser.h>
10 :
11 : #include <vtest.h>
12 : #include <nl_util.h>
13 : #include "include/vt_packet.h"
14 : #include <vt_main.h>
15 : #include <vt_gen_message_modules.h>
16 : #include <vr_types.h>
17 : #include <vt_gen_lib.h>
18 :
19 : #include <vr_message.h>
20 : #include <vr_packet.h>
21 : #include <vr_interface.h>
22 : #include <vr_dpdk_usocket.h>
23 :
24 : #include "vt_packet.h"
25 :
26 : static int
27 : tx_rx_pcap_test(struct vtest *test);
28 :
29 : /**
30 : * vt_file_name_assign - assign relative file name by concatinating
31 : * test file directory and relative PCAP file name.
32 : */
33 : void
34 194 : vt_fname_assign(struct vtest *test, char *fname, char *rel_name)
35 : {
36 : size_t i, l;
37 :
38 194 : if (rel_name[0] == '/') {
39 0 : strncpy(fname, rel_name, PATH_MAX - 1);
40 : } else {
41 : /* Copy current test directory. */
42 194 : l = strlen(test->file_name);
43 194 : if (l > PATH_MAX)
44 0 : l = PATH_MAX;
45 7639 : for (i = l; i > 0; i--) {
46 7639 : if (test->file_name[i] == '/')
47 194 : break;
48 : }
49 : /* If there is no '/' in path, use curr dir */
50 194 : if (i == 0) {
51 0 : strncpy(fname, "." , 1);
52 0 : i++;
53 : } else {
54 194 : strncpy(fname, test->file_name, i);
55 : }
56 194 : fname[i] = '/'; fname[i + 1] = '\0';
57 :
58 : /* Append relative file name. */
59 194 : strncat(fname, rel_name, PATH_MAX - i - 1);
60 : }
61 :
62 194 : return;
63 : }
64 :
65 : /*
66 : * Parse XML structure and set structures packet and packet interface (vtest.h)
67 : */
68 : int
69 126 : vt_packet(xmlNodePtr node, struct vtest *test)
70 : {
71 126 : xmlNodePtr l_node_interface = NULL;
72 126 : node = node->xmlChildrenNode;
73 :
74 1028 : while (node) {
75 :
76 902 : if (node->type == XML_TEXT_NODE) {
77 514 : node = node->next;
78 514 : continue;
79 : }
80 388 : if (!strncmp(node->name, "pcap_input_file", strlen(node->name))) {
81 126 : if (node->children && node->children->content) {
82 126 : if (node->children && node->children->content) {
83 126 : vt_fname_assign(test,
84 126 : test->packet.pcap_file, node->children->content);
85 : }
86 : }
87 :
88 262 : } else if (!strncmp(node->name, "pcap_expected_file", strlen(node->name))) {
89 0 : if (node->children && node->children->content) {
90 0 : vt_fname_assign(test,
91 0 : test->packet.pcap_ref_file, node->children->content);
92 : }
93 262 : } else if (!strncmp(node->name, "pcap_output_file", strlen(node->name))) {
94 68 : if (node->children && node->children->content) {
95 68 : vt_fname_assign(test,
96 68 : test->packet.pcap_dest_file, node->children->content);
97 : }
98 194 : } else if (!strncmp(node->name, "tx_interface", strlen(node->name))) {
99 :
100 126 : l_node_interface = node;
101 126 : l_node_interface = l_node_interface->xmlChildrenNode;
102 :
103 252 : while (l_node_interface) {
104 252 : if (l_node_interface->type != XML_ELEMENT_NODE) {
105 126 : l_node_interface = l_node_interface->next;
106 126 : continue;
107 : }
108 126 : if (l_node_interface->children && l_node_interface->children->content) {
109 126 : strncpy(test->packet_tx.un_socket,
110 126 : l_node_interface->children->content, UNIX_PATH_MAX);
111 126 : break;
112 : }
113 0 : l_node_interface = l_node_interface->next;
114 :
115 : }
116 68 : } else if (!strncmp(node->name, "rx_interface", strlen(node->name))) {
117 68 : l_node_interface = node;
118 68 : l_node_interface = l_node_interface->xmlChildrenNode;
119 :
120 136 : while (l_node_interface) {
121 136 : if (l_node_interface->type != XML_ELEMENT_NODE) {
122 68 : l_node_interface = l_node_interface->next;
123 68 : continue;
124 : }
125 68 : if (l_node_interface->children && l_node_interface->children->content) {
126 68 : strncpy(test->packet_rx[test->packet.rx_client_num].un_socket,
127 68 : l_node_interface->children->content, UNIX_PATH_MAX);
128 68 : break;
129 : //for multicast purpose 1:M, multicast is not implemented
130 : test->packet.rx_client_num += 1;
131 : break;
132 : }
133 0 : l_node_interface = l_node_interface->next;
134 : }
135 : }
136 388 : node = node->next;
137 :
138 : }
139 :
140 126 : test->packet_test = 1;
141 126 : return E_PACKET_OK;
142 : }
143 :
144 : int
145 0 : pcap_compare(char *pcap_file_1, char *pcap_file_2) {
146 :
147 0 : struct pcap_pkthdr *pkt_header_1 = NULL;
148 0 : const u_char *pkt_data_1 = NULL;
149 0 : int end_pcap_1 = 0;
150 :
151 0 : char errbuf_1[PCAP_ERRBUF_SIZE] = {0};
152 :
153 0 : struct pcap_pkthdr *pkt_header_2 = NULL;
154 0 : const u_char *pkt_data_2 = NULL;
155 0 : int end_pcap_2 = 0;
156 0 : char errbuf_2[PCAP_ERRBUF_SIZE] = {0};
157 :
158 0 : printf("Comparing reference file with %s...\n", pcap_file_2);
159 0 : pcap_t *p_1 = pcap_open_offline(pcap_file_1, errbuf_1);
160 0 : if (!p_1) {
161 0 : fprintf(stderr, "%s(): Error opening pcap reference file: %s\n",
162 : __func__, errbuf_1);
163 0 : return E_PACKET_PCAP_SETUP_TEST_ERR;
164 : }
165 :
166 0 : pcap_t *p_2 = pcap_open_offline(pcap_file_2, errbuf_2);
167 0 : if (!p_2) {
168 0 : fprintf(stderr, "%s(): Error opening pcap destination file: %s\n",
169 : __func__, errbuf_2);
170 0 : return E_PACKET_PCAP_SETUP_TEST_ERR;
171 : }
172 :
173 : while(true) {
174 :
175 0 : if (pcap_next_ex(p_1, &pkt_header_1, &pkt_data_1) < 0) {
176 0 : end_pcap_1 = true;
177 : }
178 :
179 0 : if (pcap_next_ex(p_2, &pkt_header_2, &pkt_data_2) < 0 ) {
180 0 : end_pcap_2 = true;
181 : }
182 :
183 0 : if (end_pcap_1 != end_pcap_2) {
184 0 : fprintf(stderr, "%s(): Error comparing pcap files: different number of packets\n",
185 : __func__);
186 0 : return E_PACKET_PCAP_FAIL_ERR;
187 :
188 0 : } else if (end_pcap_1 && end_pcap_2) {
189 0 : return E_PACKET_PCAP_OK;
190 : }
191 0 : if (pkt_header_1->len == pkt_header_2->len) {
192 0 : if (memcmp((u_char *) pkt_data_1, (u_char *) pkt_data_2, pkt_header_1->len)) {
193 0 : fprintf(stderr, "%s(): Error comparing pcap files: packet data is different\n",
194 : __func__);
195 0 : return E_PACKET_PCAP_FAIL_ERR;
196 : }
197 :
198 : } else {
199 0 : fprintf(stderr, "%s(): Error comparing pcap files: packet len is different\n",
200 : __func__);
201 0 : return E_PACKET_PCAP_FAIL_ERR;
202 : }
203 :
204 : }
205 :
206 : return E_PACKET_PCAP_OK;
207 : }
208 :
209 : static int inline
210 126 : clean_vtest_struct_packet(struct vtest *test){
211 :
212 126 : if (!test) {
213 0 : return E_PACKET_FARG_ERR;
214 : }
215 :
216 126 : memset(&test->packet, 0, sizeof(struct packet));
217 :
218 126 : return E_PACKET_OK;
219 : }
220 :
221 : int
222 126 : run_pcap_test(struct vtest *test) {
223 :
224 126 : int ret = 0;
225 126 : if (!test) {
226 0 : return E_PACKET_FARG_ERR;
227 : }
228 :
229 126 : ret = tx_rx_pcap_test(test);
230 :
231 126 : if (ret != E_PACKET_OK) {
232 0 : test->vtest_return = E_MAIN_TEST_FAIL;
233 126 : } else if (strlen(test->packet.pcap_ref_file)) {
234 0 : ret = pcap_compare(test->packet.pcap_ref_file, test->packet.pcap_dest_file);
235 :
236 0 : if (ret != E_PACKET_PCAP_OK) {
237 0 : test->vtest_return = E_MAIN_TEST_FAIL;
238 : } else {
239 0 : test->vtest_return = E_MAIN_TEST_PASS;
240 : }
241 : } else {
242 126 : test->vtest_return = E_MAIN_TEST_PASS;
243 126 : ret = 0;
244 : }
245 :
246 126 : clean_vtest_struct_packet(test);
247 :
248 126 : return ret;
249 : }
250 :
251 :
252 : /* TODO Multicast, return parameter */
253 : static int
254 126 : tx_rx_pcap_test(struct vtest *test) {
255 : typedef enum {
256 : S_SEND,
257 : S_RECV,
258 : S_RECV_ERR,
259 : S_RECV_TIMEOUT
260 : } TX_RX_AUTOMATA_STATE;
261 :
262 126 : int ret = 0;
263 126 : char src_vif_ctrl_sock[UNIX_PATH_MAX] = {0};
264 126 : char dst_vif_ctrl_sock[UNIX_PATH_MAX] = {0};
265 :
266 : struct tx_rx_handler tx_rx_handler;
267 126 : vhost_net_state rx_state = E_VHOST_NET_OK;
268 126 : vhost_net_state tx_state = E_VHOST_NET_OK;
269 :
270 : /* Path variable */
271 :
272 126 : char pcap_dest[PATH_MAX] = {0};
273 126 : bool send_only = false;
274 :
275 126 : if ((test->packet.pcap_ref_file[0] == '\0') &&
276 126 : (test->packet.pcap_dest_file[0] == '\0')) {
277 58 : send_only = true;
278 : }
279 :
280 126 : if (!strlen(test->packet.pcap_dest_file)) {
281 58 : ret = snprintf(pcap_dest, PATH_MAX, "/tmp/dest_%u.pcap", (unsigned)(time(NULL)));
282 58 : strncpy(test->packet.pcap_dest_file, pcap_dest, strlen(pcap_dest));
283 : }
284 :
285 126 : ret = snprintf(src_vif_ctrl_sock, UNIX_PATH_MAX, "%s/uvh_vif_%s",
286 126 : vr_socket_dir, test->packet_tx.un_socket);
287 126 : if (!send_only) {
288 68 : ret = snprintf(dst_vif_ctrl_sock, UNIX_PATH_MAX, "%s/uvh_vif_%s",
289 68 : vr_socket_dir, test->packet_rx[0].un_socket);
290 : }
291 :
292 126 : memset(&tx_rx_handler, 0, sizeof(struct tx_rx_handler));
293 :
294 126 : tx_state = init_vhost_net(&tx_rx_handler.send_data, src_vif_ctrl_sock, 1);
295 126 : if (!send_only) {
296 68 : rx_state = init_vhost_net(&tx_rx_handler.recv_data, dst_vif_ctrl_sock, 1);
297 : }
298 :
299 126 : if (tx_state != E_VHOST_NET_OK || rx_state != E_VHOST_NET_OK) {
300 0 : return E_PACKET_ERR;
301 : }
302 :
303 126 : memset(&tx_rx_handler.errbuf, 0, sizeof(char) * PCAP_ERRBUF_SIZE);
304 126 : tx_rx_handler.p = pcap_open_offline(test->packet.pcap_file, tx_rx_handler.errbuf);
305 126 : if (!tx_rx_handler.p) {
306 0 : fprintf(stderr, "%s(): Error opening pcap offline: %s\n",
307 : __func__, tx_rx_handler.errbuf);
308 0 : return E_PACKET_PCAP_SETUP_TEST_ERR;
309 : }
310 :
311 126 : tx_rx_handler.pd = pcap_open_dead(DLT_EN10MB, 1 << 16);
312 126 : if (!tx_rx_handler.pd) {
313 0 : fprintf(stderr, "%s(): Error opening pcap dead\n", __func__);
314 0 : return E_PACKET_PCAP_SETUP_TEST_ERR;
315 : }
316 :
317 252 : tx_rx_handler.dumper = pcap_dump_open(tx_rx_handler.pd,
318 126 : test->packet.pcap_dest_file);
319 126 : if (!tx_rx_handler.dumper) {
320 0 : fprintf(stderr, "%s(): Error opening pcap dump: %s\n",
321 : __func__, pcap_geterr(tx_rx_handler.pd));
322 0 : return E_PACKET_PCAP_SETUP_TEST_ERR;
323 : }
324 :
325 126 : gettimeofday(&tx_rx_handler.tv_before, NULL);
326 :
327 126 : int return_val_tx = 0;
328 126 : int return_val_rx = 0;
329 :
330 126 : TX_RX_AUTOMATA_STATE tx_rx_state = S_SEND;
331 :
332 126 : unsigned int read_try = 0 ;
333 :
334 : //TODO: Burst
335 : // We need to be sure, that vRouter has empty desc for writing packets. -> sleep(1);
336 126 : sleep(1);
337 :
338 : while(1) {
339 : //Now we can send next data
340 2148528306 : if (tx_rx_state == S_SEND) {
341 285 : if (pcap_next_ex(tx_rx_handler.p, &tx_rx_handler.pkt_header, &tx_rx_handler.pkt_data) == -2) {
342 125 : break;
343 : }
344 :
345 160 : return_val_tx = (tx_rx_handler.send_data->tx(
346 160 : tx_rx_handler.send_data->context,
347 160 : (u_char *)tx_rx_handler.pkt_data,
348 160 : (size_t *) &(tx_rx_handler.pkt_header->len)));
349 160 : if (!send_only) {
350 84 : tx_rx_state = S_RECV;
351 : } else {
352 76 : usleep(100);
353 : }
354 2148528021 : } else if (tx_rx_state == S_RECV) {
355 2148528021 : return_val_rx = (tx_rx_handler.recv_data->rx(
356 2148528021 : tx_rx_handler.recv_data->context,
357 : &tx_rx_handler.data_dest_buf,
358 : &tx_rx_handler.data_len_recv));
359 :
360 : //If everything is correct e.g. we have space in a ring...
361 : //We can save packet to pcap
362 2148528021 : if (return_val_rx == E_VHOST_NET_OK) {
363 83 : tx_rx_handler.pcap_hdr.caplen = tx_rx_handler.data_len_recv;
364 83 : tx_rx_handler.pcap_hdr.len = tx_rx_handler.pcap_hdr.caplen;
365 83 : (pcap_dump(
366 83 : (u_char*) tx_rx_handler.dumper,
367 : &tx_rx_handler.pcap_hdr,
368 : (u_char *) tx_rx_handler.data_dest_buf));
369 83 : gettimeofday(&tx_rx_handler.tv_after, NULL);
370 83 : tx_rx_handler.pcap_hdr.ts.tv_usec = tx_rx_handler.tv_after.tv_usec - tx_rx_handler.tv_before.tv_usec;
371 83 : tx_rx_handler.pcap_hdr.ts.tv_sec = tx_rx_handler.tv_after.tv_sec - tx_rx_handler.tv_before.tv_sec;
372 :
373 83 : tx_rx_state = S_SEND;
374 83 : read_try = 0;
375 83 : continue;
376 2148527938 : } else if (return_val_rx == E_VHOST_NET_ERR_RECV_PACKET) {
377 : // Try again...
378 2148527938 : if (++read_try > READ_TRY_MAX) {
379 : // ...or give up.
380 1 : fprintf(stderr, "%s(): RX error: pkt not recvd after %u retries.\n",
381 : __func__, read_try);
382 1 : break;
383 : }
384 : } else {
385 0 : fprintf(stderr, "%s(): RX critical error: %d\n",
386 : __func__, return_val_rx);
387 : }
388 : }
389 : }
390 :
391 126 : pcap_close(tx_rx_handler.pd);
392 126 : pcap_dump_close(tx_rx_handler.dumper);
393 126 : deinit_vhost_net(tx_rx_handler.send_data);
394 126 : if (!send_only) {
395 68 : deinit_vhost_net(tx_rx_handler.recv_data);
396 : }
397 :
398 126 : return E_PACKET_OK;
399 : }
400 :
401 :
|