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 : }
|