LCOV - code coverage report
Current view: top level - root/contrail/vrouter/dpdk - dpdk_vrouter.c (source / functions) Hit Total Coverage
Test: OpenSDN C/C++ coverage (all TARGET_SET jobs) Lines: 299 593 50.4 %
Date: 2026-08-03 02:19:58 Functions: 22 27 81.5 %
Legend: Lines: hit not hit

          Line data    Source code
       1             : /*
       2             :  * Copyright (C) 2014 Semihalf.
       3             :  *
       4             :  * This program is free software; you can redistribute it and/or
       5             :  * modify it under the terms of the GNU General Public License as
       6             :  * published by the Free Software Foundation version 2.
       7             :  *
       8             :  * This program is distributed "as is" WITHOUT ANY WARRANTY of any
       9             :  * kind, whether express or implied; without even the implied warranty
      10             :  * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
      11             :  * GNU General Public License for more details.
      12             :  *
      13             :  * dpdk_vrouter.c -- vRouter/DPDK application
      14             :  *
      15             :  */
      16             : 
      17             : /* For sched_getaffinity() */
      18             : #define _GNU_SOURCE
      19             : 
      20             : #include <stdio.h>
      21             : #include <stdlib.h>
      22             : #include <string.h>
      23             : #include <ctype.h>
      24             : 
      25             : #include <stdint.h>
      26             : #include <getopt.h>
      27             : #include <signal.h>
      28             : #include <sys/time.h>
      29             : #include <unistd.h>
      30             : 
      31             : #include "vr_dpdk.h"
      32             : #include "vr_dpdk_usocket.h"
      33             : #include "vr_dpdk_virtio.h"
      34             : #include "vr_dpdk_pmd_context.h"
      35             : #include "vr_uvhost.h"
      36             : #include "vr_bridge.h"
      37             : #include "vr_mem.h"
      38             : #include "nl_util.h"
      39             : #include "vr_offloads.h"
      40             : 
      41             : #include <rte_version.h>
      42             : #include <rte_errno.h>
      43             : #include <rte_ethdev.h>
      44             : #include <rte_kni.h>
      45             : #include <rte_timer.h>
      46             : 
      47             : 
      48             : /* vRouter/DPDK command-line options. */
      49             : enum vr_opt_index {
      50             : #define NO_DAEMON_OPT           "no-daemon"
      51             :     NO_DAEMON_OPT_INDEX,
      52             : #define NO_HUGE_OPT             "no-huge"
      53             :     NO_HUGE_OPT_INDEX,
      54             : #define HELP_OPT                "help"
      55             :     HELP_OPT_INDEX,
      56             : #define VERSION_OPT             "version"
      57             :     VERSION_OPT_INDEX,
      58             : #define MEMPOOL_SIZE_OPT        "vr_mempool_sz"
      59             :     MEMPOOL_SIZE_OPT_INDEX,
      60             : #define DPDK_TXD_SIZE_OPT       "dpdk_txd_sz"
      61             :     DPDK_TXD_SIZE_OPT_INDEX,
      62             : #define DPDK_RXD_SIZE_OPT       "dpdk_rxd_sz"
      63             :     DPDK_RXD_SIZE_OPT_INDEX,
      64             : #define PACKET_SIZE_OPT         "vr_packet_sz"
      65             :     PACKET_SIZE_OPT_INDEX,
      66             : #define VLAN_TCI_OPT            "vlan_tci"
      67             :     VLAN_TCI_OPT_INDEX,
      68             : #define VLAN_NAME_OPT           "vlan_fwd_intf_name"
      69             :     VLAN_NAME_OPT_INDEX,
      70             : #define LOG_FILE_OPT            "log_file"
      71             :     LOG_FILE_OPT_INDEX,
      72             : #define VTEST_VLAN_OPT          "vtest_vlan"
      73             :     VTEST_VLAN_OPT_INDEX,
      74             : #define VDEV_OPT                "vdev"
      75             :     VDEV_OPT_INDEX,
      76             : #define NO_GRO_OPT              "no-gro"
      77             :     NO_GRO_OPT_INDEX,
      78             : #define NO_GSO_OPT              "no-gso"
      79             :     NO_GSO_OPT_INDEX,
      80             : #define NO_RX_MRG_BUF_OPT       "no-mrgbuf"
      81             :     NO_RX_MRG_BUF_INDEX,
      82             : #define BRIDGE_ENTRIES_OPT      "vr_bridge_entries"
      83             :     BRIDGE_ENTRIES_OPT_INDEX,
      84             : #define BRIDGE_OENTRIES_OPT     "vr_bridge_oentries"
      85             :     BRIDGE_OENTRIES_OPT_INDEX,
      86             : #define FLOW_ENTRIES_OPT        "vr_flow_entries"
      87             :     FLOW_ENTRIES_OPT_INDEX,
      88             : #define OFLOW_ENTRIES_OPT       "vr_oflow_entries"
      89             :     OFLOW_ENTRIES_OPT_INDEX,
      90             : #define MPLS_LABELS_OPT         "vr_mpls_labels"
      91             :     MPLS_LABELS_OPT_INDEX,
      92             : #define NEXTHOPS_OPT            "vr_nexthops"
      93             :     NEXTHOPS_OPT_INDEX,
      94             : #define VRFS_OPT                "vr_vrfs"
      95             :     VRFS_OPT_INDEX,
      96             : #define SOCKET_DIR_OPT          "vr_socket_dir"
      97             :     SOCKET_DIR_OPT_INDEX,
      98             : #define NETLINK_PORT_OPT        "vr_netlink_port"
      99             :     NETLINK_PORT_OPT_INDEX,
     100             : #define SOCKET_MEM_OPT          "socket-mem"
     101             :     SOCKET_MEM_OPT_INDEX,
     102             : #define OFFLOADS_OPT            "offloads"
     103             :     OFFLOADS_OPT_INDEX,
     104             : #define PKT_DROP_LOG_BUFFER_SIZE_OPT "vr_dropstats_bufsz"
     105             :    PKT_DROP_LOG_BUFFER_SIZE_OPT_INDEX,
     106             : #define MEMORY_ALLOC_CHECKS_OPT "vr_memory_alloc_checks"
     107             :     MEMORY_ALLOC_CHECKS_OPT_INDEX,
     108             : #define VR_DPDK_RX_RING_SZ_OPT      "vr_dpdk_rx_ring_sz"
     109             :     VR_DPDK_RX_RING_SZ_OPT_INDEX,
     110             : #define VR_DPDK_TX_RING_SZ_OPT      "vr_dpdk_tx_ring_sz"
     111             :     VR_DPDK_TX_RING_SZ_OPT_INDEX,
     112             : #define VR_DPDK_YIELD_OPT           "yield_option"
     113             :     VR_DPDK_YIELD_OPT_INDEX,
     114             : #define VR_DPDK_LOG_LEVEL        "log-level"
     115             :     VR_DPDK_LOG_OPT_INDEX,
     116             : #define VR_SERVICE_CORE_MASK_OPT    "service_core_mask"
     117             :     VR_SERVICE_CORE_MASK_OPT_INDEX,
     118             : #define VR_DPDK_CTRL_THREAD_MASK_OPT "dpdk_ctrl_thread_mask"
     119             :     VR_DPDK_CTRL_THREAD_MASK_OPT_INDEX,
     120             : #define VR_UNCOND_CLOSE_FLOW_ON_TCP_RST_OPT "vr_uncond_close_flow_on_tcp_rst"
     121             :     VR_UNCOND_CLOSE_FLOW_ON_TCP_RST_OPT_INDEX,
     122             : #define VR_NO_LOAD_BALANCE_OPT       "vr_no_load_balance"
     123             :     VR_NO_LOAD_BALANCE_OPT_INDEX,
     124             : #define VR_DPDK_DDP_OPT          "ddp"
     125             :     VR_DPDK_DDP_OPT_INDEX,
     126             : #define LCORES_OPT              "lcores"
     127             :     LCORES_OPT_INDEX,
     128             :     MAX_OPT_INDEX
     129             : };
     130             : 
     131             : /* dp-core parameters */
     132             : extern unsigned int vr_bridge_entries;
     133             : extern unsigned int vr_bridge_oentries;
     134             : extern unsigned int vr_mpls_labels;
     135             : extern unsigned int vr_nexthops;
     136             : extern unsigned int vr_vrfs;
     137             : extern unsigned int datapath_offloads;
     138             : extern unsigned int vr_pkt_droplog_bufsz;
     139             : extern unsigned int vr_uncond_close_flow_on_tcp_rst;
     140             : 
     141             : unsigned int vr_dpdk_rx_ring_sz = VR_DPDK_RX_RING_SZ;
     142             : unsigned int vr_dpdk_tx_ring_sz = VR_DPDK_TX_RING_SZ;
     143             : unsigned int vr_service_core_mask = 0;
     144             : unsigned int vr_dpdk_ctrl_thread_mask = 0;
     145             : unsigned int vr_dpdk_yield_option = VR_DPDK_YIELD_NO_PACKETS;
     146             : bool vr_no_load_balance = false;
     147             : char service_core_mask_str[VR_DPDK_STR_BUF_SZ];
     148             : char dpdk_ctrl_thread_mask_str[VR_DPDK_STR_BUF_SZ];
     149             : char *service_core_mask_ptr = NULL;
     150             : char *dpdk_ctrl_thread_mask_ptr = NULL;
     151             : char *vr_dpdk_log_level = NULL;
     152             : static char log_string[VR_DPDK_STR_BUF_SZ];
     153             : 
     154             : static int no_daemon_set;
     155             : static int no_gro_set = 0;
     156             : static int no_gso_set = 0;
     157             : int no_huge_set;
     158             : int no_rx_mrgbuf = 0;
     159             : #define DPDK_LOG_FILE_SZ 512
     160             : char dpdk_log_file[512] = "/var/log/contrail/contrail-vrouter-dpdk.log";
     161             : unsigned int vr_mempool_sz = VR_DEF_MEMPOOL_SZ;
     162             : unsigned int vr_rxd_sz = VR_DPDK_NB_RXD;
     163             : unsigned int vr_txd_sz = VR_DPDK_NB_TXD;
     164             : unsigned int vr_packet_sz = VR_DEF_MAX_PACKET_SZ;
     165             : extern char *ContrailBuildInfo;
     166             : 
     167             : /* Global vRouter/DPDK structure */
     168             : struct vr_dpdk_global vr_dpdk;
     169             : 
     170             : /* EAL command line options for rte_eal_init() */
     171             : static char *dpdk_argv[] = {
     172             :     "dpdk",
     173             :     "-n", VR_DPDK_MAX_MEMCHANNELS,
     174             :     "-m", VR_DPDK_DEF_MEM,
     175             :     /* Up to 5 pairs of argument-value (for vdev, lcores, socket-mem options). */
     176             :     NULL, NULL,
     177             :     NULL, NULL,
     178             :     NULL, NULL,
     179             :     NULL, NULL,
     180             :     NULL, NULL
     181             : };
     182             : 
     183             : /* Timestamp logger */
     184             : static FILE *timestamp_log_stream;
     185             : static FILE *dpdk_log = NULL;
     186             : 
     187             : /* A packet mbuf pool constructor with vr_packet support */
     188          53 : void vr_dpdk_pktmbuf_pool_init(struct rte_mempool *mp, void *opaque_arg)
     189             : {
     190             :     struct rte_pktmbuf_pool_private priv;
     191             : 
     192             :     /* Set private mbuf size for vr_packet. */
     193          53 :     priv.mbuf_data_room_size = mp->elt_size - sizeof(struct rte_mbuf)
     194          53 :         - sizeof(struct vr_packet);
     195          53 :     priv.mbuf_priv_size = sizeof(struct vr_packet);
     196             : 
     197          53 :     rte_pktmbuf_pool_init(mp, &priv);
     198          53 : }
     199             : 
     200             : /* The packet mbuf constructor with vr_packet support */
     201             : void
     202      868352 : vr_dpdk_pktmbuf_init(struct rte_mempool *mp, void *opaque_arg, void *_m, unsigned i)
     203             : {
     204      868352 :     struct rte_mbuf *m = _m;
     205             :     struct vr_packet *pkt;
     206      868352 :     rte_pktmbuf_init(mp, opaque_arg, _m, i);
     207             : 
     208             :     /* basic vr_packet initialization */
     209      868352 :     pkt = vr_dpdk_mbuf_to_pkt(m);
     210      868352 :     pkt->vp_head = (unsigned char *)m->buf_addr;
     211      868352 :     pkt->vp_end = m->buf_len;
     212      868352 : }
     213             : 
     214             : /* Create memory pools */
     215             : static int
     216          53 : dpdk_mempools_create(void)
     217             : {
     218          53 :     unsigned int rss_mempool_sz = vr_mempool_sz;
     219          53 :     unsigned int frag_direct_mempool_sz = VR_DPDK_FRAG_DIRECT_MEMPOOL_SZ;
     220          53 :     unsigned int frag_indirect_mempool_sz = VR_DPDK_FRAG_INDIRECT_MEMPOOL_SZ;
     221             : 
     222             :     /* Create the mbuf pool used for RSS */
     223          53 :     vr_dpdk.rss_mempool = rte_mempool_create("rss_mempool",
     224             :             rss_mempool_sz,
     225             :             VR_DPDK_MBUF_HDR_SZ + vr_packet_sz, VR_DPDK_RSS_MEMPOOL_CACHE_SZ,
     226             :             sizeof(struct rte_pktmbuf_pool_private),
     227             :             vr_dpdk_pktmbuf_pool_init, NULL, vr_dpdk_pktmbuf_init, NULL,
     228          53 :             rte_socket_id(), 0);
     229          53 :     if (vr_dpdk.rss_mempool == NULL) {
     230           0 :         RTE_LOG(CRIT, VROUTER, "Error creating RSS mempool: %s (%d)\n",
     231             :             rte_strerror(rte_errno), rte_errno);
     232           0 :         return -rte_errno;
     233             :     }
     234             : 
     235             :     /* Create the mbuf pool used for IP fragmentation (direct mbufs) */
     236          53 :     vr_dpdk.frag_direct_mempool = rte_mempool_create("frag_direct_mempool",
     237             :             frag_direct_mempool_sz, VR_DPDK_FRAG_DIRECT_MBUF_SZ,
     238             :             VR_DPDK_FRAG_DIRECT_MEMPOOL_CACHE_SZ,
     239             :             sizeof(struct rte_pktmbuf_pool_private), rte_pktmbuf_pool_init,
     240          53 :             NULL, rte_pktmbuf_init, NULL, rte_socket_id(), 0);
     241          53 :     if (vr_dpdk.frag_direct_mempool == NULL) {
     242           0 :         RTE_LOG(CRIT, VROUTER, "Error creating FRAG_DIRECT mempool: %s (%d)\n",
     243             :             rte_strerror(rte_errno), rte_errno);
     244           0 :         return -rte_errno;
     245             :     }
     246             : 
     247             :     /* Create the mbuf pool used for IP fragmentation (indirect mbufs) */
     248          53 :     vr_dpdk.frag_indirect_mempool = rte_mempool_create("frag_indirect_mempool",
     249             :             frag_indirect_mempool_sz, VR_DPDK_FRAG_INDIRECT_MBUF_SZ,
     250             :             VR_DPDK_FRAG_INDIRECT_MEMPOOL_CACHE_SZ, 0, rte_pktmbuf_pool_init, NULL,
     251          53 :             rte_pktmbuf_init, NULL, rte_socket_id(), 0);
     252          53 :     if (vr_dpdk.frag_indirect_mempool == NULL) {
     253           0 :         RTE_LOG(CRIT, VROUTER, "Error creating FRAG_INDIRECT mempool: %s (%d)\n",
     254             :             rte_strerror(rte_errno), rte_errno);
     255           0 :         return -rte_errno;
     256             :     }
     257             : 
     258             : #if VR_DPDK_USE_HW_FILTERING
     259             :     int ret, i;
     260             :     char mempool_name[RTE_MEMPOOL_NAMESIZE];
     261             :     unsigned int vm_mempool_sz = VR_DPDK_VM_MEMPOOL_SZ;
     262             : 
     263             :     /* Create a list of free mempools */
     264             :     vr_dpdk.nb_free_mempools = 0;
     265             :     for (i = 0; i < VR_DPDK_MAX_VM_MEMPOOLS; i++) {
     266             :         ret = snprintf(mempool_name, sizeof(mempool_name), "vr_mempool_%d", i);
     267             :         if (ret >= sizeof(mempool_name)) {
     268             :             RTE_LOG(INFO, VROUTER, "Error creating VM mempool %d name\n", i);
     269             :             return -ENOMEM;
     270             :         }
     271             :         vr_dpdk.free_mempools[i] = rte_mempool_create(mempool_name,
     272             :                 vm_mempool_sz, VR_DPDK_MBUF_HDR_SZ + vr_packet_sz, VR_DPDK_VM_MEMPOOL_CACHE_SZ,
     273             :                 sizeof(struct rte_pktmbuf_pool_private),
     274             :                 vr_dpdk_pktmbuf_pool_init, NULL, vr_dpdk_pktmbuf_init, NULL,
     275             :                 rte_socket_id(), 0);
     276             :         if (vr_dpdk.free_mempools[i] == NULL) {
     277             :             RTE_LOG(CRIT, VROUTER, "Error creating VM mempool %d: %s (%d)\n",
     278             :                 i, rte_strerror(rte_errno), rte_errno);
     279             :             return -rte_errno;
     280             :         }
     281             :         vr_dpdk.nb_free_mempools++;
     282             :     }
     283             :     RTE_LOG(INFO, VROUTER, "Allocated %" PRIu16 " VM mempool(s)\n",
     284             :         vr_dpdk.nb_free_mempools);
     285             : #endif
     286             : 
     287          53 :     return 0;
     288             : }
     289             : 
     290             : /*
     291             :  * Figure out a number of CPU cores/threads and compute an affinity mask
     292             :  * which will be passed to EAL initialization in dpdk_init().
     293             :  *
     294             :  * Returns:
     295             :  *      new core mask on success
     296             :  *      VR_DPDK_DEF_LCORE_MASK on failure
     297             :  *      0 if the system does not have enough cores
     298             :  */
     299             : static cpu_set_t
     300          53 : dpdk_core_mask_get(long system_cpus_count)
     301             : {
     302             :     cpu_set_t cs;
     303             :     cpu_set_t cpu_core_mask;
     304             :     cpu_set_t def_cpu_core_mask;
     305             :     int i;
     306             :     long core_mask_count;
     307             : 
     308          53 :     CPU_ZERO(&def_cpu_core_mask);
     309         265 :     for (i = 0; (1 << i) < VR_DPDK_DEF_LCORE_MASK; i++) {
     310         212 :         if ((1 << i) & VR_DPDK_DEF_LCORE_MASK) {
     311         212 :             CPU_SET(i, &def_cpu_core_mask);
     312             :         }
     313             :     }
     314             : 
     315          53 :     CPU_ZERO(&cpu_core_mask);
     316          53 :     if (sched_getaffinity(0, sizeof(cs), &cs) < 0) {
     317           0 :         RTE_LOG(ERR, VROUTER, "Error getting affinity."
     318             :             " Falling back do the default core mask 0x%" PRIx64 "\n",
     319             :                 (uint64_t)(VR_DPDK_DEF_LCORE_MASK));
     320           0 :         return def_cpu_core_mask;
     321             :     }
     322             : 
     323             :     /*
     324             :      * Go through all the CPUs in the cpu_set_t structure to check
     325             :      * if they are available or not. Build an affinity mask based on that.
     326             :      * There is no official way to obtain the mask directly, as there is
     327             :      * no macro for this.
     328             :      *
     329             :      * Due to size of uint64_t, maximum number of supported CPUs is 64.
     330             :      */
     331       54325 :     for (i = 0; i < CPU_SETSIZE; i++) {
     332       54272 :         if (CPU_ISSET(i, &cs))
     333         106 :             CPU_SET(i, &cpu_core_mask);
     334             :     }
     335             : 
     336          53 :     core_mask_count = CPU_COUNT(&cpu_core_mask);
     337          53 :     if (core_mask_count == 0) {
     338           0 :         RTE_LOG(ERR, VROUTER, "Error: core mask is zero."
     339             :             " Falling back do the default core mask 0x%" PRIx64 "\n",
     340             :                 (uint64_t)(VR_DPDK_DEF_LCORE_MASK));
     341           0 :         return def_cpu_core_mask;
     342             :     }
     343             : 
     344             :     /*
     345             :      * Do not allow to run vRouter on all the cores available, as some have
     346             :      * to be spared for virtual machines.
     347             :      */
     348          53 :     core_mask_count = CPU_COUNT(&cpu_core_mask);
     349          53 :     if (core_mask_count == system_cpus_count) {
     350           0 :         RTE_LOG(NOTICE, VROUTER, "Use taskset(1) to set the core mask."
     351             :             " Falling back do the default core mask 0x%" PRIx64 "\n",
     352             :                 (uint64_t)(VR_DPDK_DEF_LCORE_MASK));
     353           0 :         return def_cpu_core_mask;
     354             :     }
     355             : 
     356          53 :     return cpu_core_mask;
     357             : }
     358             : 
     359             : /*
     360             :  * dpdk_shared_io_core_mask_stringify - stringify shared IO core mask
     361             :  * Example: if core mask is 0xf and FWD_LCORES_PER_IO is 2,
     362             :  *          there are will be 4 forwarding lcores: 7@0,8@1,9@2,10@3
     363             :  *          and 2 shared IO lcores: 3@(0,1),4@(2,3)
     364             :  */
     365             : static char *
     366          53 : dpdk_shared_io_core_mask_stringify(cpu_set_t core_set_mask)
     367             : {
     368          53 :     int cpu_id = 0;
     369          53 :     int io_lcore_id = VR_DPDK_IO_LCORE_ID;
     370             :     static char core_mask_string[VR_DPDK_STR_BUF_SZ];
     371             :     static char io_cpus_string[VR_DPDK_STR_BUF_SZ];
     372          53 :     char *p = core_mask_string;
     373          53 :     char *iop = io_cpus_string;
     374          53 :     int nb_fwd_cores = 0;
     375             : 
     376             :     if (!VR_DPDK_USE_IO_LCORES || !VR_DPDK_SHARED_IO_LCORES)
     377          53 :         return "";
     378             : 
     379             :     while (cpu_id < CPU_SETSIZE) {
     380             :         if (CPU_ISSET(cpu_id, &core_set_mask)) {
     381             :             /* add CPU ID to IO lcore string */
     382             :             if (iop != io_cpus_string)
     383             :                 *iop++ = ',';
     384             : 
     385             :             iop += snprintf(iop,
     386             :                     sizeof(io_cpus_string) - (iop - io_cpus_string),
     387             :                     "%d", cpu_id);
     388             :             if (iop - io_cpus_string >= sizeof(io_cpus_string)) {
     389             :                 RTE_LOG(ERR, VROUTER, "Error stringifying IO CPU ID: buffer overflow\n");
     390             :                 return NULL;
     391             :             }
     392             : 
     393             :             nb_fwd_cores++;
     394             :             if (nb_fwd_cores >= VR_DPDK_FWD_LCORES_PER_IO
     395             :                 || cpu_id + 1 >= CPU_SETSIZE) {
     396             :                 if (io_lcore_id > VR_DPDK_LAST_IO_LCORE_ID) {
     397             :                     RTE_LOG(WARNING, VROUTER,
     398             :                         "Warning: IO lcores limit exceeded (%d > %d)\n",
     399             :                         io_lcore_id, VR_DPDK_LAST_IO_LCORE_ID);
     400             :                     break;
     401             :                 }
     402             : 
     403             :                 p += snprintf(p,
     404             :                         sizeof(core_mask_string) - (p - core_mask_string),
     405             :                         "%d@(%s),", io_lcore_id, io_cpus_string);
     406             :                 if (p - core_mask_string >= sizeof(core_mask_string)) {
     407             :                     RTE_LOG(ERR, VROUTER, "Error stringifying IO core mask: buffer overflow\n");
     408             :                     return NULL;
     409             :                 }
     410             : 
     411             :                 io_lcore_id++;
     412             :                 iop = io_cpus_string;
     413             :                 nb_fwd_cores = 0;
     414             :             }
     415             :         }
     416             :         cpu_id++;
     417             :     }
     418             :     *p = '\0';
     419             :     return core_mask_string;
     420             : }
     421             : 
     422             : /*
     423             :  * dpdk_fwd_core_mask_stringify - stringify forwarding and dedicated IO
     424             :  *                                core mask
     425             :  * Example: if core mask is 0x3f and FWD_LCORES_PER_IO is 2,
     426             :  *             there are will be 4 forwarding lcores: 7@1,8@2,9@4,10@5
     427             :  *             and 2 dedicated IO lcores: 3@0,4@3
     428             :  */
     429             : static char *
     430          53 : dpdk_fwd_core_mask_stringify(cpu_set_t core_set_mask)
     431             : {
     432          53 :     int cpu_id = 0;
     433          53 :     int fwd_lcore_id = VR_DPDK_FWD_LCORE_ID;
     434             :     static char core_mask_string[VR_DPDK_STR_BUF_SZ];
     435          53 :     char *p = core_mask_string;
     436          53 :     int io_lcore_id = VR_DPDK_IO_LCORE_ID;
     437          53 :     int nb_fwd_cores = 0;
     438             : 
     439       54325 :     while (cpu_id < CPU_SETSIZE) {
     440       54272 :         if (CPU_ISSET(cpu_id, &core_set_mask)) {
     441         106 :             if (p != core_mask_string)
     442          53 :                 *p++ = ',';
     443             : 
     444         106 :             if (nb_fwd_cores == 0
     445          53 :                 && io_lcore_id == VR_DPDK_LAST_IO_LCORE_ID + 1) {
     446           0 :                 RTE_LOG(WARNING, VROUTER,
     447             :                     "Warning: IO lcores limit exceeded (%d > %d)\n",
     448             :                     io_lcore_id, VR_DPDK_LAST_IO_LCORE_ID);
     449           0 :                 io_lcore_id++;
     450             :             }
     451             :             if (VR_DPDK_USE_IO_LCORES && !VR_DPDK_SHARED_IO_LCORES
     452             :                     && nb_fwd_cores == 0
     453             :                     && io_lcore_id <= VR_DPDK_LAST_IO_LCORE_ID) {
     454             :                 /* first dedicated CPU is an IO lcore */
     455             :                 p += snprintf(p,
     456             :                         sizeof(core_mask_string) - (p - core_mask_string),
     457             :                         "%d@%d", io_lcore_id, cpu_id);
     458             :                 if (p - core_mask_string >= sizeof(core_mask_string)) {
     459             :                     RTE_LOG(ERR, VROUTER, "Error stringifying IO core mask: buffer overflow\n");
     460             :                     return NULL;
     461             :                 }
     462             :                 io_lcore_id++;
     463             :             } else {
     464             :                 /* forwarding lcore */
     465         106 :                 p += snprintf(p,
     466         106 :                         sizeof(core_mask_string) - (p - core_mask_string),
     467             :                         "%d@%d", fwd_lcore_id, cpu_id);
     468         106 :                 if (p - core_mask_string >= sizeof(core_mask_string)) {
     469           0 :                     RTE_LOG(ERR, VROUTER, "Error stringifying forwarding core mask: buffer overflow\n");
     470           0 :                     return NULL;
     471             :                 }
     472         106 :                 fwd_lcore_id++;
     473             :             }
     474             : 
     475         106 :             nb_fwd_cores++;
     476         106 :             if (nb_fwd_cores > VR_DPDK_FWD_LCORES_PER_IO)
     477           0 :                 nb_fwd_cores = 0;
     478             : 
     479             :         }
     480       54272 :         cpu_id++;
     481             :     }
     482          53 :     *p = '\0';
     483          53 :     return core_mask_string;
     484             : }
     485             : 
     486             : /*
     487             :  * dpdk_argv_remove - remove specific argument and value from dpdk_argv[]
     488             :  * Returns 0 on success, < 0 otherwise.
     489             :  */
     490             : static int
     491           0 : dpdk_argv_remove(char *arg)
     492             : {
     493             :     int i;
     494           0 :     int len = strlen(arg);
     495             : 
     496           0 :     for (i = 0; i < RTE_DIM(dpdk_argv) - 1; i++) {
     497           0 :         if (strncmp(dpdk_argv[i], arg, len) == 0) {
     498           0 :             dpdk_argv[i] = NULL;
     499           0 :             dpdk_argv[i + 1] = NULL;
     500           0 :             return 0;
     501             :         }
     502             :     }
     503             : 
     504           0 :     return -1;
     505             : }
     506             : 
     507             : /*
     508             :  * dpdk_argv_append - append argument and value to dpdk_argv[]
     509             :  * Returns 0 on success, < 0 otherwise.
     510             :  */
     511             : static int
     512         106 : dpdk_argv_append(char *arg, char *val)
     513             : {
     514             :     int i;
     515             : 
     516         742 :     for (i = 0; i < RTE_DIM(dpdk_argv) - 1; i++) {
     517         742 :         if (dpdk_argv[i] == NULL && dpdk_argv[i + 1] == NULL) {
     518         106 :             dpdk_argv[i] = arg;
     519         106 :             dpdk_argv[i + 1] = val;
     520         106 :             return 0;
     521             :         }
     522             :     }
     523             : 
     524           0 :     return -1;
     525             : }
     526             : 
     527             : char *
     528           0 : vr_core_mask_util(unsigned int core_mask, char *mask)
     529             : {
     530           0 :     int i = 0, j = 0, k = 0;
     531           0 :     mask[j++] = '(';
     532           0 :     while (core_mask != 0) {
     533           0 :         if ((core_mask & 1) == 1) {
     534           0 :             k = sprintf(mask+j, "%d", i);
     535           0 :             j += k;
     536           0 :             mask[j++] = ',';
     537             :         }
     538           0 :         core_mask >>= 1;
     539           0 :         i++;
     540             :     }
     541           0 :     mask[--j] = ')';
     542           0 :     return mask;
     543             : }
     544             : 
     545             : bool
     546           0 : validate_mask_str(char *str)
     547             : {
     548           0 :      int i = 0;
     549           0 :      if (str[i] != '\0') {
     550           0 :          if (str[i] == '(') {
     551           0 :              i++;
     552           0 :              while ((str[i] != '\0') && (i <= VR_DPDK_STR_BUF_SZ)) {
     553           0 :                 if (str[i] == ')' && str[i+1] == '\0')
     554           0 :                     return true;
     555           0 :                 if (!((str[i] >= '0' && str[i] <= '9') || (str[i] == ',') ||
     556           0 :                       (str[i] == '-')))
     557           0 :                     return false;
     558           0 :                 i++;
     559             :              }
     560             :          } else {
     561           0 :              return  false;
     562             :          }
     563             :      }
     564           0 :      return false;
     565             : }
     566             : 
     567             : /*
     568             :  * dpdk_argv_update - update EAL command line options for rte_eal_init()
     569             :  * Returns number of arguments in dpdk_argv on success, < 0 otherwise.
     570             :  */
     571             : static int
     572          53 : dpdk_argv_update(void)
     573             : {
     574             :     long int system_cpus_count;
     575             :     int i;
     576             :     cpu_set_t core_mask;
     577          53 :     uint64_t old_core_bit_mask = 0, new_core_bit_mask = 0;
     578             :     char *io_core_mask_str;
     579             :     char *fwd_core_mask_str;
     580             :     static char lcores_string[VR_DPDK_STR_BUF_SZ];
     581          53 :     unsigned int rss_mempool_sz = vr_mempool_sz;
     582             : 
     583             :     /* get number of available CPUs */
     584          53 :     system_cpus_count = sysconf(_SC_NPROCESSORS_CONF);
     585          53 :     if (system_cpus_count == -1) {
     586           0 :         system_cpus_count = __builtin_popcountll(
     587             :                 (unsigned long long)VR_DPDK_DEF_LCORE_MASK);
     588             :     }
     589          53 :     if (system_cpus_count == 0)
     590           0 :         return -1;
     591             : 
     592          53 :     core_mask = dpdk_core_mask_get(system_cpus_count);
     593             : 
     594             :     /* calculate number of forwarding and IO lcores */
     595          53 :     vr_dpdk.nb_fwd_lcores = CPU_COUNT(&core_mask);
     596          53 :     vr_dpdk.nb_io_lcores = 0;
     597             :     if (VR_DPDK_USE_IO_LCORES) {
     598             :         if (VR_DPDK_SHARED_IO_LCORES) {
     599             :             vr_dpdk.nb_io_lcores = (vr_dpdk.nb_fwd_lcores + VR_DPDK_FWD_LCORES_PER_IO - 1)
     600             :                                     /VR_DPDK_FWD_LCORES_PER_IO;
     601             :             if (vr_dpdk.nb_io_lcores > VR_DPDK_MAX_IO_LORES)
     602             :                 vr_dpdk.nb_io_lcores = VR_DPDK_MAX_IO_LORES;
     603             :         } else {
     604             :             vr_dpdk.nb_io_lcores = (vr_dpdk.nb_fwd_lcores + VR_DPDK_FWD_LCORES_PER_IO)
     605             :                                     /(VR_DPDK_FWD_LCORES_PER_IO + 1);
     606             :             if (vr_dpdk.nb_io_lcores > VR_DPDK_MAX_IO_LORES)
     607             :                 vr_dpdk.nb_io_lcores = VR_DPDK_MAX_IO_LORES;
     608             :             vr_dpdk.nb_fwd_lcores -= vr_dpdk.nb_io_lcores;
     609             :         }
     610             :     }
     611             : 
     612             :     /* sanity checks */
     613          53 :     if (vr_dpdk.nb_fwd_lcores <= 1) {
     614           0 :         RTE_LOG(ERR, VROUTER, "Error configuring lcores: forwarding lcores should be more than 1\n");
     615           0 :         return -1;
     616             :     }
     617             : 
     618          53 :     if (vr_dpdk.nb_fwd_lcores > VR_MAX_CPUS_DPDK - VR_DPDK_FWD_LCORE_ID) {
     619           0 :         RTE_LOG(ERR, VROUTER, "Error configuring lcores: number of forwarding cores exceeds maximum of %u\n",
     620             :                 VR_MAX_CPUS_DPDK - VR_DPDK_FWD_LCORE_ID);
     621           0 :         return -1;
     622             :     }
     623             : 
     624             : 
     625          53 :     if (vr_dpdk.nb_io_lcores > 1
     626           0 :         && vr_dpdk.nb_fwd_lcores == VR_DPDK_FWD_LCORES_PER_IO*(vr_dpdk.nb_io_lcores - 1)) {
     627             :         /*
     628             :          * The last IO lcore has no forwarding lcores.
     629             :          * Decrease the number of IO lcores and continue.
     630             :          */
     631           0 :         RTE_LOG(INFO, VROUTER, "Adjusting number of IO lcores: %u -> %u\n",
     632             :             vr_dpdk.nb_io_lcores, vr_dpdk.nb_io_lcores - 1);
     633           0 :         vr_dpdk.nb_io_lcores--;
     634             :         /* remove the leftmost bit from the core mask */
     635           0 :         for (i = 0; i < 64; i++) {
     636           0 :             if (CPU_ISSET(i, &core_mask)) {
     637           0 :                 old_core_bit_mask |= 1 << i;
     638             :             }
     639             :         }
     640           0 :         for (i = 32; i < 64; i++) {
     641           0 :             CPU_CLR(i, &core_mask);
     642             :         }
     643           0 :         for (i = 0; i < 32; i++) {
     644           0 :             if (CPU_ISSET(i, &core_mask)) {
     645           0 :                 new_core_bit_mask |= 1 << i;
     646             :             }
     647             :         }
     648           0 :         RTE_LOG(INFO, VROUTER, "Adjusting core mask: 0x%"PRIx64" -> 0x%"PRIx64"\n",
     649             :             old_core_bit_mask, new_core_bit_mask);
     650             :     }
     651             : 
     652          53 :     io_core_mask_str = dpdk_shared_io_core_mask_stringify(core_mask);
     653          53 :     if (io_core_mask_str == NULL)
     654           0 :         return -1;
     655             : 
     656          53 :     fwd_core_mask_str = dpdk_fwd_core_mask_stringify(core_mask);
     657          53 :     if (fwd_core_mask_str == NULL)
     658           0 :         return -1;
     659             : 
     660          53 :     if (vr_service_core_mask != 0) {
     661           0 :         service_core_mask_ptr = vr_core_mask_util(vr_service_core_mask,
     662             :                                 service_core_mask_str);
     663          53 :     } else if (!service_core_mask_ptr) {
     664          53 :         sprintf(service_core_mask_str, "(0-%ld)", (system_cpus_count - 1));
     665          53 :         service_core_mask_ptr = service_core_mask_str;
     666             :     }
     667             : 
     668          53 :     if (vr_dpdk_ctrl_thread_mask != 0) {
     669           0 :         dpdk_ctrl_thread_mask_ptr = vr_core_mask_util(vr_dpdk_ctrl_thread_mask,
     670             :                         dpdk_ctrl_thread_mask_str);
     671             :     }
     672          53 :     if (dpdk_ctrl_thread_mask_ptr) {
     673           0 :         if (dpdk_argv_append("-C", dpdk_ctrl_thread_mask_ptr) != 0)
     674           0 :             return -1;
     675             :     }
     676             : 
     677             :     /* lcores order: service, IO, lcores with TX queues, forwaridng lcores */
     678          53 :     if (snprintf(lcores_string, sizeof(lcores_string),
     679             :         "(0-%d)@%s,%s(%d-%d)@%s,%s",
     680             :         VR_DPDK_IO_LCORE_ID - 1, service_core_mask_ptr,
     681             :         io_core_mask_str,
     682             :         VR_DPDK_PACKET_LCORE_ID, VR_DPDK_FWD_LCORE_ID - 1, service_core_mask_ptr,
     683             :         fwd_core_mask_str)
     684             :             >= sizeof(lcores_string)) {
     685           0 :         return -1;
     686             :     }
     687             : 
     688          53 :     (void)vr_dpdk_pmd_ctx_lcore_request(lcores_string, sizeof(lcores_string),
     689             :         service_core_mask_ptr);
     690             : 
     691             :     /* Append lcores option. */
     692          53 :     if (dpdk_argv_append("--"LCORES_OPT, lcores_string) != 0)
     693           0 :         return -1;
     694          53 :     if ((vr_dpdk_log_level != NULL) && (vr_dpdk_log_level[0] != '\0')) {
     695           0 :         if (isdigit(vr_dpdk_log_level[0]) && strlen(vr_dpdk_log_level) == 1) {
     696           0 :             snprintf(log_string, sizeof(log_string), "*:%d", atoi(vr_dpdk_log_level));
     697           0 :             if (dpdk_argv_append("--"VR_DPDK_LOG_LEVEL, log_string) != 0) {
     698           0 :                 return -1;
     699             :             }
     700             :         }
     701             :         else {
     702           0 :             RTE_LOG(INFO, VROUTER, "\nAppending string : %s\n",vr_dpdk_log_level);
     703           0 :             if (dpdk_argv_append("--"VR_DPDK_LOG_LEVEL, vr_dpdk_log_level) != 0) {
     704           0 :                 return -1;
     705             :             }
     706             :         }
     707             :     }
     708             : 
     709             :     /* Append no huge option. */
     710          53 :     if (no_huge_set && dpdk_argv_append("--"NO_HUGE_OPT, NULL) != 0)
     711           0 :         return -1;
     712             : 
     713             :     /* print out configuration */
     714          53 :     RTE_LOG(INFO, VROUTER, "Log file : %s\n", dpdk_log_file);
     715          53 :     if (vr_dpdk.vlan_tag != VLAN_ID_INVALID) {
     716           0 :         RTE_LOG(INFO, VROUTER, "Using VLAN TCI: %" PRIu16 "\n", vr_dpdk.vlan_tag);
     717             :     }
     718          53 :     RTE_LOG(INFO, VROUTER, "Bridge Table limit:          %" PRIu32 "\n",
     719             :                 vr_bridge_entries);
     720          53 :     RTE_LOG(INFO, VROUTER, "Bridge Table overflow limit: %" PRIu32 "\n",
     721             :                 vr_bridge_oentries);
     722          53 :     RTE_LOG(INFO, VROUTER, "Flow Table limit:            %" PRIu32 "\n",
     723             :                 vr_flow_entries);
     724          53 :     RTE_LOG(INFO, VROUTER, "Flow Table overflow limit:   %" PRIu32 "\n",
     725             :                 vr_oflow_entries);
     726          53 :     RTE_LOG(INFO, VROUTER, "MPLS labels limit:           %" PRIu32 "\n",
     727             :                 vr_mpls_labels);
     728          53 :     RTE_LOG(INFO, VROUTER, "Nexthops limit:              %" PRIu32 "\n",
     729             :                 vr_nexthops);
     730          53 :     RTE_LOG(INFO, VROUTER, "VRF tables limit:            %" PRIu32 "\n",
     731             :                 vr_vrfs);
     732          53 :     RTE_LOG(INFO, VROUTER, "Packet pool size:            %" PRIu32 "\n",
     733             :                 rss_mempool_sz);
     734          53 :     RTE_LOG(INFO, VROUTER, "PMD Tx Descriptor size:      %" PRIu32 "\n",
     735             :                 vr_txd_sz);
     736          53 :     RTE_LOG(INFO, VROUTER, "PMD Rx Descriptor size:      %" PRIu32 "\n",
     737             :                 vr_rxd_sz);
     738          53 :     RTE_LOG(INFO, VROUTER, "Maximum packet size:         %" PRIu32 "\n",
     739             :                 vr_packet_sz);
     740          53 :     RTE_LOG(INFO, VROUTER, "Maximum log buffer size:     %" PRIu32 "\n",
     741             :                 vr_pkt_droplog_bufsz);
     742          53 :     RTE_LOG(INFO, VROUTER, "VR_DPDK_RX_RING_SZ:          %" PRIu32 "\n",
     743             :                 vr_dpdk_rx_ring_sz);
     744          53 :     RTE_LOG(INFO, VROUTER, "VR_DPDK_TX_RING_SZ:          %" PRIu32 "\n",
     745             :                 vr_dpdk_tx_ring_sz);
     746          53 :     RTE_LOG(INFO, VROUTER, "VR_DPDK_YIELD_OPTION:        %" PRIu32 "\n",
     747             :                 vr_dpdk_yield_option);
     748          53 :     RTE_LOG(INFO, VROUTER, "VR_DPDK_LOG_LEVEL:           %s\n",
     749             :                 vr_dpdk_log_level);
     750          53 :     RTE_LOG(INFO, VROUTER, "VR_SERVICE_CORE_MASK:        0x%x\n",
     751             :                 vr_service_core_mask);
     752          53 :     RTE_LOG(INFO, VROUTER, "VR_DPDK_CTRL_THREAD_MASK:    0x%x\n",
     753             :                 vr_dpdk_ctrl_thread_mask);
     754          53 :     RTE_LOG(INFO, VROUTER, "Unconditional Close Flow on TCP RST:       %" PRIu32 "\n",
     755             :                 vr_uncond_close_flow_on_tcp_rst);
     756          53 :     RTE_LOG(INFO, VROUTER, "S/W Load-balancing:          %s\n",
     757             :         vr_no_load_balance ? "Disable" : "Enable");
     758          53 :     RTE_LOG(INFO, VROUTER, "EAL arguments:\n");
     759         265 :     for (i = 1; i < RTE_DIM(dpdk_argv) - 1; i += 2) {
     760         265 :         if (dpdk_argv[i] == NULL)
     761          53 :             break;
     762         212 :         if (dpdk_argv[i + 1] == NULL) {
     763          53 :             RTE_LOG(INFO, VROUTER, " %12s\n", dpdk_argv[i]);
     764          53 :             i--;
     765             :         } else {
     766         159 :             RTE_LOG(INFO, VROUTER, " %12s  \"%s\"\n",
     767             :                 dpdk_argv[i], dpdk_argv[i + 1]);
     768             :         }
     769             :     }
     770          53 :     return i;
     771             : }
     772             : 
     773             : static void
     774          53 : version_print(void)
     775             : {
     776          53 :     RTE_LOG(INFO, VROUTER, "vRouter version: %s\n", ContrailBuildInfo);
     777          53 :     RTE_LOG(INFO, VROUTER, "DPDK version: %s\n", rte_version());
     778          53 : }
     779             : 
     780             : /*
     781             :  * dpdk_check_rx_mrgbuf_disable - check if mergeable buffers is disabled by cmdline */
     782             : int
     783         194 : dpdk_check_rx_mrgbuf_disable(void)
     784             : {
     785         194 :     return no_rx_mrgbuf;
     786             : }
     787             : 
     788             : /*
     789             :  * dpdk_check_sriov_vf - check if any of eth devices is a virtual function.
     790             :  *               - Pin the lcore for SR-IOV vf I/O for eth devices.
     791             :  */
     792             : static void
     793          53 : dpdk_check_sriov_vf(void)
     794             : {
     795             :     int i;
     796             :     struct rte_eth_dev_info dev_info;
     797             :     size_t soff;
     798             : 
     799          53 :     VR_DPDK_RTE_ETH_FOREACH_DEV(i)
     800             :     {
     801           0 :         rte_eth_dev_info_get(i, &dev_info);
     802             :         /* Check PMD name suffix to detect SR-IOV virtual function. */
     803           0 :         soff = strlen(dev_info.driver_name) - sizeof(VR_DPDK_VF_PMD_SFX) + 1;
     804           0 :         if (soff > 0 &&
     805           0 :                 strncmp(dev_info.driver_name + soff, VR_DPDK_VF_PMD_SFX,
     806             :                 sizeof(VR_DPDK_VF_PMD_SFX)) == 0) {
     807             :             /* Dedicate the first forwarding lcore to VF RX/TX. */
     808           0 :             if (dev_info.max_tx_queues < vr_dpdk.nb_fwd_lcores
     809             :                     /* We also need 2 TX queues for Netlink and Packet lcores. */
     810             :                     + VR_DPDK_FWD_LCORE_ID - VR_DPDK_PACKET_LCORE_ID) {
     811           0 :                 vr_dpdk.vf_lcore_id = VR_DPDK_FWD_LCORE_ID;
     812           0 :                 RTE_LOG(INFO, VROUTER,
     813             :                         "%s: Lcore %d: SR-IOV virtual function IO for eth device %d (%s)\n",
     814             :                         __func__, VR_DPDK_FWD_LCORE_ID, i, dev_info.driver_name);
     815           0 :                 break;
     816             :             }
     817             :         }
     818             :     }
     819          53 : }
     820             : 
     821             : 
     822             : /* Init DPDK EAL */
     823             : static int
     824          53 : dpdk_init(void)
     825             : {
     826             :     int ret, nb_sys_ports;
     827             : 
     828          53 :     version_print();
     829             : 
     830          53 :     ret = vr_dpdk_table_mem_init(VR_MEM_FLOW_TABLE_OBJECT, vr_flow_entries,
     831             :             VR_FLOW_TABLE_SIZE, vr_oflow_entries, VR_OFLOW_TABLE_SIZE);
     832          53 :     if (ret < 0) {
     833           0 :         RTE_LOG(ERR, VROUTER, "Error initializing flow table: %s (%d)\n",
     834             :             rte_strerror(-ret), -ret);
     835           0 :         return ret;
     836             :     }
     837             : 
     838          53 :     ret = vr_dpdk_table_mem_init(VR_MEM_BRIDGE_TABLE_OBJECT, vr_bridge_entries,
     839             :             VR_BRIDGE_TABLE_SIZE, vr_bridge_oentries,
     840             :             VR_BRIDGE_OFLOW_TABLE_SIZE);
     841          53 :     if (ret < 0) {
     842           0 :         RTE_LOG(ERR, VROUTER, "Error initializing bridge table: %s (%d)\n",
     843             :             rte_strerror(-ret), -ret);
     844           0 :         return ret;
     845             :     }
     846             :     //converting it into dpdk understandable arguments
     847          53 :     ret = dpdk_argv_update();
     848          53 :     if (ret == -1) {
     849           0 :         RTE_LOG(ERR, VROUTER, "Error updating EAL arguments\n");
     850           0 :         return -1;
     851             :     }
     852             : 
     853          53 :     ret = vr_dpdk_pmd_ctx_init(ret, dpdk_argv);
     854          53 :     if (ret < 0) {
     855           0 :         RTE_LOG(ERR, VROUTER, "Error initializing EAL\n");
     856           0 :         return ret;
     857             :     }
     858             :     /* EAL resets the log stream */
     859          53 :     rte_openlog_stream(timestamp_log_stream);
     860             : 
     861             :     /* disable unwanted logtypes for debug purposes */
     862          53 :     rte_log_set_level(VR_DPDK_LOGTYPE_DISABLE, 0);
     863             : 
     864             :     /* set default log level to INFO */
     865          53 :     rte_log_set_global_level(RTE_LOG_INFO);
     866             : 
     867          53 :     ret = dpdk_mempools_create();
     868          53 :     if (ret < 0)
     869           0 :         return ret;
     870             : 
     871             :     /* get number of available ports found in scan */
     872          53 :     nb_sys_ports = rte_eth_dev_count_avail();
     873          53 :     RTE_LOG(INFO, VROUTER, "Found %d eth device(s)\n", nb_sys_ports);
     874             : 
     875             :     /* get number of cores */
     876          53 :     RTE_LOG(INFO, VROUTER, "Using %d forwarding lcore(s)\n",
     877             :                             vr_dpdk.nb_fwd_lcores);
     878          53 :     RTE_LOG(INFO, VROUTER, "Using %d IO lcore(s)\n",
     879             :                             vr_dpdk.nb_io_lcores);
     880          53 :     RTE_LOG(INFO, VROUTER, "Using %d service lcores\n",
     881             :                             rte_lcore_count() - vr_dpdk.nb_fwd_lcores
     882             :                             - vr_dpdk.nb_io_lcores);
     883             : 
     884             :     /* init timer subsystem */
     885          53 :     rte_timer_subsystem_init();
     886             : 
     887             :     /* Check if any of eth devices is a SR-IOV virtual function. */
     888          53 :     dpdk_check_sriov_vf();
     889             : 
     890             :     /* Init the interface configuration mutex
     891             :      * ATM we use it just to synchronize access between the NetLink interface
     892             :      * and kernel KNI events. The datapath is not affected. */
     893          53 :     return pthread_mutex_init(&vr_dpdk.if_lock, NULL);
     894             : }
     895             : 
     896             : /* Shutdown DPDK EAL */
     897             : static void
     898          53 : dpdk_exit(void)
     899             : {
     900             :     int i;
     901             : 
     902          53 :     vr_dpdk_if_lock();
     903          53 :     RTE_LOG(INFO, VROUTER, "Releasing KNI devices...\n");
     904         901 :     for (i = 0; i < VR_DPDK_MAX_KNI_INTERFACES; i++) {
     905         848 :         if (vr_dpdk.knis[i] != NULL) {
     906           0 :             rte_kni_release(vr_dpdk.knis[i]);
     907           0 :             vr_dpdk.knis[i] = NULL;
     908             :         }
     909             :     }
     910             : 
     911          53 :     RTE_LOG(INFO, VROUTER, "Releasing TAP devices...\n");
     912         901 :     for (i = 0; i < VR_DPDK_MAX_TAP_INTERFACES; i++) {
     913         848 :         if (vr_dpdk.tapdevs[i].tapdev_fd > 0) {
     914           0 :             close(vr_dpdk.tapdevs[i].tapdev_fd);
     915           0 :             vr_dpdk.tapdevs[i].tapdev_fd = -1;
     916             :         }
     917             :     }
     918             : 
     919          53 :     RTE_LOG(INFO, VROUTER, "Closing eth devices...\n");
     920        1749 :     for (i = 0; i < RTE_MAX_ETHPORTS; i++) {
     921        1696 :         if (vr_dpdk.ethdevs[i].ethdev_ptr != NULL) {
     922           0 :             rte_eth_dev_stop(i);
     923           0 :             rte_eth_dev_close(i);
     924           0 :             vr_dpdk.ethdevs[i].ethdev_ptr = NULL;
     925             :         }
     926             :     }
     927          53 :     vr_dpdk_if_unlock();
     928             : 
     929             :     /* destroy interface lock */
     930          53 :     if (pthread_mutex_destroy(&vr_dpdk.if_lock)) {
     931           0 :         RTE_LOG(ERR, VROUTER, "Error destroying interface lock\n");
     932             :     }
     933             : 
     934          53 :     (void)vr_dpdk_pmd_ctx_exit();
     935          53 : }
     936             : 
     937             : /* Set stop flag for all lcores */
     938             : static void
     939         106 : dpdk_stop_flag_set(void)
     940             : {
     941             :     /* check if the flag is already set */
     942         106 :     if (unlikely(vr_dpdk_is_stop_flag_set()))
     943          53 :         return;
     944             : 
     945          53 :     rte_atomic16_inc(&vr_dpdk.stop_flag);
     946          53 :     vr_dpdk_lcore_cmd_post_all(VR_DPDK_LCORE_STOP_CMD, 0);
     947             : 
     948             :     /* wakeup UVHost server to shutdown */
     949          53 :     vr_uvhost_wakeup();
     950             : }
     951             : 
     952             : /* Check if the stop flag is set */
     953             : int
     954    12541077 : vr_dpdk_is_stop_flag_set(void)
     955             : {
     956    12541077 :     if (unlikely(rte_atomic16_read(&vr_dpdk.stop_flag)))
     957         374 :         return 1;
     958             : 
     959    12540682 :     return 0;
     960             : }
     961             : 
     962             : /* Custom handling of signals */
     963             : static void
     964          53 : dpdk_signal_handler_stop(int signum)
     965             : {
     966          53 :     RTE_LOG(INFO, VROUTER, "Got signal %d on lcore %u, stopping...\n",
     967             :             signum, rte_lcore_id());
     968             : 
     969          53 :     dpdk_stop_flag_set();
     970          53 : }
     971             : static void
     972           0 : dpdk_signal_handler_ignore(int signum)
     973             : {
     974           0 :     RTE_LOG(INFO, VROUTER, "Got signal %d on lcore %u, ignoring...\n",
     975             :             signum, rte_lcore_id());
     976           0 : }
     977             : 
     978             : /* Setup signal handlers */
     979             : static int
     980          53 : dpdk_signals_init(void)
     981             : {
     982             :     struct sigaction act;
     983             :     sigset_t set;
     984             : 
     985          53 :     memset(&act, 0 , sizeof(act));
     986          53 :     act.sa_handler = dpdk_signal_handler_stop;
     987          53 :     if (sigaction(SIGTERM, &act, NULL) != 0) {
     988           0 :         RTE_LOG(CRIT, VROUTER, "Error registering SIGTERM handler\n");
     989           0 :         return -1;
     990             :     }
     991          53 :     if (sigaction(SIGINT, &act, NULL) != 0) {
     992           0 :         RTE_LOG(CRIT, VROUTER, "Error registering SIGINT handler\n");
     993           0 :         return -1;
     994             :     }
     995             : 
     996          53 :     act.sa_handler = dpdk_signal_handler_ignore;
     997          53 :     if (sigaction(SIGPIPE, &act, NULL) != 0) {
     998           0 :         RTE_LOG(CRIT, VROUTER, "Error registering SIGPIPE handler\n");
     999           0 :         return -1;
    1000             :     }
    1001             : 
    1002             :     /* Block (ignore) all the signals for this and all the child threads.
    1003             :      * The signals will be unblocked for the master lcore later during
    1004             :      * the lcore intialization.
    1005             :      */
    1006          53 :     sigfillset(&set);
    1007          53 :     if (pthread_sigmask(SIG_BLOCK, &set, NULL) != 0) {
    1008           0 :         RTE_LOG(CRIT, VROUTER, "Error setting signal mask\n");
    1009           0 :         return -1;
    1010             :     }
    1011             : 
    1012          53 :     return 0;
    1013             : }
    1014             : 
    1015             : /*
    1016             :  * vr_dpdk_exit_trigger - function that is called by user space vhost server
    1017             :  * to cause all DPDK threads to exit.
    1018             :  *
    1019             :  * Returns nothing.
    1020             :  */
    1021             : void
    1022          53 : vr_dpdk_exit_trigger(void)
    1023             : {
    1024          53 :     dpdk_stop_flag_set();
    1025             : 
    1026          53 :     return;
    1027             : }
    1028             : 
    1029             : static struct option long_options[] = {
    1030             :     [NO_DAEMON_OPT_INDEX]           =   {NO_DAEMON_OPT,         no_argument,
    1031             :                                                     &no_daemon_set,         1},
    1032             :     [NO_HUGE_OPT_INDEX]             =   {NO_HUGE_OPT,           no_argument,
    1033             :                                                     &no_huge_set,           1},
    1034             :     [HELP_OPT_INDEX]                =   {HELP_OPT,              no_argument,
    1035             :                                                     NULL,                   0},
    1036             :     [VERSION_OPT_INDEX]             =   {VERSION_OPT,           no_argument,
    1037             :                                                     NULL,                   0},
    1038             :     [MEMPOOL_SIZE_OPT_INDEX]        =   {MEMPOOL_SIZE_OPT,      required_argument,
    1039             :                                                     NULL,                   0},
    1040             :     [DPDK_TXD_SIZE_OPT_INDEX]        =  {DPDK_TXD_SIZE_OPT,     required_argument,
    1041             :                                                     NULL,                   0},
    1042             :     [DPDK_RXD_SIZE_OPT_INDEX]        =  {DPDK_RXD_SIZE_OPT,     required_argument,
    1043             :                                                     NULL,                   0},
    1044             :     [PACKET_SIZE_OPT_INDEX]         =   {PACKET_SIZE_OPT,       required_argument,
    1045             :                                                     NULL,                   0},
    1046             :     [VLAN_TCI_OPT_INDEX]            =   {VLAN_TCI_OPT,          required_argument,
    1047             :                                                     NULL,                   0},
    1048             :     [VLAN_NAME_OPT_INDEX]           =   {VLAN_NAME_OPT,         required_argument,
    1049             :                                                     NULL,                   0},
    1050             :     [LOG_FILE_OPT_INDEX]            =   {LOG_FILE_OPT,          required_argument,
    1051             :                                                     NULL,                   0},
    1052             :     [VTEST_VLAN_OPT_INDEX]          =   {VTEST_VLAN_OPT,        no_argument,
    1053             :                                                     NULL,                   0},
    1054             :     [VDEV_OPT_INDEX]                =   {VDEV_OPT,              required_argument,
    1055             :                                                     NULL,                   0},
    1056             :     [NO_GRO_OPT_INDEX]              =   {NO_GRO_OPT,            no_argument,
    1057             :                                                     &no_gro_set,            1},
    1058             :     [NO_GSO_OPT_INDEX]              =   {NO_GSO_OPT,            no_argument,
    1059             :                                                     &no_gso_set,            1},
    1060             :     [NO_RX_MRG_BUF_INDEX]           =   {NO_RX_MRG_BUF_OPT,     no_argument,
    1061             :                                                     &no_rx_mrgbuf,          1},
    1062             :     [BRIDGE_ENTRIES_OPT_INDEX]      =   {BRIDGE_ENTRIES_OPT,    required_argument,
    1063             :                                                     NULL,                   0},
    1064             :     [BRIDGE_OENTRIES_OPT_INDEX]     =   {BRIDGE_OENTRIES_OPT,   required_argument,
    1065             :                                                     NULL,                   0},
    1066             :     [FLOW_ENTRIES_OPT_INDEX]        =   {FLOW_ENTRIES_OPT,      required_argument,
    1067             :                                                     NULL,                   0},
    1068             :     [OFLOW_ENTRIES_OPT_INDEX]       =   {OFLOW_ENTRIES_OPT,     required_argument,
    1069             :                                                     NULL,                   0},
    1070             :     [MPLS_LABELS_OPT_INDEX]         =   {MPLS_LABELS_OPT,       required_argument,
    1071             :                                                     NULL,                   0},
    1072             :     [NEXTHOPS_OPT_INDEX]            =   {NEXTHOPS_OPT,          required_argument,
    1073             :                                                     NULL,                   0},
    1074             :     [VRFS_OPT_INDEX]                =   {VRFS_OPT,              required_argument,
    1075             :                                                     NULL,                   0},
    1076             :     [SOCKET_DIR_OPT_INDEX]          =   {SOCKET_DIR_OPT,        required_argument,
    1077             :                                                     NULL,                   0},
    1078             :     [NETLINK_PORT_OPT_INDEX]        =   {NETLINK_PORT_OPT,      required_argument,
    1079             :                                                     NULL,                   0},
    1080             :     [SOCKET_MEM_OPT_INDEX]          =   {SOCKET_MEM_OPT,        required_argument,
    1081             :                                                     NULL,                   0},
    1082             :     [OFFLOADS_OPT_INDEX]            =   {OFFLOADS_OPT,          no_argument,
    1083             :                                                     NULL,                   0},
    1084             :     [PKT_DROP_LOG_BUFFER_SIZE_OPT_INDEX] =   {PKT_DROP_LOG_BUFFER_SIZE_OPT, required_argument,
    1085             :                                                     NULL,                   0},
    1086             :     [MEMORY_ALLOC_CHECKS_OPT_INDEX] =   {MEMORY_ALLOC_CHECKS_OPT, no_argument,
    1087             :                                                     NULL,                   0},
    1088             :     [VR_DPDK_RX_RING_SZ_OPT_INDEX]  =   {VR_DPDK_RX_RING_SZ_OPT, required_argument,
    1089             :                                                     NULL,                   0},
    1090             :     [VR_DPDK_TX_RING_SZ_OPT_INDEX]  =   {VR_DPDK_TX_RING_SZ_OPT, required_argument,
    1091             :                                                     NULL,                   0},
    1092             :     [VR_DPDK_YIELD_OPT_INDEX]       =   {VR_DPDK_YIELD_OPT, required_argument,
    1093             :                                                     NULL,                   0},
    1094             :     [VR_DPDK_LOG_OPT_INDEX]       =   {VR_DPDK_LOG_LEVEL, required_argument,
    1095             :                                                     NULL,                   0},
    1096             :     [VR_SERVICE_CORE_MASK_OPT_INDEX]=   {VR_SERVICE_CORE_MASK_OPT, required_argument,
    1097             :                                                     NULL,                   0},
    1098             :     [VR_DPDK_CTRL_THREAD_MASK_OPT_INDEX] = {VR_DPDK_CTRL_THREAD_MASK_OPT, required_argument,
    1099             :                                                     NULL,                   0},
    1100             :     [VR_NO_LOAD_BALANCE_OPT_INDEX] = {VR_NO_LOAD_BALANCE_OPT, no_argument,
    1101             :                                                     NULL,                   0},
    1102             :     [VR_DPDK_DDP_OPT_INDEX]     = {VR_DPDK_DDP_OPT, no_argument,
    1103             :                                                     NULL,                   0},
    1104             :     [VR_UNCOND_CLOSE_FLOW_ON_TCP_RST_OPT_INDEX] = {VR_UNCOND_CLOSE_FLOW_ON_TCP_RST_OPT,
    1105             :                                                     required_argument,
    1106             :                                                     NULL,                   0},
    1107             :     [MAX_OPT_INDEX]                 =   {NULL,                  0,
    1108             :                                                     NULL,                   0},
    1109             : };
    1110             : 
    1111             : static void
    1112           0 : Usage(void)
    1113             : {
    1114           0 :     printf(
    1115             :         "Usage: contrail-vrouter-dpdk [options]\n"
    1116             :         "    --"NO_DAEMON_OPT"  Do not demonize the vRouter\n"
    1117             :         "    --"NO_HUGE_OPT"    Use malloc instead of hugetlbfs\n"
    1118             :         "    --"HELP_OPT"       This help\n"
    1119             :         "    --"VERSION_OPT"    Display build information\n"
    1120             :         "    --"LOG_FILE_OPT" <path> Override default log file location to <path>\n"
    1121             :         "\n"
    1122             :         "    --"VDEV_OPT" CONF          Add a virtual device.\n"
    1123             :         "                         The argument format is <driver><id>[,key=val,...]\n"
    1124             :         "                         (ex: --"VDEV_OPT" eth_bond0,mode=4,slave=0000:04:00.0)\n"
    1125             :         "    --"SOCKET_MEM_OPT" MB,...  Memory to allocate on sockets.\n"
    1126             :         "                         (ex: --"SOCKET_MEM_OPT" 256,256)\n"
    1127             :         "    --"OFFLOADS_OPT" Use smart nic HW offloads.\n"
    1128             :         "\n"
    1129             :         "    --"VLAN_TCI_OPT" TCI             VLAN tag control information to use\n"
    1130             :         "                               It may be a value between 0 and 4095\n"
    1131             :         "    --"VLAN_NAME_OPT" NAME  VLAN forwarding interface name\n"
    1132             :         "\n"
    1133             :         "    --"BRIDGE_ENTRIES_OPT" NUM   Bridge table limit\n"
    1134             :         "    --"BRIDGE_OENTRIES_OPT" NUM  Bridge table overflow limit\n"
    1135             :         "    --"FLOW_ENTRIES_OPT" NUM     Flow table limit\n"
    1136             :         "    --"OFLOW_ENTRIES_OPT" NUM    Flow overflow table limit\n"
    1137             :         "    --"MPLS_LABELS_OPT" NUM      MPLS table limit\n"
    1138             :         "    --"NEXTHOPS_OPT" NUM         Nexthop table limit\n"
    1139             :         "    --"VRFS_OPT" NUM             VRF tables limit\n"
    1140             :         "    --"MEMORY_ALLOC_CHECKS_OPT"  Enable memory checks\n"
    1141             :         "    --"MEMPOOL_SIZE_OPT" NUM     Main packet pool size\n"
    1142             :         "    --"DPDK_TXD_SIZE_OPT" NUM    DPDK PMD Tx Descriptor size\n"
    1143             :         "    --"DPDK_RXD_SIZE_OPT" NUM    DPDK PMD Rx Descriptor size\n"
    1144             :         "    --"PACKET_SIZE_OPT" NUM      Maximum packet size\n"
    1145             :         "    --"PKT_DROP_LOG_BUFFER_SIZE_OPT" NUM Maximum debug log buffer size\n"
    1146             :         "    --"VR_DPDK_RX_RING_SZ_OPT" NUM Configure vr_dpdk_rx_ring_sz value\n"
    1147             :         "    --"VR_DPDK_TX_RING_SZ_OPT" NUM Configure vr_dpd_tx_ring_sz value\n"
    1148             :         "    --"VR_DPDK_YIELD_OPT" NUM      Configurable parameter to disable yield\n"
    1149             :         "    --"VR_DPDK_LOG_LEVEL" NUM  Set log level\n"
    1150             :         "    --"VR_NO_LOAD_BALANCE_OPT"    Disable s/w load-balancing\n"
    1151             :         "    --"VR_DPDK_DDP_OPT"        Enable DDP feature\n"
    1152             :         "    --"VR_SERVICE_CORE_MASK_OPT" NUM LIST OR HEXADECIMAL BITMASK "
    1153             :                                          "Configurable parameter for service "
    1154             :                                          "core mask\n"
    1155             :         "    --"VR_DPDK_CTRL_THREAD_MASK_OPT" NUM LIST OR HEXADECIMAL BITMASK "
    1156             :                                              "Configurable parameter for dpdk "
    1157             :                                              "control threads\n"
    1158             :         "    --"VR_UNCOND_CLOSE_FLOW_ON_TCP_RST_OPT" NUM Enable/Disable unconditional closure of Flow "
    1159             :                                            "on TCP RST\n"
    1160             :         );
    1161             : 
    1162           0 :     (void)vr_dpdk_pmd_ctx_print_usage();
    1163             : 
    1164           0 :     exit(1);
    1165             : }
    1166             : 
    1167             : static void
    1168         230 : parse_long_opts(int opt_flow_index, char *optarg)
    1169             : {
    1170         230 :     errno = 0;
    1171             : 
    1172         230 :     switch (opt_flow_index) {
    1173         106 :     case NO_DAEMON_OPT_INDEX:
    1174             :     case NO_HUGE_OPT_INDEX:
    1175             :     case NO_GRO_OPT_INDEX:
    1176             :     case NO_GSO_OPT_INDEX:
    1177             :     case NO_RX_MRG_BUF_INDEX:
    1178         106 :         break;
    1179             : 
    1180           0 :     case VERSION_OPT_INDEX:
    1181           0 :         version_print();
    1182           0 :         exit(0);
    1183             :         break;
    1184             : 
    1185           0 :     case MEMPOOL_SIZE_OPT_INDEX:
    1186           0 :         vr_mempool_sz = (unsigned int)strtoul(optarg, NULL, 0);
    1187           0 :         if (errno != 0) {
    1188           0 :             vr_mempool_sz = VR_DEF_MEMPOOL_SZ;
    1189             :         }
    1190           0 :         break;
    1191             : 
    1192           0 :     case DPDK_RXD_SIZE_OPT_INDEX:
    1193           0 :         vr_rxd_sz = (unsigned int)strtoul(optarg, NULL, 0);
    1194           0 :         if (errno != 0) {
    1195           0 :             vr_rxd_sz = VR_DPDK_NB_RXD;
    1196             :         }
    1197           0 :         break;
    1198             : 
    1199           0 :     case DPDK_TXD_SIZE_OPT_INDEX:
    1200           0 :         vr_txd_sz = (unsigned int)strtoul(optarg, NULL, 0);
    1201           0 :         if (errno != 0) {
    1202           0 :             vr_txd_sz = VR_DPDK_NB_TXD;
    1203             :         }
    1204           0 :         break;
    1205             : 
    1206          53 :     case PACKET_SIZE_OPT_INDEX:
    1207          53 :         vr_packet_sz = (unsigned int)strtoul(optarg, NULL, 0);
    1208          53 :         if (errno != 0) {
    1209           0 :             vr_packet_sz = VR_DEF_MAX_PACKET_SZ;
    1210             :         }
    1211          53 :         break;
    1212             : 
    1213             :     /*
    1214             :      * If VLAN tag is set, vRouter will expect tagged packets. The tag
    1215             :      * will be stripped by NIC or in vr_dpdk_ethdev_rx_emulate() and
    1216             :      * injected in dpdk_if_tx().
    1217             :      *
    1218             :      * Received packets with unmatching tag will be forwarded to the VLAN
    1219             :      * forwarding interface, that is created in main(). Packets sent on that
    1220             :      * interface will be immediately forwarded to the physical interface.
    1221             :      *
    1222             :      * See following funtions: dpdk_lcore_fwd_io(), vr_dpdk_ethdev_rx_emulate(),
    1223             :      * vr_dpdk_lcore_vroute(), dpdk_vlan_forwarding_if_add().
    1224             :      */
    1225           0 :     case VLAN_TCI_OPT_INDEX:
    1226           0 :         vr_dpdk.vlan_tag = (uint16_t)strtoul(optarg, NULL, 0);
    1227           0 :         if (errno != 0) {
    1228           0 :             vr_dpdk.vlan_tag = VLAN_ID_INVALID;
    1229             :         }
    1230           0 :         if (vr_dpdk.vlan_tag > 4095)
    1231           0 :             Usage();
    1232           0 :         break;
    1233             : 
    1234           0 :     case VTEST_VLAN_OPT_INDEX:
    1235           0 :         vr_dpdk.vtest_vlan = 1;
    1236           0 :         break;
    1237             :     /*
    1238             :      * VLAN packets with unmatching tag will be forwarded to the kernel using
    1239             :      * an interface with name defined here.
    1240             :      */
    1241           0 :     case VLAN_NAME_OPT_INDEX:
    1242           0 :         strncpy(vr_dpdk.vlan_name, optarg, sizeof(vr_dpdk.vlan_name) - 1);
    1243           0 :         break;
    1244             : 
    1245             : 
    1246           0 :     case VDEV_OPT_INDEX:
    1247           0 :         dpdk_argv_append("--"VDEV_OPT, optarg);
    1248           0 :         break;
    1249             : 
    1250           0 :     case BRIDGE_ENTRIES_OPT_INDEX:
    1251           0 :         vr_bridge_entries = (unsigned int)strtoul(optarg, NULL, 0);
    1252           0 :         if (errno != 0) {
    1253           0 :             vr_bridge_entries = VR_DEF_BRIDGE_ENTRIES;
    1254             :         }
    1255           0 :         break;
    1256             : 
    1257           0 :     case BRIDGE_OENTRIES_OPT_INDEX:
    1258           0 :         vr_bridge_oentries = (unsigned int)strtoul(optarg, NULL, 0);
    1259           0 :         if (errno != 0) {
    1260           0 :             vr_bridge_oentries = ((vr_bridge_entries / 5) + 1023) & ~1023;
    1261             :         }
    1262           0 :         break;
    1263             : 
    1264           0 :     case FLOW_ENTRIES_OPT_INDEX:
    1265           0 :         vr_flow_entries = (unsigned int)strtoul(optarg, NULL, 0);
    1266           0 :         if (errno != 0) {
    1267           0 :             vr_flow_entries = VR_DEF_FLOW_ENTRIES;
    1268             :         }
    1269           0 :         break;
    1270             : 
    1271           0 :     case OFLOW_ENTRIES_OPT_INDEX:
    1272           0 :         vr_oflow_entries = (unsigned int)strtoul(optarg, NULL, 0);
    1273           0 :         if (errno != 0) {
    1274             :             /* vr_flow_entries would be either VR_DEF_FLOW_ENTRIES or
    1275             :              * user value
    1276             :              */
    1277           0 :             vr_oflow_entries = ((vr_flow_entries / 5) + 1023) & ~1023;
    1278             :         }
    1279           0 :         break;
    1280             : 
    1281           0 :     case MEMORY_ALLOC_CHECKS_OPT_INDEX:
    1282           0 :         vr_memory_alloc_checks = 1;
    1283           0 :         break;
    1284             : 
    1285           0 :     case MPLS_LABELS_OPT_INDEX:
    1286           0 :         vr_mpls_labels = (unsigned int)strtoul(optarg, NULL, 0);
    1287           0 :         if (errno != 0) {
    1288           0 :             vr_mpls_labels = VR_DEF_LABELS;
    1289             :         }
    1290           0 :         break;
    1291             : 
    1292           0 :     case NEXTHOPS_OPT_INDEX:
    1293           0 :         vr_nexthops = (unsigned int)strtoul(optarg, NULL, 0);
    1294           0 :         if (errno != 0) {
    1295           0 :             vr_nexthops = VR_DEF_NEXTHOPS;
    1296             :         }
    1297           0 :         break;
    1298             : 
    1299           0 :     case VRFS_OPT_INDEX:
    1300           0 :         vr_vrfs = (unsigned int)strtoul(optarg, NULL, 0);
    1301           0 :         if (errno != 0) {
    1302           0 :             vr_vrfs = VR_DEF_VRFS;
    1303             :         }
    1304           0 :         break;
    1305           0 :     case PKT_DROP_LOG_BUFFER_SIZE_OPT_INDEX:
    1306           0 :         vr_pkt_droplog_bufsz = (unsigned int)strtoul(optarg, NULL, 0);
    1307           0 :         if (errno != 0) {
    1308           0 :             vr_pkt_droplog_bufsz = VR_PKT_DROP_LOG_MAX;
    1309             :         }
    1310           0 :         break;
    1311             : 
    1312           0 :     case VR_DPDK_RX_RING_SZ_OPT_INDEX:
    1313           0 :         vr_dpdk_rx_ring_sz = (unsigned int) strtoul(optarg, NULL, 0);
    1314           0 :         if (errno != 0) {
    1315           0 :             vr_dpdk_rx_ring_sz = VR_DPDK_RX_RING_SZ;
    1316             :         }
    1317           0 :         break;
    1318             : 
    1319           0 :     case VR_DPDK_TX_RING_SZ_OPT_INDEX:
    1320           0 :         vr_dpdk_tx_ring_sz = (unsigned int) strtoul(optarg, NULL, 0);
    1321           0 :         if (errno != 0) {
    1322           0 :             vr_dpdk_tx_ring_sz = VR_DPDK_TX_RING_SZ;
    1323             :         }
    1324           0 :         break;
    1325             : 
    1326           0 :     case VR_DPDK_YIELD_OPT_INDEX:
    1327           0 :         vr_dpdk_yield_option = (unsigned int) strtoul(optarg, NULL, 0);
    1328           0 :         if (errno != 0) {
    1329           0 :             vr_dpdk_yield_option = 1;
    1330             :         }
    1331           0 :         break;
    1332             : 
    1333           0 :     case VR_DPDK_LOG_OPT_INDEX:
    1334           0 :         vr_dpdk_log_level = optarg;
    1335           0 :         if (errno != 0) {
    1336           0 :             vr_dpdk_log_level = NULL;
    1337             :         }
    1338           0 :         break;
    1339             : 
    1340           0 :     case VR_SERVICE_CORE_MASK_OPT_INDEX:
    1341           0 :         if (validate_mask_str(optarg)) {
    1342           0 :             service_core_mask_ptr = optarg;
    1343             :         } else {
    1344           0 :             vr_service_core_mask = (unsigned int) strtoul(optarg, NULL, 0);
    1345           0 :             if (errno != 0) {
    1346           0 :                 vr_service_core_mask = 0;
    1347             :             }
    1348             :         }
    1349           0 :         break;
    1350             : 
    1351           0 :     case VR_DPDK_CTRL_THREAD_MASK_OPT_INDEX:
    1352           0 :         if (validate_mask_str(optarg)) {
    1353           0 :             dpdk_ctrl_thread_mask_ptr = optarg;
    1354             :         } else {
    1355           0 :             vr_dpdk_ctrl_thread_mask = (unsigned int) strtoul(optarg, NULL, 0);
    1356           0 :             if (errno != 0) {
    1357           0 :                 vr_dpdk_ctrl_thread_mask = 0;
    1358             :             }
    1359             :         }
    1360           0 :         break;
    1361             : 
    1362          18 :     case VR_UNCOND_CLOSE_FLOW_ON_TCP_RST_OPT_INDEX:
    1363          18 :         vr_uncond_close_flow_on_tcp_rst = (unsigned int) strtoul(optarg, NULL, 0);
    1364          18 :         if (errno != 0) {
    1365           0 :             vr_uncond_close_flow_on_tcp_rst = 0;
    1366             :         }
    1367          18 :         break;
    1368             : 
    1369           0 :     case VR_NO_LOAD_BALANCE_OPT_INDEX:
    1370           0 :         vr_no_load_balance = true;
    1371           0 :         break;
    1372             : 
    1373           0 :     case VR_DPDK_DDP_OPT_INDEX:
    1374           0 :         vr_dpdk_set_ddp();
    1375           0 :         break;
    1376             : 
    1377          53 :     case SOCKET_DIR_OPT_INDEX:
    1378          53 :         vr_socket_dir = optarg;
    1379          53 :         break;
    1380             : 
    1381           0 :     case NETLINK_PORT_OPT_INDEX:
    1382           0 :         vr_netlink_port = (unsigned int)strtoul(optarg, NULL, 0);
    1383           0 :         if (errno != 0) {
    1384           0 :             vr_netlink_port = VR_DEF_NETLINK_PORT;
    1385             :         }
    1386           0 :         break;
    1387             : 
    1388           0 :     case SOCKET_MEM_OPT_INDEX:
    1389             :         /* Remove -m option if present. */
    1390           0 :         dpdk_argv_remove("-m");
    1391           0 :         dpdk_argv_append("--"SOCKET_MEM_OPT, optarg);
    1392           0 :         break;
    1393             : 
    1394           0 :     case LOG_FILE_OPT_INDEX:
    1395           0 :         strncpy(dpdk_log_file, optarg, sizeof(dpdk_log_file) - 1);
    1396           0 :         dpdk_log_file[sizeof(dpdk_log_file) - 1] = '\0';
    1397           0 :         break;
    1398             : 
    1399           0 :     case OFFLOADS_OPT_INDEX:
    1400           0 :         printf("Use datapath offloads\n");
    1401           0 :         datapath_offloads = 1;
    1402           0 :         break;
    1403             : 
    1404           0 :     case HELP_OPT_INDEX:
    1405             :     default:
    1406           0 :         Usage();
    1407             :     }
    1408         230 : }
    1409             : 
    1410             : static ssize_t
    1411       15672 : timestamp_log_write(void *c, const char *buf, size_t size)
    1412             : {
    1413             :     ssize_t ret;
    1414             :     struct timeval tv;
    1415             :     struct tm *tm;
    1416             :     char outbuf[VR_DPDK_STR_BUF_SZ];
    1417       15672 :     size_t len = 0;
    1418             : 
    1419       15672 :     gettimeofday(&tv, NULL);
    1420       15672 :     if ((tm = localtime(&tv.tv_sec)) != NULL) {
    1421       15672 :         len += strftime(outbuf, sizeof(outbuf) - len, VR_DPDK_TIMESTAMP, tm);
    1422       15672 :         len += snprintf(outbuf + len, sizeof(outbuf) - len, ",%03lu ", tv.tv_usec/1000);
    1423             :     }
    1424             : 
    1425       15672 :     strncpy(outbuf + len, buf, sizeof(outbuf) - len);
    1426       15672 :     if (sizeof(outbuf) - len > size)
    1427       15672 :         len += size;
    1428             :     else
    1429           0 :         len = sizeof(outbuf);
    1430             : 
    1431       15672 :     ret = fwrite(outbuf, len, 1, stdout);
    1432       15672 :     if (c != NULL) {
    1433           0 :         ret = fwrite(outbuf, len, 1, (FILE*)c);
    1434           0 :         fflush((FILE*)c);
    1435             :     }
    1436       15672 :     fflush(stdout);
    1437             : 
    1438       15672 :     if (ret == 0)
    1439           0 :         return -1;
    1440             : 
    1441       15672 :     return ret;
    1442             : }
    1443             : static cookie_io_functions_t timestamp_log_func = {
    1444             :     .write = timestamp_log_write,
    1445             : };
    1446             : 
    1447             : /* API to check CLIs with no_argument flag.
    1448             :  * Currently CLI with no_argument flag accepts argument,
    1449             :  * so if user passes an argument it will dispaly an error message
    1450             :  */
    1451             : static bool
    1452         230 : parse_no_arg_cli(int opt_flow_index, int optind, char *argv[])
    1453             : {
    1454         230 :     if (opt_flow_index == NO_DAEMON_OPT_INDEX ||
    1455         124 :         opt_flow_index == NO_HUGE_OPT_INDEX ||
    1456         124 :         opt_flow_index == NO_GRO_OPT_INDEX ||
    1457         124 :         opt_flow_index == NO_GSO_OPT_INDEX ||
    1458         124 :         opt_flow_index == NO_RX_MRG_BUF_INDEX ||
    1459         124 :         opt_flow_index == HELP_OPT_INDEX ||
    1460         124 :         opt_flow_index == OFFLOADS_OPT_INDEX ||
    1461         124 :         opt_flow_index == MEMORY_ALLOC_CHECKS_OPT_INDEX ||
    1462         124 :         opt_flow_index == VERSION_OPT_INDEX ||
    1463         124 :         opt_flow_index == VTEST_VLAN_OPT_INDEX ||
    1464         124 :         opt_flow_index == VR_DPDK_LOG_OPT_INDEX ||
    1465         124 :         opt_flow_index == VR_DPDK_DDP_OPT_INDEX ||
    1466             :         opt_flow_index == VR_NO_LOAD_BALANCE_OPT_INDEX) {
    1467         106 :             if(argv[optind] && argv[optind][0] != '-') {
    1468           0 :                 printf("No arguments required \n");
    1469           0 :                 Usage();
    1470           0 :                 return false;
    1471             :             }
    1472             :         }
    1473         230 :     return true;
    1474             : }
    1475             : 
    1476             : int
    1477          53 : main(int argc, char *argv[])
    1478             : {
    1479             :     /* Coredump filter command size to use */
    1480             :     #define COREDUMP_CMD_SIZE   50
    1481             : 
    1482             :     int ret, opt, option_index;
    1483             :     unsigned int lcore_id;
    1484             :     pid_t dpdk_pid;
    1485             :     char coredump_filter_cmd[COREDUMP_CMD_SIZE];
    1486             : 
    1487          53 :     vr_dpdk.vlan_tag = VLAN_ID_INVALID;
    1488          53 :     strncpy(vr_dpdk.vlan_name, VR_DPDK_VLAN_FWD_DEF_NAME,
    1489             :         sizeof(vr_dpdk.vlan_name) - 1);
    1490             : 
    1491          53 :     rte_openlog_stream(stdout);
    1492             : 
    1493             :     /*
    1494             :      * Set the core dump filter to include shared hugepages so that all the
    1495             :      * vrouter related data structures are available in the core file.
    1496             :      */
    1497          53 :     dpdk_pid = getpid();
    1498          53 :     snprintf(coredump_filter_cmd, COREDUMP_CMD_SIZE, "echo 0x7f > /proc/%d/coredump_filter", dpdk_pid);
    1499          53 :     ret = system(coredump_filter_cmd);
    1500          53 :     if(ret != 0) {
    1501           0 :         RTE_LOG(ERR, VROUTER, "Failed to set coredump filter %d\n", ret);
    1502             :     }
    1503             : 
    1504         283 :     while ((opt = getopt_long(argc, argv, "", long_options, &option_index))
    1505         283 :             >= 0) {
    1506         230 :         ret = vr_dpdk_pmd_ctx_parse_opt(argc, argv, optind, opt, optarg);
    1507         230 :         bool opt_parsed_by_pmd_ctx = ret == 0;
    1508             : 
    1509         230 :         switch (opt) {
    1510         230 :         case 0:
    1511         230 :             if (parse_no_arg_cli(option_index, optind, argv)) {
    1512         230 :                 parse_long_opts(option_index, optarg);
    1513             :             }
    1514         230 :             break;
    1515             : 
    1516           0 :         case '?':
    1517             :         default:
    1518           0 :             if (opt_parsed_by_pmd_ctx)
    1519           0 :                 break;
    1520           0 :             RTE_LOG(ERR, VROUTER, "Invalid option %s\n", argv[optind - 1]);
    1521           0 :             Usage();
    1522           0 :             break;
    1523             :         }
    1524             :     }
    1525             : 
    1526             :     /* init the timestamp log */
    1527          53 :     dpdk_log = fopen(dpdk_log_file, "a+");
    1528          53 :     if (dpdk_log == NULL) {
    1529          53 :         RTE_LOG(ERR, VROUTER, "Error opening %s: errno %d\n", dpdk_log_file, errno);
    1530             :     }
    1531          53 :     timestamp_log_stream = fopencookie(dpdk_log, "a+", timestamp_log_func);
    1532          53 :     if (timestamp_log_stream == NULL) {
    1533           0 :         printf("Error configuring log stream. Falling back to stdout.\n");
    1534           0 :         timestamp_log_stream = stdout;
    1535             :     }
    1536          53 :     rte_openlog_stream(timestamp_log_stream);
    1537             : 
    1538             :     /* for other getopts in DPDK */
    1539          53 :     optind = 0;
    1540             : 
    1541          53 :     if (!no_daemon_set) {
    1542           0 :         if (daemon(0, 0) < 0) {
    1543           0 :             RTE_LOG(ERR, VROUTER, "Error daemonizing vRouter: %s (%d)\n",
    1544             :                 rte_strerror(errno), errno);
    1545           0 :             return 1;
    1546             :         }
    1547             :     }
    1548             : 
    1549          53 :     vr_perfr = no_gro_set ? 0 : 1;
    1550          53 :     vr_perfs = no_gso_set ? 0 : 1;
    1551             : 
    1552             :     /* init DPDK first since vRouter uses DPDK mallocs and logs */
    1553          53 :     ret = dpdk_init();
    1554          53 :     if (ret != 0) {
    1555           0 :         return ret;
    1556             :     }
    1557             : 
    1558             :     /* associate signal hanlder with signals */
    1559          53 :     ret = dpdk_signals_init();
    1560          53 :     if (ret != 0) {
    1561           0 :         dpdk_exit();
    1562           0 :         return ret;
    1563             :     }
    1564             : 
    1565             :     /* init the vRouter */
    1566          53 :     ret = vr_dpdk_host_init();
    1567          53 :     if (ret != 0) {
    1568           0 :         dpdk_exit();
    1569           0 :         return ret;
    1570             :     }
    1571             : 
    1572             :     /* Init fragment assembler */
    1573          53 :     ret = dpdk_fragment_assembler_init();
    1574          53 :     if (ret != 0) {
    1575           0 :         vr_dpdk_host_exit();
    1576           0 :         dpdk_fragment_assembler_exit();
    1577           0 :         dpdk_exit();
    1578           0 :         return ret;
    1579             :     }
    1580             : 
    1581             :     /* Create VLAN forwarding interface if needed. */
    1582          53 :     if ((vr_dpdk.vlan_tag != VLAN_ID_INVALID) && !vr_dpdk.vtest_vlan) {
    1583           0 :         dpdk_vlan_forwarding_if_add();
    1584             :         /* vRouter can start without the forwarding if, so ignore any errors. */
    1585             :     }
    1586             : 
    1587             :     /* run all the lcores */
    1588          53 :     ret = vr_dpdk_pmd_ctx_launch_lcores(vr_dpdk_lcore_launch);
    1589             : 
    1590          53 :     rte_eal_mp_wait_lcore();
    1591         371 :     RTE_LCORE_FOREACH_SLAVE(lcore_id)
    1592         318 :         dpdk_lcore_exit(lcore_id);
    1593          53 :     dpdk_fragment_assembler_exit();
    1594          53 :     dpdk_netlink_exit();
    1595          53 :     vr_dpdk_host_exit();
    1596          53 :     dpdk_exit();
    1597             : 
    1598          53 :     rte_exit(ret, "vRouter/DPDK is stopped.\n");
    1599             : 
    1600             :     if (dpdk_log) {
    1601             :         fclose(dpdk_log);
    1602             :         dpdk_log = NULL;
    1603             :     }
    1604             : }

Generated by: LCOV version 1.14