Prepare for DPDK 19.08 support
[samplevnf.git] / VNFs / DPPD-PROX / main.c
1 /*
2 // Copyright (c) 2010-2017 Intel Corporation
3 //
4 // Licensed under the Apache License, Version 2.0 (the "License");
5 // you may not use this file except in compliance with the License.
6 // You may obtain a copy of the License at
7 //
8 //     http://www.apache.org/licenses/LICENSE-2.0
9 //
10 // Unless required by applicable law or agreed to in writing, software
11 // distributed under the License is distributed on an "AS IS" BASIS,
12 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 // See the License for the specific language governing permissions and
14 // limitations under the License.
15 */
16
17 #include <string.h>
18 #include <locale.h>
19 #include <unistd.h>
20 #include <signal.h>
21 #include <curses.h>
22
23 #include <rte_cycles.h>
24 #include <rte_atomic.h>
25 #include <rte_table_hash.h>
26 #include <rte_memzone.h>
27 #include <rte_errno.h>
28
29 #include "prox_malloc.h"
30 #include "run.h"
31 #include "main.h"
32 #include "log.h"
33 #include "quit.h"
34 #include "clock.h"
35 #include "defines.h"
36 #include "version.h"
37 #include "prox_args.h"
38 #include "prox_assert.h"
39 #include "prox_cfg.h"
40 #include "prox_shared.h"
41 #include "prox_port_cfg.h"
42 #include "toeplitz.h"
43 #include "hash_utils.h"
44 #include "handle_lb_net.h"
45 #include "prox_cksum.h"
46 #include "thread_nop.h"
47 #include "thread_generic.h"
48 #include "thread_pipeline.h"
49 #include "cqm.h"
50 #include "handle_master.h"
51
52 #if RTE_VERSION < RTE_VERSION_NUM(1,8,0,0)
53 #define RTE_CACHE_LINE_SIZE CACHE_LINE_SIZE
54 #endif
55
56 uint8_t lb_nb_txrings = 0xff;
57 struct rte_ring *ctrl_rings[RTE_MAX_LCORE*MAX_TASKS_PER_CORE];
58
59 static void __attribute__((noreturn)) prox_usage(const char *prgname)
60 {
61         plog_info("\nUsage: %s [-f CONFIG_FILE] [-a|-e] [-m|-s|-i] [-w DEF] [-u] [-t]\n"
62                   "\t-f CONFIG_FILE : configuration file to load, ./prox.cfg by default\n"
63                   "\t-l LOG_FILE : log file name, ./prox.log by default\n"
64                   "\t-p : include PID in log file name if default log file is used\n"
65                   "\t-o DISPLAY: Set display to use, can be 'curses' (default), 'cli' or 'none'\n"
66                   "\t-v verbosity : initial logging verbosity\n"
67                   "\t-a : autostart all cores (by default)\n"
68                   "\t-e : don't autostart\n"
69                   "\t-n : Create NULL devices instead of using PCI devices, useful together with -i\n"
70                   "\t-m : list supported task modes and exit\n"
71                   "\t-s : check configuration file syntax and exit\n"
72                   "\t-i : check initialization sequence and exit\n"
73                   "\t-u : Listen on UDS /tmp/prox.sock\n"
74                   "\t-t : Listen on TCP port 8474\n"
75                   "\t-q : Pass argument to Lua interpreter, useful to define variables\n"
76                   "\t-w : define variable using syntax varname=value\n"
77                   "\t     takes precedence over variables defined in CONFIG_FILE\n"
78                   "\t-k : Log statistics to file \"stats_dump\" in current directory\n"
79                   "\t-d : Run as daemon, the parent process will block until PROX is not initialized\n"
80                   "\t-z : Ignore CPU topology, implies -i\n"
81                   "\t-r : Change initial screen refresh rate. If set to a lower than 0.001 seconds,\n"
82                   "\t     screen refreshing will be disabled\n"
83                   , prgname);
84         exit(EXIT_FAILURE);
85 }
86
87 static void check_mixed_normal_pipeline(void)
88 {
89         struct lcore_cfg *lconf = NULL;
90         uint32_t lcore_id = -1;
91
92         while (prox_core_next(&lcore_id, 0) == 0) {
93                 lconf = &lcore_cfg[lcore_id];
94
95                 int all_thread_nop = 1;
96                 int generic = 0;
97                 int pipeline = 0;
98                 int l3 = 0;
99                 for (uint8_t task_id = 0; task_id < lconf->n_tasks_all; ++task_id) {
100                         struct task_args *targ = &lconf->targs[task_id];
101                         l3 = !strcmp("l3", targ->sub_mode_str);
102                         all_thread_nop = all_thread_nop && !l3 &&
103                                 targ->task_init->thread_x == thread_nop;
104
105                         pipeline = pipeline || targ->task_init->thread_x == thread_pipeline;
106                         generic = generic || targ->task_init->thread_x == thread_generic || l3;
107                 }
108                 PROX_PANIC(generic && pipeline, "Can't run both pipeline and normal thread on same core\n");
109
110                 if (all_thread_nop)
111                         lconf->thread_x = thread_nop;
112                 else {
113                         lconf->thread_x = thread_generic;
114                 }
115         }
116 }
117
118 static void check_zero_rx(void)
119 {
120         struct lcore_cfg *lconf = NULL;
121         struct task_args *targ;
122
123         while (core_targ_next(&lconf, &targ, 0) == 0) {
124                 if (targ->nb_rxports != 0) {
125                         PROX_PANIC(task_init_flag_set(targ->task_init, TASK_FEATURE_NO_RX),
126                            "\tCore %u task %u: rx_ports configured while mode %s does not use it\n", lconf->id, targ->id, targ->task_init->mode_str);
127                 }
128         }
129 }
130
131 static void check_nb_mbuf(void)
132 {
133         struct lcore_cfg *lconf = NULL;
134         struct task_args *targ = NULL;
135         uint8_t port_id;
136         int n_txd = 0, n_rxd = 0;
137
138         while (core_targ_next(&lconf, &targ, 0) == 0) {
139                 for (uint8_t i = 0; i < targ->nb_txports; ++i) {
140                         port_id = targ->tx_port_queue[i].port;
141                         n_txd = prox_port_cfg[port_id].n_txd;
142                 }
143                 for (uint8_t i = 0; i < targ->nb_rxports; ++i) {
144                         port_id = targ->rx_port_queue[i].port;
145                         n_rxd = prox_port_cfg[port_id].n_rxd;
146                 }
147                 if (targ->nb_mbuf <= n_rxd + n_txd + targ->nb_cache_mbuf + MAX_PKT_BURST) {
148                         plog_warn("Core %d, task %d might not have enough mbufs (%d) to support %d txd, %d rxd and %d cache_mbuf\n",
149                                 lconf->id, targ->id, targ->nb_mbuf, n_txd, n_rxd, targ->nb_cache_mbuf);
150                 }
151         }
152 }
153
154 static void check_missing_rx(void)
155 {
156         struct lcore_cfg *lconf = NULL, *rx_lconf = NULL, *tx_lconf = NULL;
157         struct task_args *targ, *rx_targ = NULL, *tx_targ = NULL;
158         uint8_t port_id, rx_port_id, ok;
159
160         while (core_targ_next(&lconf, &targ, 0) == 0) {
161                 PROX_PANIC((targ->flags & TASK_ARG_RX_RING) && targ->rx_rings[0] == 0 && !targ->tx_opt_ring_task,
162                            "Configuration Error - Core %u task %u Receiving from ring, but nobody xmitting to this ring\n", lconf->id, targ->id);
163                 if (targ->nb_rxports == 0 && targ->nb_rxrings == 0) {
164                         PROX_PANIC(!task_init_flag_set(targ->task_init, TASK_FEATURE_NO_RX),
165                                    "\tCore %u task %u: no rx_ports and no rx_rings configured while required by mode %s\n", lconf->id, targ->id, targ->task_init->mode_str);
166                 }
167         }
168
169         lconf = NULL;
170         while (core_targ_next(&lconf, &targ, 0) == 0) {
171                 if (strcmp(targ->sub_mode_str, "l3") != 0)
172                         continue;
173
174                 PROX_PANIC((targ->nb_rxports == 0) && (targ->nb_txports == 0), "L3 task must have a RX or a TX port\n");
175                 // If the L3 sub_mode receives from a port, check that there is at least one core/task
176                 // transmitting to this port in L3 sub_mode
177                 for (uint8_t i = 0; i < targ->nb_rxports; ++i) {
178                         rx_port_id = targ->rx_port_queue[i].port;
179                         ok = 0;
180                         tx_lconf = NULL;
181                         while (core_targ_next(&tx_lconf, &tx_targ, 0) == 0) {
182                                 if ((port_id = tx_targ->tx_port_queue[0].port) == OUT_DISCARD)
183                                         continue;
184                                 if ((rx_port_id == port_id) && (tx_targ->flags & TASK_ARG_L3)){
185                                         ok = 1;
186                                         break;
187                                 }
188                         }
189                         PROX_PANIC(ok == 0, "RX L3 sub mode for port %d on core %d task %d, but no core/task transmitting on that port\n", rx_port_id, lconf->id, targ->id);
190                 }
191
192                 // If the L3 sub_mode transmits to a port, check that there is at least one core/task
193                 // receiving from that port in L3 sub_mode.
194                 if ((port_id = targ->tx_port_queue[0].port) == OUT_DISCARD)
195                         continue;
196                 rx_lconf = NULL;
197                 ok = 0;
198                 plog_info("\tCore %d task %d transmitting to port %d in L3 mode\n", lconf->id, targ->id, port_id);
199                 while (core_targ_next(&rx_lconf, &rx_targ, 0) == 0) {
200                         for (uint8_t i = 0; i < rx_targ->nb_rxports; ++i) {
201                                 rx_port_id = rx_targ->rx_port_queue[i].port;
202                                 if ((rx_port_id == port_id) && (rx_targ->flags & TASK_ARG_L3)){
203                                         ok = 1;
204                                         break;
205                                 }
206                         }
207                         if (ok == 1) {
208                                 plog_info("\tCore %d task %d has found core %d task %d receiving from port %d\n", lconf->id, targ->id, rx_lconf->id, rx_targ->id, port_id);
209                                 break;
210                         }
211                 }
212                 PROX_PANIC(ok == 0, "L3 sub mode for port %d on core %d task %d, but no core/task receiving on that port\n", port_id, lconf->id, targ->id);
213         }
214 }
215
216 static void check_cfg_consistent(void)
217 {
218         check_nb_mbuf();
219         check_missing_rx();
220         check_zero_rx();
221         check_mixed_normal_pipeline();
222 }
223
224 static void plog_all_rings(void)
225 {
226         struct lcore_cfg *lconf = NULL;
227         struct task_args *targ;
228
229         while (core_targ_next(&lconf, &targ, 0) == 0) {
230                 for (uint8_t ring_idx = 0; ring_idx < targ->nb_rxrings; ++ring_idx) {
231                         plog_info("\tCore %u, task %u, rx_ring[%u] %p\n", lconf->id, targ->id, ring_idx, targ->rx_rings[ring_idx]);
232                 }
233         }
234 }
235
236 static int chain_flag_state(struct task_args *targ, uint64_t flag, int is_set)
237 {
238         if (task_init_flag_set(targ->task_init, flag) == is_set)
239                 return 1;
240
241         int ret = 0;
242
243         for (uint32_t i = 0; i < targ->n_prev_tasks; ++i) {
244                 ret = chain_flag_state(targ->prev_tasks[i], flag, is_set);
245                 if (ret)
246                         return 1;
247         }
248         return 0;
249 }
250
251 static int chain_flag_always_set(struct task_args *targ, uint64_t flag)
252 {
253         return (!chain_flag_state(targ, flag, 0));
254 }
255
256 static int chain_flag_never_set(struct task_args *targ, uint64_t flag)
257 {
258         return (!chain_flag_state(targ, flag, 1));
259 }
260
261 static int chain_flag_sometimes_set(struct task_args *targ, uint64_t flag)
262 {
263         return (chain_flag_state(targ, flag, 1));
264 }
265
266 static void configure_if_tx_queues(struct task_args *targ, uint8_t socket)
267 {
268         uint8_t if_port;
269
270         for (uint8_t i = 0; i < targ->nb_txports; ++i) {
271                 if_port = targ->tx_port_queue[i].port;
272
273                 PROX_PANIC(if_port == OUT_DISCARD, "port misconfigured, exiting\n");
274
275                 PROX_PANIC(!prox_port_cfg[if_port].active, "\tPort %u not used, skipping...\n", if_port);
276
277                 int dsocket = prox_port_cfg[if_port].socket;
278                 if (dsocket != -1 && dsocket != socket) {
279                         plog_warn("TX core on socket %d while device on socket %d\n", socket, dsocket);
280                 }
281
282                 if (prox_port_cfg[if_port].tx_ring[0] == '\0') {  // Rings-backed port can use single queue
283                         targ->tx_port_queue[i].queue = prox_port_cfg[if_port].n_txq;
284                         prox_port_cfg[if_port].n_txq++;
285                 } else {
286                         prox_port_cfg[if_port].n_txq = 1;
287                         targ->tx_port_queue[i].queue = 0;
288                 }
289                 /* By default OFFLOAD is enabled, but if the whole
290                    chain has NOOFFLOADS set all the way until the
291                    first task that receives from a port, it will be
292                    disabled for the destination port. */
293 #if RTE_VERSION < RTE_VERSION_NUM(18,8,0,1)
294                 if (chain_flag_always_set(targ, TASK_FEATURE_TXQ_FLAGS_NOOFFLOADS)) {
295                         prox_port_cfg[if_port].tx_conf.txq_flags |= ETH_TXQ_FLAGS_NOOFFLOADS;
296                 }
297 #else
298                 if (chain_flag_always_set(targ, TASK_FEATURE_TXQ_FLAGS_NOOFFLOADS)) {
299                         prox_port_cfg[if_port].requested_tx_offload &= ~(DEV_TX_OFFLOAD_IPV4_CKSUM | DEV_TX_OFFLOAD_UDP_CKSUM);
300                 }
301 #endif
302         }
303 }
304
305 static void configure_if_rx_queues(struct task_args *targ, uint8_t socket)
306 {
307         struct prox_port_cfg *port;
308         for (int i = 0; i < targ->nb_rxports; i++) {
309                 uint8_t if_port = targ->rx_port_queue[i].port;
310
311                 if (if_port == OUT_DISCARD) {
312                         return;
313                 }
314
315                 port = &prox_port_cfg[if_port];
316                 PROX_PANIC(!port->active, "Port %u not used, aborting...\n", if_port);
317
318                 if(port->rx_ring[0] != '\0') {
319                         port->n_rxq = 0;
320                 }
321
322                 // If the mbuf size (of the rx task) is not big enough, we might receive multiple segments
323                 // This is usually the case when setting a big mtu size i.e. enabling jumbo frames.
324                 // If the packets get transmitted, then multi segments will have to be enabled on the TX port
325                 uint16_t max_frame_size = port->mtu + PROX_RTE_ETHER_HDR_LEN + PROX_RTE_ETHER_CRC_LEN + 2 * PROX_VLAN_TAG_SIZE;
326                 if (max_frame_size + sizeof(struct rte_mbuf) + RTE_PKTMBUF_HEADROOM > targ->mbuf_size) {
327                         targ->task_init->flag_features |= TASK_FEATURE_TXQ_FLAGS_MULTSEGS;
328                 }
329                 targ->rx_port_queue[i].queue = port->n_rxq;
330                 port->pool[targ->rx_port_queue[i].queue] = targ->pool;
331                 port->pool_size[targ->rx_port_queue[i].queue] = targ->nb_mbuf - 1;
332                 port->n_rxq++;
333
334                 int dsocket = port->socket;
335                 if (dsocket != -1 && dsocket != socket) {
336                         plog_warn("RX core on socket %d while device on socket %d\n", socket, dsocket);
337                 }
338         }
339 }
340
341 static void configure_if_queues(void)
342 {
343         struct lcore_cfg *lconf = NULL;
344         struct task_args *targ;
345         uint8_t socket;
346
347         while (core_targ_next(&lconf, &targ, 0) == 0) {
348                 socket = rte_lcore_to_socket_id(lconf->id);
349
350                 configure_if_rx_queues(targ, socket);
351                 configure_if_tx_queues(targ, socket);
352         }
353 }
354
355 static void configure_tx_queue_flags(void)
356 {
357         struct lcore_cfg *lconf = NULL;
358         struct task_args *targ;
359         uint8_t socket;
360         uint8_t if_port;
361
362         while (core_targ_next(&lconf, &targ, 0) == 0) {
363                 socket = rte_lcore_to_socket_id(lconf->id);
364                 for (uint8_t i = 0; i < targ->nb_txports; ++i) {
365                         if_port = targ->tx_port_queue[i].port;
366 #if RTE_VERSION < RTE_VERSION_NUM(18,8,0,1)
367                         /* Set the ETH_TXQ_FLAGS_NOREFCOUNT flag if none of
368                         the tasks up to the task transmitting to the port
369                         use refcnt. */
370                         if (chain_flag_never_set(targ, TASK_FEATURE_TXQ_FLAGS_REFCOUNT)) {
371                                 prox_port_cfg[if_port].tx_conf.txq_flags |= ETH_TXQ_FLAGS_NOREFCOUNT;
372                         }
373 #else
374                         /* Set the DEV_TX_OFFLOAD_MBUF_FAST_FREE flag if none of
375                         the tasks up to the task transmitting to the port
376                         use refcnt and per-queue all mbufs comes from the same mempool. */
377                         if (chain_flag_never_set(targ, TASK_FEATURE_TXQ_FLAGS_REFCOUNT)) {
378                                 if (chain_flag_never_set(targ, TASK_FEATURE_TXQ_FLAGS_MULTIPLE_MEMPOOL))
379                                         prox_port_cfg[if_port].requested_tx_offload |= DEV_TX_OFFLOAD_MBUF_FAST_FREE;
380                         }
381 #endif
382                 }
383         }
384 }
385
386 static void configure_multi_segments(void)
387 {
388         struct lcore_cfg *lconf = NULL;
389         struct task_args *targ;
390         uint8_t if_port;
391
392         while (core_targ_next(&lconf, &targ, 0) == 0) {
393                 for (uint8_t i = 0; i < targ->nb_txports; ++i) {
394                         if_port = targ->tx_port_queue[i].port;
395                         // Multi segment is disabled for most tasks. It is only enabled for tasks requiring big packets.
396 #if RTE_VERSION < RTE_VERSION_NUM(18,8,0,1)
397                         // We can only enable "no multi segment" if no such task exists in the chain of tasks.
398                         if (chain_flag_never_set(targ, TASK_FEATURE_TXQ_FLAGS_MULTSEGS)) {
399                                 prox_port_cfg[if_port].tx_conf.txq_flags |= ETH_TXQ_FLAGS_NOMULTSEGS;
400                         }
401 #else
402                         // We enable "multi segment" if at least one task requires it in the chain of tasks.
403                         if (chain_flag_sometimes_set(targ, TASK_FEATURE_TXQ_FLAGS_MULTSEGS)) {
404                                 prox_port_cfg[if_port].requested_tx_offload |= DEV_TX_OFFLOAD_MULTI_SEGS;
405                         }
406 #endif
407                 }
408         }
409 }
410
411 static const char *gen_ring_name(void)
412 {
413         static char retval[] = "XX";
414         static const char* ring_names =
415                 "ABCDEFGHIJKLMNOPQRSTUVWXYZ"
416                 "abcdefghijklmnopqrstuvwxyz"
417                 "[\\]^_`!\"#$%&'()*+,-./:;<="
418                 ">?@{|}0123456789";
419         static int idx2 = 0;
420
421         int idx = idx2;
422
423         retval[0] = ring_names[idx % strlen(ring_names)];
424         idx /= strlen(ring_names);
425         retval[1] = idx ? ring_names[(idx - 1) % strlen(ring_names)] : 0;
426
427         idx2++;
428
429         return retval;
430 }
431
432 struct ring_init_stats {
433         uint32_t n_pkt_rings;
434         uint32_t n_ctrl_rings;
435         uint32_t n_opt_rings;
436 };
437
438 static uint32_t ring_init_stats_total(const struct ring_init_stats *ris)
439 {
440         return ris->n_pkt_rings + ris->n_ctrl_rings + ris->n_opt_rings;
441 }
442
443 static uint32_t count_incoming_tasks(uint32_t lcore_worker, uint32_t dest_task)
444 {
445         struct lcore_cfg *lconf = NULL;
446         struct task_args *targ;
447         uint32_t ret = 0;
448         struct core_task ct;
449
450         while (core_targ_next(&lconf, &targ, 0) == 0) {
451                 for (uint8_t idxx = 0; idxx < MAX_PROTOCOLS; ++idxx) {
452                         for (uint8_t ridx = 0; ridx < targ->core_task_set[idxx].n_elems; ++ridx) {
453                                 ct = targ->core_task_set[idxx].core_task[ridx];
454
455                                 if (dest_task == ct.task && lcore_worker == ct.core)
456                                         ret++;
457                         }
458                 }
459         }
460         return ret;
461 }
462
463 static struct rte_ring *get_existing_ring(uint32_t lcore_id, uint32_t task_id)
464 {
465         if (!prox_core_active(lcore_id, 0))
466                 return NULL;
467
468         struct lcore_cfg *lconf = &lcore_cfg[lcore_id];
469
470         if (task_id >= lconf->n_tasks_all)
471                 return NULL;
472
473         if (lconf->targs[task_id].nb_rxrings == 0)
474                 return NULL;
475
476         return lconf->targs[task_id].rx_rings[0];
477 }
478
479 static struct rte_ring *init_ring_between_tasks(struct lcore_cfg *lconf, struct task_args *starg,
480                                     const struct core_task ct, uint8_t ring_idx, int idx,
481                                     struct ring_init_stats *ris)
482 {
483         uint8_t socket;
484         struct rte_ring *ring = NULL;
485         struct lcore_cfg *lworker;
486         struct task_args *dtarg;
487
488         PROX_ASSERT(prox_core_active(ct.core, 0));
489         lworker = &lcore_cfg[ct.core];
490
491         /* socket used is the one that the sending core resides on */
492         socket = rte_lcore_to_socket_id(lconf->id);
493
494         plog_info("\t\tCreating ring on socket %u with size %u\n"
495                   "\t\t\tsource core, task and socket = %u, %u, %u\n"
496                   "\t\t\tdestination core, task and socket = %u, %u, %u\n"
497                   "\t\t\tdestination worker id = %u\n",
498                   socket, starg->ring_size,
499                   lconf->id, starg->id, socket,
500                   ct.core, ct.task, rte_lcore_to_socket_id(ct.core),
501                   ring_idx);
502
503         if (ct.type) {
504                 struct rte_ring **dring = NULL;
505
506                 if (ct.type == CTRL_TYPE_MSG)
507                         dring = &lworker->ctrl_rings_m[ct.task];
508                 else if (ct.type == CTRL_TYPE_PKT) {
509                         dring = &lworker->ctrl_rings_p[ct.task];
510                         starg->flags |= TASK_ARG_CTRL_RINGS_P;
511                 }
512
513                 if (*dring == NULL)
514                         ring = rte_ring_create(gen_ring_name(), starg->ring_size, socket, RING_F_SC_DEQ);
515                 else
516                         ring = *dring;
517                 PROX_PANIC(ring == NULL, "Cannot create ring to connect I/O core %u with worker core %u\n", lconf->id, ct.core);
518
519                 starg->tx_rings[starg->tot_n_txrings_inited] = ring;
520                 starg->tot_n_txrings_inited++;
521                 *dring = ring;
522                 if (lconf->id == prox_cfg.master) {
523                         ctrl_rings[ct.core*MAX_TASKS_PER_CORE + ct.task] = ring;
524                 } else if (ct.core == prox_cfg.master) {
525                         starg->ctrl_plane_ring = ring;
526                 }
527
528                 plog_info("\t\t\tCore %u task %u to -> core %u task %u ctrl_ring %s %p %s\n",
529                           lconf->id, starg->id, ct.core, ct.task, ct.type == CTRL_TYPE_PKT?
530                           "pkt" : "msg", ring, ring->name);
531                 ris->n_ctrl_rings++;
532                 return ring;
533         }
534
535         dtarg = &lworker->targs[ct.task];
536         lworker->targs[ct.task].worker_thread_id = ring_idx;
537         PROX_ASSERT(dtarg->flags & TASK_ARG_RX_RING);
538         PROX_ASSERT(ct.task < lworker->n_tasks_all);
539
540         /* If all the following conditions are met, the ring can be
541            optimized away. */
542         if (!task_is_master(starg) && !task_is_master(dtarg) && starg->lconf->id == dtarg->lconf->id &&
543             starg->nb_txrings == 1 && idx == 0 && dtarg->task &&
544             dtarg->tot_rxrings == 1 && starg->task == dtarg->task - 1) {
545                 plog_info("\t\tOptimizing away ring on core %u from task %u to task %u\n",
546                           dtarg->lconf->id, starg->task, dtarg->task);
547                 /* No need to set up ws_mbuf. */
548                 starg->tx_opt_ring = 1;
549                 /* During init of destination task, the buffer in the
550                    source task will be initialized. */
551                 dtarg->tx_opt_ring_task = starg;
552                 ris->n_opt_rings++;
553                 ++dtarg->nb_rxrings;
554                 return NULL;
555         }
556
557         int ring_created = 1;
558         /* Only create multi-producer rings if configured to do so AND
559            there is only one task sending to the task */
560         if ((prox_cfg.flags & DSF_MP_RINGS && count_incoming_tasks(ct.core, ct.task) > 1)
561                 || (prox_cfg.flags & DSF_ENABLE_BYPASS)) {
562                 ring = get_existing_ring(ct.core, ct.task);
563
564                 if (ring) {
565                         plog_info("\t\tCore %u task %u creatign MP ring %p to core %u task %u\n",
566                                   lconf->id, starg->id, ring, ct.core, ct.task);
567                         ring_created = 0;
568                 }
569                 else {
570                         ring = rte_ring_create(gen_ring_name(), starg->ring_size, socket, RING_F_SC_DEQ);
571                         plog_info("\t\tCore %u task %u using MP ring %p from core %u task %u\n",
572                                   lconf->id, starg->id, ring, ct.core, ct.task);
573                 }
574         }
575         else
576                 ring = rte_ring_create(gen_ring_name(), starg->ring_size, socket, RING_F_SP_ENQ | RING_F_SC_DEQ);
577
578         PROX_PANIC(ring == NULL, "Cannot create ring to connect I/O core %u with worker core %u\n", lconf->id, ct.core);
579
580         starg->tx_rings[starg->tot_n_txrings_inited] = ring;
581         starg->tot_n_txrings_inited++;
582
583         if (ring_created) {
584                 PROX_ASSERT(dtarg->nb_rxrings < MAX_RINGS_PER_TASK);
585                 dtarg->rx_rings[dtarg->nb_rxrings] = ring;
586                 ++dtarg->nb_rxrings;
587                 if (dtarg->nb_rxrings > 1)
588                         dtarg->task_init->flag_features |= TASK_FEATURE_TXQ_FLAGS_MULTIPLE_MEMPOOL;
589         }
590         dtarg->nb_slave_threads = starg->core_task_set[idx].n_elems;
591         dtarg->lb_friend_core = lconf->id;
592         dtarg->lb_friend_task = starg->id;
593         plog_info("\t\tWorker thread %d has core %d, task %d as a lb friend\n", ct.core, lconf->id, starg->id);
594         plog_info("\t\tCore %u task %u tx_ring[%u] -> core %u task %u rx_ring[%u] %p %s %u WT\n",
595                   lconf->id, starg->id, ring_idx, ct.core, ct.task, dtarg->nb_rxrings, ring, ring->name,
596                   dtarg->nb_slave_threads);
597         ++ris->n_pkt_rings;
598         return ring;
599 }
600
601 static void init_rings(void)
602 {
603         struct lcore_cfg *lconf = NULL;
604         struct task_args *starg;
605         struct ring_init_stats ris = {0};
606
607         while (core_targ_next(&lconf, &starg, 1) == 0) {
608                 plog_info("\t*** Initializing rings on core %u, task %u ***\n", lconf->id, starg->id);
609                 for (uint8_t idx = 0; idx < MAX_PROTOCOLS; ++idx) {
610                         for (uint8_t ring_idx = 0; ring_idx < starg->core_task_set[idx].n_elems; ++ring_idx) {
611                                 PROX_ASSERT(ring_idx < MAX_WT_PER_LB);
612                                 PROX_ASSERT(starg->tot_n_txrings_inited < MAX_RINGS_PER_TASK);
613
614                                 struct core_task ct = starg->core_task_set[idx].core_task[ring_idx];
615                                 init_ring_between_tasks(lconf, starg, ct, ring_idx, idx, &ris);
616                         }
617                 }
618         }
619
620         plog_info("\tInitialized %d rings:\n"
621                   "\t\tNumber of packet rings: %u\n"
622                   "\t\tNumber of control rings: %u\n"
623                   "\t\tNumber of optimized rings: %u\n",
624                   ring_init_stats_total(&ris),
625                   ris.n_pkt_rings,
626                   ris.n_ctrl_rings,
627                   ris.n_opt_rings);
628
629         lconf = NULL;
630         struct prox_port_cfg *port;
631         while (core_targ_next(&lconf, &starg, 1) == 0) {
632                 if ((starg->task_init) && (starg->flags & TASK_ARG_L3)) {
633                         struct core_task ct;
634                         ct.core = prox_cfg.master;
635                         ct.task = 0;
636                         ct.type = CTRL_TYPE_PKT;
637                         struct rte_ring *rx_ring = init_ring_between_tasks(lconf, starg, ct, 0, 0, &ris);
638
639                         ct.core = lconf->id;
640                         ct.task = starg->id;;
641                         struct rte_ring *tx_ring = init_ring_between_tasks(&lcore_cfg[prox_cfg.master], lcore_cfg[prox_cfg.master].targs, ct, 0, 0, &ris);
642                 }
643         }
644 }
645
646 static void shuffle_mempool(struct rte_mempool* mempool, uint32_t nb_mbuf)
647 {
648         struct rte_mbuf** pkts = prox_zmalloc(nb_mbuf * sizeof(*pkts), rte_socket_id());
649         uint64_t got = 0;
650
651         while ((got < nb_mbuf) && (rte_mempool_get_bulk(mempool, (void**)(pkts + got), 1) == 0))
652                 ++got;
653
654         nb_mbuf = got;
655         while (got) {
656                 int idx;
657                 do {
658                         idx = rand() % nb_mbuf;
659                 } while (pkts[idx] == 0);
660
661                 rte_mempool_put_bulk(mempool, (void**)&pkts[idx], 1);
662                 pkts[idx] = 0;
663                 --got;
664         };
665         prox_free(pkts);
666 }
667
668 static void set_mbuf_size(struct task_args *targ)
669 {
670         /* mbuf size can be set
671          *  - from config file (highest priority, overwriting any other config) - should only be used as workaround
672          *  - defaulted to MBUF_SIZE.
673          * Except if set explicitely, ensure that size is big enough for vmxnet3 driver
674          */
675         if (targ->mbuf_size)
676                 return;
677
678         targ->mbuf_size = MBUF_SIZE;
679         struct prox_port_cfg *port;
680         uint16_t max_frame_size = 0, min_buffer_size = 0;
681         int i40e = 0;
682         for (int i = 0; i < targ->nb_rxports; i++) {
683                 uint8_t if_port = targ->rx_port_queue[i].port;
684
685                 if (if_port == OUT_DISCARD) {
686                         continue;
687                 }
688                 port = &prox_port_cfg[if_port];
689                 if (max_frame_size < port->mtu + PROX_RTE_ETHER_HDR_LEN + PROX_RTE_ETHER_CRC_LEN + 2 * PROX_VLAN_TAG_SIZE)
690                         max_frame_size = port->mtu + PROX_RTE_ETHER_HDR_LEN + PROX_RTE_ETHER_CRC_LEN + 2 * PROX_VLAN_TAG_SIZE;
691                 if (min_buffer_size < port->min_rx_bufsize)
692                         min_buffer_size = port->min_rx_bufsize;
693
694                 // Check whether we receive from i40e. This driver have extra mbuf size requirements
695                 if (strcmp(port->short_name, "i40e") == 0)
696                         i40e = 1;
697         }
698         if (i40e) {
699                 // i40e supports a maximum of 5 descriptors chained
700                 uint16_t required_mbuf_size = RTE_ALIGN(max_frame_size / 5, 128) + sizeof(struct rte_mbuf) + RTE_PKTMBUF_HEADROOM;
701                 if (required_mbuf_size > targ->mbuf_size) {
702                         targ->mbuf_size = required_mbuf_size;
703                         plog_info("\t\tSetting mbuf_size to %u to support frame_size %u\n", targ->mbuf_size, max_frame_size);
704                 }
705         }
706         if (min_buffer_size > targ->mbuf_size) {
707                 plog_warn("Mbuf size might be too small. This might result in packet segmentation and memory leak\n");
708         }
709
710 }
711
712 static void setup_mempools_unique_per_socket(void)
713 {
714         uint32_t flags = 0;
715         char name[64];
716         struct lcore_cfg *lconf = NULL;
717         struct task_args *targ;
718
719         struct rte_mempool     *pool[MAX_SOCKETS];
720         uint32_t mbuf_count[MAX_SOCKETS] = {0};
721         uint32_t nb_cache_mbuf[MAX_SOCKETS] = {0};
722         uint32_t mbuf_size[MAX_SOCKETS] = {0};
723
724         while (core_targ_next_early(&lconf, &targ, 0) == 0) {
725                 PROX_PANIC(targ->task_init == NULL, "task_init = NULL, is mode specified for core %d, task %d ?\n", lconf->id, targ->id);
726                 uint8_t socket = rte_lcore_to_socket_id(lconf->id);
727                 PROX_ASSERT(socket < MAX_SOCKETS);
728
729                 set_mbuf_size(targ);
730                 if (targ->rx_port_queue[0].port != OUT_DISCARD) {
731                         struct prox_port_cfg* port_cfg = &prox_port_cfg[targ->rx_port_queue[0].port];
732                         PROX_ASSERT(targ->nb_mbuf != 0);
733                         mbuf_count[socket] += targ->nb_mbuf;
734                         if (nb_cache_mbuf[socket] == 0)
735                                 nb_cache_mbuf[socket] = targ->nb_cache_mbuf;
736                         else {
737                                 PROX_PANIC(nb_cache_mbuf[socket] != targ->nb_cache_mbuf,
738                                            "all mbuf_cache must have the same size if using a unique mempool per socket\n");
739                         }
740                         if (mbuf_size[socket] == 0)
741                                 mbuf_size[socket] = targ->mbuf_size;
742                         else {
743                                 PROX_PANIC(mbuf_size[socket] != targ->mbuf_size,
744                                            "all mbuf_size must have the same size if using a unique mempool per socket\n");
745                         }
746                 }
747         }
748         for (int i = 0 ; i < MAX_SOCKETS; i++) {
749                 if (mbuf_count[i] != 0) {
750                         sprintf(name, "socket_%u_pool", i);
751                         pool[i] = rte_mempool_create(name,
752                                                      mbuf_count[i] - 1, mbuf_size[i],
753                                                      nb_cache_mbuf[i],
754                                                      sizeof(struct rte_pktmbuf_pool_private),
755                                                      rte_pktmbuf_pool_init, NULL,
756                                                      prox_pktmbuf_init, NULL,
757                                                      i, flags);
758                         PROX_PANIC(pool[i] == NULL, "\t\tError: cannot create mempool for socket %u\n", i);
759                         plog_info("\t\tMempool %p size = %u * %u cache %u, socket %d\n", pool[i],
760                                   mbuf_count[i], mbuf_size[i], nb_cache_mbuf[i], i);
761
762                         if (prox_cfg.flags & DSF_SHUFFLE) {
763                                 shuffle_mempool(pool[i], mbuf_count[i]);
764                         }
765                 }
766         }
767
768         lconf = NULL;
769         while (core_targ_next_early(&lconf, &targ, 0) == 0) {
770                 uint8_t socket = rte_lcore_to_socket_id(lconf->id);
771
772                 if (targ->rx_port_queue[0].port != OUT_DISCARD) {
773                         /* use this pool for the interface that the core is receiving from */
774                         /* If one core receives from multiple ports, all the ports use the same mempool */
775                         targ->pool = pool[socket];
776                         /* Set the number of mbuf to the number of the unique mempool, so that the used and free work */
777                         targ->nb_mbuf = mbuf_count[socket];
778                         plog_info("\t\tMempool %p size = %u * %u cache %u, socket %d\n", targ->pool,
779                                   targ->nb_mbuf, mbuf_size[socket], targ->nb_cache_mbuf, socket);
780                 }
781         }
782 }
783
784 static void setup_mempool_for_rx_task(struct lcore_cfg *lconf, struct task_args *targ)
785 {
786         const uint8_t socket = rte_lcore_to_socket_id(lconf->id);
787         struct prox_port_cfg *port_cfg = &prox_port_cfg[targ->rx_port_queue[0].port];
788         const struct rte_memzone *mz;
789         struct rte_mempool *mp = NULL;
790         uint32_t flags = 0;
791         char memzone_name[64];
792         char name[64];
793
794         set_mbuf_size(targ);
795
796         /* allocate memory pool for packets */
797         PROX_ASSERT(targ->nb_mbuf != 0);
798
799         if (targ->pool_name[0] == '\0') {
800                 sprintf(name, "core_%u_port_%u_pool", lconf->id, targ->id);
801         }
802
803         snprintf(memzone_name, sizeof(memzone_name)-1, "MP_%s", targ->pool_name);
804         mz = rte_memzone_lookup(memzone_name);
805
806         if (mz != NULL) {
807                 mp = (struct rte_mempool*)mz->addr;
808
809                 targ->nb_mbuf = mp->size;
810                 targ->pool = mp;
811         }
812
813 #ifdef RTE_LIBRTE_IVSHMEM_FALSE
814         if (mz != NULL && mp != NULL && mp->phys_addr != mz->ioremap_addr) {
815                 /* Init mbufs with ioremap_addr for dma */
816                 mp->phys_addr = mz->ioremap_addr;
817                 mp->elt_pa[0] = mp->phys_addr + (mp->elt_va_start - (uintptr_t)mp);
818
819                 struct prox_pktmbuf_reinit_args init_args;
820                 init_args.mp = mp;
821                 init_args.lconf = lconf;
822
823                 uint32_t elt_sz = mp->elt_size + mp->header_size + mp->trailer_size;
824                 rte_mempool_obj_iter((void*)mp->elt_va_start, mp->size, elt_sz, 1,
825                                      mp->elt_pa, mp->pg_num, mp->pg_shift, prox_pktmbuf_reinit, &init_args);
826         }
827 #endif
828
829         /* Use this pool for the interface that the core is
830            receiving from if one core receives from multiple
831            ports, all the ports use the same mempool */
832         if (targ->pool == NULL) {
833                 plog_info("\t\tCreating mempool with name '%s'\n", name);
834                 targ->pool = rte_mempool_create(name,
835                                                 targ->nb_mbuf - 1, targ->mbuf_size,
836                                                 targ->nb_cache_mbuf,
837                                                 sizeof(struct rte_pktmbuf_pool_private),
838                                                 rte_pktmbuf_pool_init, NULL,
839                                                 prox_pktmbuf_init, lconf,
840                                                 socket, flags);
841         }
842
843         PROX_PANIC(targ->pool == NULL,
844                    "\t\tError: cannot create mempool for core %u port %u: %s\n", lconf->id, targ->id, rte_strerror(rte_errno));
845
846         plog_info("\t\tMempool %p size = %u * %u cache %u, socket %d\n", targ->pool,
847                   targ->nb_mbuf, targ->mbuf_size, targ->nb_cache_mbuf, socket);
848         if (prox_cfg.flags & DSF_SHUFFLE) {
849                 shuffle_mempool(targ->pool, targ->nb_mbuf);
850         }
851 }
852
853 static void setup_mempools_multiple_per_socket(void)
854 {
855         struct lcore_cfg *lconf = NULL;
856         struct task_args *targ;
857
858         while (core_targ_next_early(&lconf, &targ, 0) == 0) {
859                 PROX_PANIC(targ->task_init == NULL, "task_init = NULL, is mode specified for core %d, task %d ?\n", lconf->id, targ->id);
860                 if (targ->rx_port_queue[0].port == OUT_DISCARD)
861                         continue;
862                 setup_mempool_for_rx_task(lconf, targ);
863         }
864 }
865
866 static void setup_mempools(void)
867 {
868         if (prox_cfg.flags & UNIQUE_MEMPOOL_PER_SOCKET)
869                 setup_mempools_unique_per_socket();
870         else
871                 setup_mempools_multiple_per_socket();
872 }
873
874 static void set_task_lconf(void)
875 {
876         struct lcore_cfg *lconf;
877         uint32_t lcore_id = -1;
878
879         while(prox_core_next(&lcore_id, 1) == 0) {
880                 lconf = &lcore_cfg[lcore_id];
881                 for (uint8_t task_id = 0; task_id < lconf->n_tasks_all; ++task_id) {
882                         lconf->targs[task_id].lconf = lconf;
883                 }
884         }
885 }
886
887 static void set_dest_threads(void)
888 {
889         struct lcore_cfg *lconf = NULL;
890         struct task_args *targ;
891
892         while (core_targ_next(&lconf, &targ, 0) == 0) {
893                 for (uint8_t idx = 0; idx < MAX_PROTOCOLS; ++idx) {
894                         for (uint8_t ring_idx = 0; ring_idx < targ->core_task_set[idx].n_elems; ++ring_idx) {
895                                 struct core_task ct = targ->core_task_set[idx].core_task[ring_idx];
896
897                                 struct task_args *dest_task = core_targ_get(ct.core, ct.task);
898                                 dest_task->prev_tasks[dest_task->n_prev_tasks++] = targ;
899                         }
900                 }
901         }
902 }
903
904 static void setup_all_task_structs_early_init(void)
905 {
906         struct lcore_cfg *lconf = NULL;
907         struct task_args *targ;
908
909         plog_info("\t*** Calling early init on all tasks ***\n");
910         while (core_targ_next(&lconf, &targ, 0) == 0) {
911                 if (targ->task_init->early_init) {
912                         targ->task_init->early_init(targ);
913                 }
914         }
915 }
916
917 static void setup_all_task_structs(void)
918 {
919         struct lcore_cfg *lconf;
920         uint32_t lcore_id = -1;
921         struct task_base *tmaster = NULL;
922
923         while(prox_core_next(&lcore_id, 1) == 0) {
924                 lconf = &lcore_cfg[lcore_id];
925                 for (uint8_t task_id = 0; task_id < lconf->n_tasks_all; ++task_id) {
926                         if (task_is_master(&lconf->targs[task_id])) {
927                                 plog_info("\tInitializing MASTER struct for core %d task %d\n", lcore_id, task_id);
928                                 lconf->tasks_all[task_id] = init_task_struct(&lconf->targs[task_id]);
929                                 tmaster = lconf->tasks_all[task_id];
930                         }
931                 }
932         }
933         PROX_PANIC(tmaster == NULL, "Can't initialize master task\n");
934         lcore_id = -1;
935
936         while(prox_core_next(&lcore_id, 1) == 0) {
937                 lconf = &lcore_cfg[lcore_id];
938                 plog_info("\tInitializing struct for core %d with %d task\n", lcore_id, lconf->n_tasks_all);
939                 for (uint8_t task_id = 0; task_id < lconf->n_tasks_all; ++task_id) {
940                         if (!task_is_master(&lconf->targs[task_id])) {
941                                 plog_info("\tInitializing struct for core %d task %d\n", lcore_id, task_id);
942                                 lconf->targs[task_id].tmaster = tmaster;
943                                 lconf->tasks_all[task_id] = init_task_struct(&lconf->targs[task_id]);
944                         }
945                 }
946         }
947 }
948
949 static void init_port_activate(void)
950 {
951         struct lcore_cfg *lconf = NULL;
952         struct task_args *targ;
953         uint8_t port_id = 0;
954
955         while (core_targ_next_early(&lconf, &targ, 0) == 0) {
956                 for (int i = 0; i < targ->nb_rxports; i++) {
957                         port_id = targ->rx_port_queue[i].port;
958                         prox_port_cfg[port_id].active = 1;
959                 }
960
961                 for (int i = 0; i < targ->nb_txports; i++) {
962                         port_id = targ->tx_port_queue[i].port;
963                         prox_port_cfg[port_id].active = 1;
964                 }
965         }
966 }
967
968 /* Initialize cores and allocate mempools */
969 static void init_lcores(void)
970 {
971         struct lcore_cfg *lconf = 0;
972         uint32_t lcore_id = -1;
973
974         while(prox_core_next(&lcore_id, 0) == 0) {
975                 uint8_t socket = rte_lcore_to_socket_id(lcore_id);
976                 PROX_PANIC(socket + 1 > MAX_SOCKETS, "Can't configure core %u (on socket %u). MAX_SOCKET is set to %d\n", lcore_id, socket, MAX_SOCKETS);
977         }
978
979         /* need to allocate mempools as the first thing to use the lowest possible address range */
980         plog_info("=== Initializing mempools ===\n");
981         setup_mempools();
982
983         lcore_cfg_alloc_hp();
984
985         set_dest_threads();
986         set_task_lconf();
987
988         plog_info("=== Initializing port addresses ===\n");
989         init_port_addr();
990
991         plog_info("=== Initializing queue numbers on cores ===\n");
992         configure_if_queues();
993
994         plog_info("=== Initializing rings on cores ===\n");
995         init_rings();
996
997         configure_multi_segments();
998         configure_tx_queue_flags();
999
1000         plog_info("=== Checking configuration consistency ===\n");
1001         check_cfg_consistent();
1002
1003         plog_all_rings();
1004 }
1005
1006 static int setup_prox(int argc, char **argv)
1007 {
1008         if (prox_read_config_file() != 0 ||
1009             prox_setup_rte(argv[0]) != 0) {
1010                 return -1;
1011         }
1012
1013         if (prox_cfg.flags & DSF_CHECK_SYNTAX) {
1014                 plog_info("=== Configuration file syntax has been checked ===\n\n");
1015                 exit(EXIT_SUCCESS);
1016         }
1017
1018         init_port_activate();
1019         plog_info("=== Initializing rte devices ===\n");
1020         if (!(prox_cfg.flags & DSF_USE_DUMMY_DEVICES))
1021                 init_rte_ring_dev();
1022         init_rte_dev(prox_cfg.flags & DSF_USE_DUMMY_DEVICES);
1023         plog_info("=== Calibrating TSC overhead ===\n");
1024         clock_init();
1025         plog_info("\tTSC running at %"PRIu64" Hz\n", rte_get_tsc_hz());
1026
1027         init_lcores();
1028         plog_info("=== Initializing ports ===\n");
1029         init_port_all();
1030
1031         setup_all_task_structs_early_init();
1032         plog_info("=== Initializing tasks ===\n");
1033         setup_all_task_structs();
1034
1035         if (prox_cfg.logbuf_size) {
1036                 prox_cfg.logbuf = prox_zmalloc(prox_cfg.logbuf_size, rte_socket_id());
1037                 PROX_PANIC(prox_cfg.logbuf == NULL, "Failed to allocate memory for logbuf with size = %d\n", prox_cfg.logbuf_size);
1038         }
1039
1040         if (prox_cfg.flags & DSF_CHECK_INIT) {
1041                 plog_info("=== Initialization sequence completed ===\n\n");
1042                 exit(EXIT_SUCCESS);
1043         }
1044
1045         /* Current way that works to disable DPDK logging */
1046         FILE *f = fopen("/dev/null", "r");
1047         rte_openlog_stream(f);
1048         plog_info("=== PROX started ===\n");
1049         return 0;
1050 }
1051
1052 static int success = 0;
1053 static void siguser_handler(int signal)
1054 {
1055         if (signal == SIGUSR1)
1056                 success = 1;
1057         else
1058                 success = 0;
1059 }
1060
1061 static void sigabrt_handler(__attribute__((unused)) int signum)
1062 {
1063         /* restore default disposition for SIGABRT and SIGPIPE */
1064         signal(SIGABRT, SIG_DFL);
1065         signal(SIGPIPE, SIG_DFL);
1066
1067         /* ignore further Ctrl-C */
1068         signal(SIGINT, SIG_IGN);
1069
1070         /* more drastic exit on tedious termination signal */
1071         plog_info("Aborting...\n");
1072         if (lcore_cfg != NULL) {
1073                 uint32_t lcore_id;
1074                 pthread_t thread_id, tid0, tid = pthread_self();
1075                 memset(&tid0, 0, sizeof(tid0));
1076
1077                 /* cancel all threads except current one */
1078                 lcore_id = -1;
1079                 while (prox_core_next(&lcore_id, 1) == 0) {
1080                         thread_id = lcore_cfg[lcore_id].thread_id;
1081                         if (pthread_equal(thread_id, tid0))
1082                                 continue;
1083                         if (pthread_equal(thread_id, tid))
1084                                 continue;
1085                         pthread_cancel(thread_id);
1086                 }
1087
1088                 /* wait for cancelled threads to terminate */
1089                 lcore_id = -1;
1090                 while (prox_core_next(&lcore_id, 1) == 0) {
1091                         thread_id = lcore_cfg[lcore_id].thread_id;
1092                         if (pthread_equal(thread_id, tid0))
1093                                 continue;
1094                         if (pthread_equal(thread_id, tid))
1095                                 continue;
1096                         pthread_join(thread_id, NULL);
1097                 }
1098         }
1099
1100         /* close ncurses */
1101         display_end();
1102
1103         /* close ports on termination signal */
1104         close_ports_atexit();
1105
1106         /* terminate now */
1107         abort();
1108 }
1109
1110 static void sigterm_handler(int signum)
1111 {
1112         /* abort on second Ctrl-C */
1113         if (signum == SIGINT)
1114                 signal(SIGINT, sigabrt_handler);
1115
1116         /* gracefully quit on harmless termination signal */
1117         /* ports will subsequently get closed at resulting exit */
1118         quit();
1119 }
1120
1121 static void set_term_env(void)
1122 {
1123         static const char var[] = "TERM";
1124         static char str[] = "TERM=putty";
1125         char *old_value, *new_value;
1126         int max_ver = 0, min_ver = 0, n;
1127
1128         old_value = getenv(var);
1129
1130         const char *ncurses_version = curses_version();
1131         n = sscanf(ncurses_version, "ncurses %d.%d", &max_ver, &min_ver);
1132         if (n != 2) {
1133                 plog_info("\tUnable to extract ncurses version from %s. TERM left unchanged to %s\n", ncurses_version, old_value);
1134                 return;
1135         } else {
1136                 plog_info("\tncurses version = %d.%d (%s)\n", max_ver, min_ver, ncurses_version);
1137         }
1138
1139         if (((max_ver > 6) || ((max_ver == 6) && (min_ver >= 1))) && (strcmp(old_value, "xterm") == 0)) {
1140                 // On recent OSes such as RHEL 8.0, ncurses(6.1)  introduced support
1141                 // for ECMA-48 repeat character control.
1142                 // Some terminal emulators use TERM=xterm but do not support this feature.
1143                 // In this case, printing repeating character such as "22000000 Hz" might
1144                 // display as 220 Hz.
1145                 // Other emulattors, such as tmux, use TERM=screen, and do not exhibit the issue.
1146                 plog_info("\tChanged TERM from %s ", old_value);
1147                 putenv(str);
1148                 new_value = getenv(var);
1149                 plog_info("to %s\n", new_value);
1150         } else {
1151                 plog_info("\tTERM left unchanged to %s\n", old_value);
1152         }
1153 }
1154
1155 int main(int argc, char **argv)
1156 {
1157         /* set en_US locale to print big numbers with ',' */
1158         setlocale(LC_NUMERIC, "en_US.utf-8");
1159
1160         if (prox_parse_args(argc, argv) != 0){
1161                 prox_usage(argv[0]);
1162         }
1163         plog_init(prox_cfg.log_name, prox_cfg.log_name_pid);
1164         plog_info("=== " PROGRAM_NAME " %s ===\n", VERSION_STR());
1165         plog_info("\tUsing DPDK %s\n", rte_version() + sizeof(RTE_VER_PREFIX));
1166         set_term_env();
1167         read_rdt_info();
1168
1169         if (prox_cfg.flags & DSF_LIST_TASK_MODES) {
1170                 /* list supported task modes and exit */
1171                 tasks_list();
1172                 return EXIT_SUCCESS;
1173         }
1174
1175         /* close ports at normal exit */
1176         atexit(close_ports_atexit);
1177         /* gracefully quit on harmless termination signals */
1178         signal(SIGHUP, sigterm_handler);
1179         signal(SIGINT, sigterm_handler);
1180         signal(SIGQUIT, sigterm_handler);
1181         signal(SIGTERM, sigterm_handler);
1182         signal(SIGUSR1, sigterm_handler);
1183         signal(SIGUSR2, sigterm_handler);
1184         /* more drastic exit on tedious termination signals */
1185         signal(SIGABRT, sigabrt_handler);
1186         signal(SIGPIPE, sigabrt_handler);
1187
1188         if (prox_cfg.flags & DSF_DAEMON) {
1189                 signal(SIGUSR1, siguser_handler);
1190                 signal(SIGUSR2, siguser_handler);
1191                 plog_info("=== Running in Daemon mode ===\n");
1192                 plog_info("\tForking child and waiting for setup completion\n");
1193
1194                 pid_t ppid = getpid();
1195                 pid_t pid = fork();
1196                 if (pid < 0) {
1197                         plog_err("Failed to fork process to run in daemon mode\n");
1198                         return EXIT_FAILURE;
1199                 }
1200
1201                 if (pid == 0) {
1202                         fclose(stdin);
1203                         fclose(stdout);
1204                         fclose(stderr);
1205                         if (setsid() < 0) {
1206                                 kill(ppid, SIGUSR2);
1207                                 return EXIT_FAILURE;
1208                         }
1209                         if (setup_prox(argc, argv) != 0) {
1210                                 kill(ppid, SIGUSR2);
1211                                 return EXIT_FAILURE;
1212                         }
1213                         else {
1214                                 kill(ppid, SIGUSR1);
1215                                 run(prox_cfg.flags);
1216                                 return EXIT_SUCCESS;
1217                         }
1218                 }
1219                 else {
1220                         /* Before exiting the parent, wait until the
1221                            child process has finished setting up */
1222                         pause();
1223                         if (prox_cfg.logbuf) {
1224                                 file_print(prox_cfg.logbuf);
1225                         }
1226                         return success? EXIT_SUCCESS : EXIT_FAILURE;
1227                 }
1228         }
1229
1230         if (setup_prox(argc, argv) != 0)
1231                 return EXIT_FAILURE;
1232         run(prox_cfg.flags);
1233         return EXIT_SUCCESS;
1234 }