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