New upstream version 18.08
[deb_dpdk.git] / app / test-pmd / softnicfwd.c
1 /* SPDX-License-Identifier: BSD-3-Clause
2  * Copyright(c) 2017 Intel Corporation
3  */
4 #include <stdio.h>
5 #include <sys/stat.h>
6
7 #include <rte_cycles.h>
8 #include <rte_mbuf.h>
9 #include <rte_malloc.h>
10 #include <rte_ethdev.h>
11 #include <rte_flow.h>
12 #include <rte_meter.h>
13 #include <rte_eth_softnic.h>
14 #include <rte_tm.h>
15
16 #include "testpmd.h"
17
18 #define SUBPORT_NODES_PER_PORT          1
19 #define PIPE_NODES_PER_SUBPORT          4096
20 #define TC_NODES_PER_PIPE                       4
21 #define QUEUE_NODES_PER_TC                      4
22
23 #define NUM_PIPE_NODES                                          \
24         (SUBPORT_NODES_PER_PORT * PIPE_NODES_PER_SUBPORT)
25
26 #define NUM_TC_NODES                                            \
27         (NUM_PIPE_NODES * TC_NODES_PER_PIPE)
28
29 #define ROOT_NODE_ID                            1000000
30 #define SUBPORT_NODES_START_ID          900000
31 #define PIPE_NODES_START_ID                     800000
32 #define TC_NODES_START_ID                       700000
33
34 #define STATS_MASK_DEFAULT                                      \
35         (RTE_TM_STATS_N_PKTS |                                  \
36         RTE_TM_STATS_N_BYTES |                                  \
37         RTE_TM_STATS_N_PKTS_GREEN_DROPPED |                     \
38         RTE_TM_STATS_N_BYTES_GREEN_DROPPED)
39
40 #define STATS_MASK_QUEUE                                        \
41         (STATS_MASK_DEFAULT |                                   \
42         RTE_TM_STATS_N_PKTS_QUEUED)
43
44 #define BYTES_IN_MBPS                           (1000 * 1000 / 8)
45 #define TOKEN_BUCKET_SIZE                       1000000
46
47 /* TM Hierarchy Levels */
48 enum tm_hierarchy_level {
49         TM_NODE_LEVEL_PORT = 0,
50         TM_NODE_LEVEL_SUBPORT,
51         TM_NODE_LEVEL_PIPE,
52         TM_NODE_LEVEL_TC,
53         TM_NODE_LEVEL_QUEUE,
54         TM_NODE_LEVEL_MAX,
55 };
56
57 struct tm_hierarchy {
58         /* TM Nodes */
59         uint32_t root_node_id;
60         uint32_t subport_node_id[SUBPORT_NODES_PER_PORT];
61         uint32_t pipe_node_id[SUBPORT_NODES_PER_PORT][PIPE_NODES_PER_SUBPORT];
62         uint32_t tc_node_id[NUM_PIPE_NODES][TC_NODES_PER_PIPE];
63         uint32_t queue_node_id[NUM_TC_NODES][QUEUE_NODES_PER_TC];
64
65         /* TM Hierarchy Nodes Shaper Rates */
66         uint32_t root_node_shaper_rate;
67         uint32_t subport_node_shaper_rate;
68         uint32_t pipe_node_shaper_rate;
69         uint32_t tc_node_shaper_rate;
70         uint32_t tc_node_shared_shaper_rate;
71
72         uint32_t n_shapers;
73 };
74
75 static struct fwd_lcore *softnic_fwd_lcore;
76 static uint16_t softnic_port_id;
77 struct fwd_engine softnic_fwd_engine;
78
79 /*
80  * Softnic packet forward
81  */
82 static void
83 softnic_fwd(struct fwd_stream *fs)
84 {
85         struct rte_mbuf *pkts_burst[MAX_PKT_BURST];
86         uint16_t nb_rx;
87         uint16_t nb_tx;
88         uint32_t retry;
89
90 #ifdef RTE_TEST_PMD_RECORD_CORE_CYCLES
91         uint64_t start_tsc;
92         uint64_t end_tsc;
93         uint64_t core_cycles;
94 #endif
95
96 #ifdef RTE_TEST_PMD_RECORD_CORE_CYCLES
97         start_tsc = rte_rdtsc();
98 #endif
99
100         /*  Packets Receive */
101         nb_rx = rte_eth_rx_burst(fs->rx_port, fs->rx_queue,
102                         pkts_burst, nb_pkt_per_burst);
103         fs->rx_packets += nb_rx;
104
105 #ifdef RTE_TEST_PMD_RECORD_BURST_STATS
106         fs->rx_burst_stats.pkt_burst_spread[nb_rx]++;
107 #endif
108
109         nb_tx = rte_eth_tx_burst(fs->tx_port, fs->tx_queue,
110                         pkts_burst, nb_rx);
111
112         /* Retry if necessary */
113         if (unlikely(nb_tx < nb_rx) && fs->retry_enabled) {
114                 retry = 0;
115                 while (nb_tx < nb_rx && retry++ < burst_tx_retry_num) {
116                         rte_delay_us(burst_tx_delay_time);
117                         nb_tx += rte_eth_tx_burst(fs->tx_port, fs->tx_queue,
118                                         &pkts_burst[nb_tx], nb_rx - nb_tx);
119                 }
120         }
121         fs->tx_packets += nb_tx;
122
123 #ifdef RTE_TEST_PMD_RECORD_BURST_STATS
124         fs->tx_burst_stats.pkt_burst_spread[nb_tx]++;
125 #endif
126
127         if (unlikely(nb_tx < nb_rx)) {
128                 fs->fwd_dropped += (nb_rx - nb_tx);
129                 do {
130                         rte_pktmbuf_free(pkts_burst[nb_tx]);
131                 } while (++nb_tx < nb_rx);
132         }
133 #ifdef RTE_TEST_PMD_RECORD_CORE_CYCLES
134         end_tsc = rte_rdtsc();
135         core_cycles = (end_tsc - start_tsc);
136         fs->core_cycles = (uint64_t) (fs->core_cycles + core_cycles);
137 #endif
138 }
139
140 static void
141 softnic_fwd_run(struct fwd_stream *fs)
142 {
143         rte_pmd_softnic_run(softnic_port_id);
144         softnic_fwd(fs);
145 }
146
147 /**
148  * Softnic init
149  */
150 static int
151 softnic_begin(void *arg __rte_unused)
152 {
153         for (;;) {
154                 if (!softnic_fwd_lcore->stopped)
155                         break;
156         }
157
158         do {
159                 /* Run softnic */
160                 rte_pmd_softnic_run(softnic_port_id);
161         } while (!softnic_fwd_lcore->stopped);
162
163         return 0;
164 }
165
166 static void
167 set_tm_hiearchy_nodes_shaper_rate(portid_t port_id,
168         struct tm_hierarchy *h)
169 {
170         struct rte_eth_link link_params;
171         uint64_t tm_port_rate;
172
173         memset(&link_params, 0, sizeof(link_params));
174
175         rte_eth_link_get(port_id, &link_params);
176         tm_port_rate = (uint64_t)ETH_SPEED_NUM_10G * BYTES_IN_MBPS;
177
178         /* Set tm hierarchy shapers rate */
179         h->root_node_shaper_rate = tm_port_rate;
180         h->subport_node_shaper_rate =
181                 tm_port_rate / SUBPORT_NODES_PER_PORT;
182         h->pipe_node_shaper_rate
183                 = h->subport_node_shaper_rate / PIPE_NODES_PER_SUBPORT;
184         h->tc_node_shaper_rate = h->pipe_node_shaper_rate;
185         h->tc_node_shared_shaper_rate = h->subport_node_shaper_rate;
186 }
187
188 static int
189 softport_tm_root_node_add(portid_t port_id, struct tm_hierarchy *h,
190         struct rte_tm_error *error)
191 {
192         struct rte_tm_node_params rnp;
193         struct rte_tm_shaper_params rsp;
194         uint32_t priority, weight, level_id, shaper_profile_id;
195
196         memset(&rsp, 0, sizeof(struct rte_tm_shaper_params));
197         memset(&rnp, 0, sizeof(struct rte_tm_node_params));
198
199         /* Shaper profile Parameters */
200         rsp.peak.rate = h->root_node_shaper_rate;
201         rsp.peak.size = TOKEN_BUCKET_SIZE;
202         rsp.pkt_length_adjust = RTE_TM_ETH_FRAMING_OVERHEAD_FCS;
203         shaper_profile_id = 0;
204
205         if (rte_tm_shaper_profile_add(port_id, shaper_profile_id,
206                 &rsp, error)) {
207                 printf("%s ERROR(%d)-%s!(shaper_id %u)\n ",
208                         __func__, error->type, error->message,
209                         shaper_profile_id);
210                 return -1;
211         }
212
213         /* Root Node Parameters */
214         h->root_node_id = ROOT_NODE_ID;
215         weight = 1;
216         priority = 0;
217         level_id = TM_NODE_LEVEL_PORT;
218         rnp.shaper_profile_id = shaper_profile_id;
219         rnp.nonleaf.n_sp_priorities = 1;
220         rnp.stats_mask = STATS_MASK_DEFAULT;
221
222         /* Add Node to TM Hierarchy */
223         if (rte_tm_node_add(port_id, h->root_node_id, RTE_TM_NODE_ID_NULL,
224                 priority, weight, level_id, &rnp, error)) {
225                 printf("%s ERROR(%d)-%s!(node_id %u, parent_id %u, level %u)\n",
226                         __func__, error->type, error->message,
227                         h->root_node_id, RTE_TM_NODE_ID_NULL,
228                         level_id);
229                 return -1;
230         }
231         /* Update */
232         h->n_shapers++;
233
234         printf("  Root node added (Start id %u, Count %u, level %u)\n",
235                 h->root_node_id, 1, level_id);
236
237         return 0;
238 }
239
240 static int
241 softport_tm_subport_node_add(portid_t port_id,
242         struct tm_hierarchy *h,
243         struct rte_tm_error *error)
244 {
245         uint32_t subport_parent_node_id, subport_node_id = 0;
246         struct rte_tm_node_params snp;
247         struct rte_tm_shaper_params ssp;
248         uint32_t priority, weight, level_id, shaper_profile_id;
249         uint32_t i;
250
251         memset(&ssp, 0, sizeof(struct rte_tm_shaper_params));
252         memset(&snp, 0, sizeof(struct rte_tm_node_params));
253
254         shaper_profile_id = h->n_shapers;
255
256         /* Add Shaper Profile to TM Hierarchy */
257         for (i = 0; i < SUBPORT_NODES_PER_PORT; i++) {
258                 ssp.peak.rate = h->subport_node_shaper_rate;
259                 ssp.peak.size = TOKEN_BUCKET_SIZE;
260                 ssp.pkt_length_adjust = RTE_TM_ETH_FRAMING_OVERHEAD_FCS;
261
262                 if (rte_tm_shaper_profile_add(port_id, shaper_profile_id,
263                         &ssp, error)) {
264                         printf("%s ERROR(%d)-%s!(shaper_id %u)\n ",
265                                 __func__, error->type, error->message,
266                                 shaper_profile_id);
267                         return -1;
268                 }
269
270                 /* Node Parameters */
271                 h->subport_node_id[i] = SUBPORT_NODES_START_ID + i;
272                 subport_parent_node_id = h->root_node_id;
273                 weight = 1;
274                 priority = 0;
275                 level_id = TM_NODE_LEVEL_SUBPORT;
276                 snp.shaper_profile_id = shaper_profile_id;
277                 snp.nonleaf.n_sp_priorities = 1;
278                 snp.stats_mask = STATS_MASK_DEFAULT;
279
280                 /* Add Node to TM Hiearchy */
281                 if (rte_tm_node_add(port_id,
282                                 h->subport_node_id[i],
283                                 subport_parent_node_id,
284                                 priority, weight,
285                                 level_id,
286                                 &snp,
287                                 error)) {
288                         printf("%s ERROR(%d)-%s!(node %u,parent %u,level %u)\n",
289                                         __func__,
290                                         error->type,
291                                         error->message,
292                                         h->subport_node_id[i],
293                                         subport_parent_node_id,
294                                         level_id);
295                         return -1;
296                 }
297                 shaper_profile_id++;
298                 subport_node_id++;
299         }
300         /* Update */
301         h->n_shapers = shaper_profile_id;
302
303         printf("  Subport nodes added (Start id %u, Count %u, level %u)\n",
304                 h->subport_node_id[0], SUBPORT_NODES_PER_PORT, level_id);
305
306         return 0;
307 }
308
309 static int
310 softport_tm_pipe_node_add(portid_t port_id,
311         struct tm_hierarchy *h,
312         struct rte_tm_error *error)
313 {
314         uint32_t pipe_parent_node_id;
315         struct rte_tm_node_params pnp;
316         struct rte_tm_shaper_params psp;
317         uint32_t priority, weight, level_id, shaper_profile_id;
318         uint32_t i, j;
319
320         memset(&psp, 0, sizeof(struct rte_tm_shaper_params));
321         memset(&pnp, 0, sizeof(struct rte_tm_node_params));
322
323         shaper_profile_id = h->n_shapers;
324
325         /* Shaper Profile Parameters */
326         psp.peak.rate = h->pipe_node_shaper_rate;
327         psp.peak.size = TOKEN_BUCKET_SIZE;
328         psp.pkt_length_adjust = RTE_TM_ETH_FRAMING_OVERHEAD_FCS;
329
330         /* Pipe Node Parameters */
331         weight = 1;
332         priority = 0;
333         level_id = TM_NODE_LEVEL_PIPE;
334         pnp.nonleaf.n_sp_priorities = 4;
335         pnp.stats_mask = STATS_MASK_DEFAULT;
336
337         /* Add Shaper Profiles and Nodes to TM Hierarchy */
338         for (i = 0; i < SUBPORT_NODES_PER_PORT; i++) {
339                 for (j = 0; j < PIPE_NODES_PER_SUBPORT; j++) {
340                         if (rte_tm_shaper_profile_add(port_id,
341                                 shaper_profile_id, &psp, error)) {
342                                 printf("%s ERROR(%d)-%s!(shaper_id %u)\n ",
343                                         __func__, error->type, error->message,
344                                         shaper_profile_id);
345                                 return -1;
346                         }
347                         pnp.shaper_profile_id = shaper_profile_id;
348                         pipe_parent_node_id = h->subport_node_id[i];
349                         h->pipe_node_id[i][j] = PIPE_NODES_START_ID +
350                                 (i * PIPE_NODES_PER_SUBPORT) + j;
351
352                         if (rte_tm_node_add(port_id,
353                                         h->pipe_node_id[i][j],
354                                         pipe_parent_node_id,
355                                         priority, weight, level_id,
356                                         &pnp,
357                                         error)) {
358                                 printf("%s ERROR(%d)-%s!(node %u,parent %u )\n",
359                                         __func__,
360                                         error->type,
361                                         error->message,
362                                         h->pipe_node_id[i][j],
363                                         pipe_parent_node_id);
364
365                                 return -1;
366                         }
367                         shaper_profile_id++;
368                 }
369         }
370         /* Update */
371         h->n_shapers = shaper_profile_id;
372
373         printf("  Pipe nodes added (Start id %u, Count %u, level %u)\n",
374                 h->pipe_node_id[0][0], NUM_PIPE_NODES, level_id);
375
376         return 0;
377 }
378
379 static int
380 softport_tm_tc_node_add(portid_t port_id,
381         struct tm_hierarchy *h,
382         struct rte_tm_error *error)
383 {
384         uint32_t tc_parent_node_id;
385         struct rte_tm_node_params tnp;
386         struct rte_tm_shaper_params tsp, tssp;
387         uint32_t shared_shaper_profile_id[TC_NODES_PER_PIPE];
388         uint32_t priority, weight, level_id, shaper_profile_id;
389         uint32_t pos, n_tc_nodes, i, j, k;
390
391         memset(&tsp, 0, sizeof(struct rte_tm_shaper_params));
392         memset(&tssp, 0, sizeof(struct rte_tm_shaper_params));
393         memset(&tnp, 0, sizeof(struct rte_tm_node_params));
394
395         shaper_profile_id = h->n_shapers;
396
397         /* Private Shaper Profile (TC) Parameters */
398         tsp.peak.rate = h->tc_node_shaper_rate;
399         tsp.peak.size = TOKEN_BUCKET_SIZE;
400         tsp.pkt_length_adjust = RTE_TM_ETH_FRAMING_OVERHEAD_FCS;
401
402         /* Shared Shaper Profile (TC) Parameters */
403         tssp.peak.rate = h->tc_node_shared_shaper_rate;
404         tssp.peak.size = TOKEN_BUCKET_SIZE;
405         tssp.pkt_length_adjust = RTE_TM_ETH_FRAMING_OVERHEAD_FCS;
406
407         /* TC Node Parameters */
408         weight = 1;
409         level_id = TM_NODE_LEVEL_TC;
410         tnp.n_shared_shapers = 1;
411         tnp.nonleaf.n_sp_priorities = 1;
412         tnp.stats_mask = STATS_MASK_DEFAULT;
413
414         /* Add Shared Shaper Profiles to TM Hierarchy */
415         for (i = 0; i < TC_NODES_PER_PIPE; i++) {
416                 shared_shaper_profile_id[i] = shaper_profile_id;
417
418                 if (rte_tm_shaper_profile_add(port_id,
419                         shared_shaper_profile_id[i], &tssp, error)) {
420                         printf("%s ERROR(%d)-%s!(Shared shaper profileid %u)\n",
421                                 __func__, error->type, error->message,
422                                 shared_shaper_profile_id[i]);
423
424                         return -1;
425                 }
426                 if (rte_tm_shared_shaper_add_update(port_id,  i,
427                         shared_shaper_profile_id[i], error)) {
428                         printf("%s ERROR(%d)-%s!(Shared shaper id %u)\n",
429                                 __func__, error->type, error->message, i);
430
431                         return -1;
432                 }
433                 shaper_profile_id++;
434         }
435
436         /* Add Shaper Profiles and Nodes to TM Hierarchy */
437         n_tc_nodes = 0;
438         for (i = 0; i < SUBPORT_NODES_PER_PORT; i++) {
439                 for (j = 0; j < PIPE_NODES_PER_SUBPORT; j++) {
440                         for (k = 0; k < TC_NODES_PER_PIPE ; k++) {
441                                 priority = k;
442                                 tc_parent_node_id = h->pipe_node_id[i][j];
443                                 tnp.shared_shaper_id =
444                                         (uint32_t *)calloc(1, sizeof(uint32_t));
445                                 if (tnp.shared_shaper_id == NULL) {
446                                         printf("Shared shaper mem alloc err\n");
447                                         return -1;
448                                 }
449                                 tnp.shared_shaper_id[0] = k;
450                                 pos = j + (i * PIPE_NODES_PER_SUBPORT);
451                                 h->tc_node_id[pos][k] =
452                                         TC_NODES_START_ID + n_tc_nodes;
453
454                                 if (rte_tm_shaper_profile_add(port_id,
455                                         shaper_profile_id, &tsp, error)) {
456                                         printf("%s ERROR(%d)-%s!(shaper %u)\n",
457                                                 __func__, error->type,
458                                                 error->message,
459                                                 shaper_profile_id);
460
461                                         return -1;
462                                 }
463                                 tnp.shaper_profile_id = shaper_profile_id;
464                                 if (rte_tm_node_add(port_id,
465                                                 h->tc_node_id[pos][k],
466                                                 tc_parent_node_id,
467                                                 priority, weight,
468                                                 level_id,
469                                                 &tnp, error)) {
470                                         printf("%s ERROR(%d)-%s!(node id %u)\n",
471                                                 __func__,
472                                                 error->type,
473                                                 error->message,
474                                                 h->tc_node_id[pos][k]);
475
476                                         return -1;
477                                 }
478                                 shaper_profile_id++;
479                                 n_tc_nodes++;
480                         }
481                 }
482         }
483         /* Update */
484         h->n_shapers = shaper_profile_id;
485
486         printf("  TC nodes added (Start id %u, Count %u, level %u)\n",
487                 h->tc_node_id[0][0], n_tc_nodes, level_id);
488
489         return 0;
490 }
491
492 static int
493 softport_tm_queue_node_add(portid_t port_id, struct tm_hierarchy *h,
494         struct rte_tm_error *error)
495 {
496         uint32_t queue_parent_node_id;
497         struct rte_tm_node_params qnp;
498         uint32_t priority, weight, level_id, pos;
499         uint32_t n_queue_nodes, i, j, k;
500
501         memset(&qnp, 0, sizeof(struct rte_tm_node_params));
502
503         /* Queue Node Parameters */
504         priority = 0;
505         weight = 1;
506         level_id = TM_NODE_LEVEL_QUEUE;
507         qnp.shaper_profile_id = RTE_TM_SHAPER_PROFILE_ID_NONE;
508         qnp.leaf.cman = RTE_TM_CMAN_TAIL_DROP;
509         qnp.stats_mask = STATS_MASK_QUEUE;
510
511         /* Add Queue Nodes to TM Hierarchy */
512         n_queue_nodes = 0;
513         for (i = 0; i < NUM_PIPE_NODES; i++) {
514                 for (j = 0; j < TC_NODES_PER_PIPE; j++) {
515                         queue_parent_node_id = h->tc_node_id[i][j];
516                         for (k = 0; k < QUEUE_NODES_PER_TC; k++) {
517                                 pos = j + (i * TC_NODES_PER_PIPE);
518                                 h->queue_node_id[pos][k] = n_queue_nodes;
519                                 if (rte_tm_node_add(port_id,
520                                                 h->queue_node_id[pos][k],
521                                                 queue_parent_node_id,
522                                                 priority,
523                                                 weight,
524                                                 level_id,
525                                                 &qnp, error)) {
526                                         printf("%s ERROR(%d)-%s!(node %u)\n",
527                                                 __func__,
528                                                 error->type,
529                                                 error->message,
530                                                 h->queue_node_id[pos][k]);
531
532                                         return -1;
533                                 }
534                                 n_queue_nodes++;
535                         }
536                 }
537         }
538         printf("  Queue nodes added (Start id %u, Count %u, level %u)\n",
539                 h->queue_node_id[0][0], n_queue_nodes, level_id);
540
541         return 0;
542 }
543
544 static int
545 softport_tm_hierarchy_specify(portid_t port_id,
546         struct rte_tm_error *error)
547 {
548
549         struct tm_hierarchy h;
550         int status;
551
552         memset(&h, 0, sizeof(struct tm_hierarchy));
553
554         /* TM hierarchy shapers rate */
555         set_tm_hiearchy_nodes_shaper_rate(port_id, &h);
556
557         /* Add root node (level 0) */
558         status = softport_tm_root_node_add(port_id, &h, error);
559         if (status)
560                 return status;
561
562         /* Add subport node (level 1) */
563         status = softport_tm_subport_node_add(port_id, &h, error);
564         if (status)
565                 return status;
566
567         /* Add pipe nodes (level 2) */
568         status = softport_tm_pipe_node_add(port_id, &h, error);
569         if (status)
570                 return status;
571
572         /* Add traffic class nodes (level 3) */
573         status = softport_tm_tc_node_add(port_id, &h, error);
574         if (status)
575                 return status;
576
577         /* Add queue nodes (level 4) */
578         status = softport_tm_queue_node_add(port_id, &h, error);
579         if (status)
580                 return status;
581
582         return 0;
583 }
584
585 /*
586  * Softnic TM default configuration
587  */
588 static void
589 softnic_tm_default_config(portid_t pi)
590 {
591         struct rte_port *port = &ports[pi];
592         struct rte_tm_error error;
593         int status;
594
595         /* Stop port */
596         rte_eth_dev_stop(pi);
597
598         /* TM hierarchy specification */
599         status = softport_tm_hierarchy_specify(pi, &error);
600         if (status) {
601                 printf("  TM Hierarchy built error(%d) - %s\n",
602                         error.type, error.message);
603                 return;
604         }
605         printf("\n  TM Hierarchy Specified!\n");
606
607         /* TM hierarchy commit */
608         status = rte_tm_hierarchy_commit(pi, 0, &error);
609         if (status) {
610                 printf("  Hierarchy commit error(%d) - %s\n",
611                         error.type, error.message);
612                 return;
613         }
614         printf("  Hierarchy Committed (port %u)!\n", pi);
615
616         /* Start port */
617         status = rte_eth_dev_start(pi);
618         if (status) {
619                 printf("\n  Port %u start error!\n", pi);
620                 return;
621         }
622
623         /* Reset the default hierarchy flag */
624         port->softport.default_tm_hierarchy_enable = 0;
625 }
626
627 /*
628  * Softnic forwarding init
629  */
630 static void
631 softnic_fwd_begin(portid_t pi)
632 {
633         struct rte_port *port = &ports[pi];
634         uint32_t lcore, fwd_core_present = 0, softnic_run_launch = 0;
635         int     status;
636
637         softnic_fwd_lcore = port->softport.fwd_lcore_arg[0];
638         softnic_port_id = pi;
639
640         /* Launch softnic_run function on lcores */
641         for (lcore = 0; lcore < RTE_MAX_LCORE; lcore++) {
642                 if (!rte_lcore_is_enabled(lcore))
643                         continue;
644
645                 if (lcore == rte_get_master_lcore())
646                         continue;
647
648                 if (fwd_core_present == 0) {
649                         fwd_core_present++;
650                         continue;
651                 }
652
653                 status = rte_eal_remote_launch(softnic_begin, NULL, lcore);
654                 if (status)
655                         printf("softnic launch on lcore %u failed (%d)\n",
656                                        lcore, status);
657
658                 softnic_run_launch = 1;
659         }
660
661         if (!softnic_run_launch)
662                 softnic_fwd_engine.packet_fwd = softnic_fwd_run;
663
664         /* Softnic TM default configuration */
665         if (port->softport.default_tm_hierarchy_enable == 1)
666                 softnic_tm_default_config(pi);
667 }
668
669 struct fwd_engine softnic_fwd_engine = {
670         .fwd_mode_name  = "softnic",
671         .port_fwd_begin = softnic_fwd_begin,
672         .port_fwd_end   = NULL,
673         .packet_fwd     = softnic_fwd,
674 };