LCOV - code coverage report
Current view: top level - root/contrail/vrouter/utils/vtest - vt_packet.c (source / functions) Hit Total Coverage
Test: OpenSDN C/C++ coverage (all TARGET_SET jobs) Lines: 140 197 71.1 %
Date: 2026-08-03 02:19:58 Functions: 5 6 83.3 %
Legend: Lines: hit not hit

          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             : 

Generated by: LCOV version 1.14