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-11-09 02:10:49 Functions: 5 6 83.3 %
Legend: Lines: hit not hit

          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             : 

Generated by: LCOV version 1.14