app/testpmd: support multiple raw encap/decap
[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 int
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         int ret;
173
174         memset(&link_params, 0, sizeof(link_params));
175
176         ret = rte_eth_link_get(port_id, &link_params);
177         if (ret < 0) {
178                 printf("Error during getting device (port %u) link info: %s\n",
179                         port_id, rte_strerror(-ret));
180                 return ret;
181         }
182         tm_port_rate = (uint64_t)ETH_SPEED_NUM_10G * BYTES_IN_MBPS;
183
184         /* Set tm hierarchy shapers rate */
185         h->root_node_shaper_rate = tm_port_rate;
186         h->subport_node_shaper_rate =
187                 tm_port_rate / SUBPORT_NODES_PER_PORT;
188         h->pipe_node_shaper_rate
189                 = h->subport_node_shaper_rate / PIPE_NODES_PER_SUBPORT;
190         h->tc_node_shaper_rate = h->pipe_node_shaper_rate;
191         h->tc_node_shared_shaper_rate = h->subport_node_shaper_rate;
192
193         return 0;
194 }
195
196 static int
197 softport_tm_root_node_add(portid_t port_id, struct tm_hierarchy *h,
198         struct rte_tm_error *error)
199 {
200         struct rte_tm_node_params rnp;
201         struct rte_tm_shaper_params rsp;
202         uint32_t priority, weight, level_id, shaper_profile_id;
203
204         memset(&rsp, 0, sizeof(struct rte_tm_shaper_params));
205         memset(&rnp, 0, sizeof(struct rte_tm_node_params));
206
207         /* Shaper profile Parameters */
208         rsp.peak.rate = h->root_node_shaper_rate;
209         rsp.peak.size = TOKEN_BUCKET_SIZE;
210         rsp.pkt_length_adjust = RTE_TM_ETH_FRAMING_OVERHEAD_FCS;
211         shaper_profile_id = 0;
212
213         if (rte_tm_shaper_profile_add(port_id, shaper_profile_id,
214                 &rsp, error)) {
215                 printf("%s ERROR(%d)-%s!(shaper_id %u)\n ",
216                         __func__, error->type, error->message,
217                         shaper_profile_id);
218                 return -1;
219         }
220
221         /* Root Node Parameters */
222         h->root_node_id = ROOT_NODE_ID;
223         weight = 1;
224         priority = 0;
225         level_id = TM_NODE_LEVEL_PORT;
226         rnp.shaper_profile_id = shaper_profile_id;
227         rnp.nonleaf.n_sp_priorities = 1;
228         rnp.stats_mask = STATS_MASK_DEFAULT;
229
230         /* Add Node to TM Hierarchy */
231         if (rte_tm_node_add(port_id, h->root_node_id, RTE_TM_NODE_ID_NULL,
232                 priority, weight, level_id, &rnp, error)) {
233                 printf("%s ERROR(%d)-%s!(node_id %u, parent_id %u, level %u)\n",
234                         __func__, error->type, error->message,
235                         h->root_node_id, RTE_TM_NODE_ID_NULL,
236                         level_id);
237                 return -1;
238         }
239         /* Update */
240         h->n_shapers++;
241
242         printf("  Root node added (Start id %u, Count %u, level %u)\n",
243                 h->root_node_id, 1, level_id);
244
245         return 0;
246 }
247
248 static int
249 softport_tm_subport_node_add(portid_t port_id,
250         struct tm_hierarchy *h,
251         struct rte_tm_error *error)
252 {
253         uint32_t subport_parent_node_id, subport_node_id = 0;
254         struct rte_tm_node_params snp;
255         struct rte_tm_shaper_params ssp;
256         uint32_t priority, weight, level_id, shaper_profile_id;
257         uint32_t i;
258
259         memset(&ssp, 0, sizeof(struct rte_tm_shaper_params));
260         memset(&snp, 0, sizeof(struct rte_tm_node_params));
261
262         shaper_profile_id = h->n_shapers;
263
264         /* Add Shaper Profile to TM Hierarchy */
265         for (i = 0; i < SUBPORT_NODES_PER_PORT; i++) {
266                 ssp.peak.rate = h->subport_node_shaper_rate;
267                 ssp.peak.size = TOKEN_BUCKET_SIZE;
268                 ssp.pkt_length_adjust = RTE_TM_ETH_FRAMING_OVERHEAD_FCS;
269
270                 if (rte_tm_shaper_profile_add(port_id, shaper_profile_id,
271                         &ssp, error)) {
272                         printf("%s ERROR(%d)-%s!(shaper_id %u)\n ",
273                                 __func__, error->type, error->message,
274                                 shaper_profile_id);
275                         return -1;
276                 }
277
278                 /* Node Parameters */
279                 h->subport_node_id[i] = SUBPORT_NODES_START_ID + i;
280                 subport_parent_node_id = h->root_node_id;
281                 weight = 1;
282                 priority = 0;
283                 level_id = TM_NODE_LEVEL_SUBPORT;
284                 snp.shaper_profile_id = shaper_profile_id;
285                 snp.nonleaf.n_sp_priorities = 1;
286                 snp.stats_mask = STATS_MASK_DEFAULT;
287
288                 /* Add Node to TM Hiearchy */
289                 if (rte_tm_node_add(port_id,
290                                 h->subport_node_id[i],
291                                 subport_parent_node_id,
292                                 priority, weight,
293                                 level_id,
294                                 &snp,
295                                 error)) {
296                         printf("%s ERROR(%d)-%s!(node %u,parent %u,level %u)\n",
297                                         __func__,
298                                         error->type,
299                                         error->message,
300                                         h->subport_node_id[i],
301                                         subport_parent_node_id,
302                                         level_id);
303                         return -1;
304                 }
305                 shaper_profile_id++;
306                 subport_node_id++;
307         }
308         /* Update */
309         h->n_shapers = shaper_profile_id;
310
311         printf("  Subport nodes added (Start id %u, Count %u, level %u)\n",
312                 h->subport_node_id[0], SUBPORT_NODES_PER_PORT, level_id);
313
314         return 0;
315 }
316
317 static int
318 softport_tm_pipe_node_add(portid_t port_id,
319         struct tm_hierarchy *h,
320         struct rte_tm_error *error)
321 {
322         uint32_t pipe_parent_node_id;
323         struct rte_tm_node_params pnp;
324         struct rte_tm_shaper_params psp;
325         uint32_t priority, weight, level_id, shaper_profile_id;
326         uint32_t i, j;
327
328         memset(&psp, 0, sizeof(struct rte_tm_shaper_params));
329         memset(&pnp, 0, sizeof(struct rte_tm_node_params));
330
331         shaper_profile_id = h->n_shapers;
332
333         /* Shaper Profile Parameters */
334         psp.peak.rate = h->pipe_node_shaper_rate;
335         psp.peak.size = TOKEN_BUCKET_SIZE;
336         psp.pkt_length_adjust = RTE_TM_ETH_FRAMING_OVERHEAD_FCS;
337
338         /* Pipe Node Parameters */
339         weight = 1;
340         priority = 0;
341         level_id = TM_NODE_LEVEL_PIPE;
342         pnp.nonleaf.n_sp_priorities = 4;
343         pnp.stats_mask = STATS_MASK_DEFAULT;
344
345         /* Add Shaper Profiles and Nodes to TM Hierarchy */
346         for (i = 0; i < SUBPORT_NODES_PER_PORT; i++) {
347                 for (j = 0; j < PIPE_NODES_PER_SUBPORT; j++) {
348                         if (rte_tm_shaper_profile_add(port_id,
349                                 shaper_profile_id, &psp, error)) {
350                                 printf("%s ERROR(%d)-%s!(shaper_id %u)\n ",
351                                         __func__, error->type, error->message,
352                                         shaper_profile_id);
353                                 return -1;
354                         }
355                         pnp.shaper_profile_id = shaper_profile_id;
356                         pipe_parent_node_id = h->subport_node_id[i];
357                         h->pipe_node_id[i][j] = PIPE_NODES_START_ID +
358                                 (i * PIPE_NODES_PER_SUBPORT) + j;
359
360                         if (rte_tm_node_add(port_id,
361                                         h->pipe_node_id[i][j],
362                                         pipe_parent_node_id,
363                                         priority, weight, level_id,
364                                         &pnp,
365                                         error)) {
366                                 printf("%s ERROR(%d)-%s!(node %u,parent %u )\n",
367                                         __func__,
368                                         error->type,
369                                         error->message,
370                                         h->pipe_node_id[i][j],
371                                         pipe_parent_node_id);
372
373                                 return -1;
374                         }
375                         shaper_profile_id++;
376                 }
377         }
378         /* Update */
379         h->n_shapers = shaper_profile_id;
380
381         printf("  Pipe nodes added (Start id %u, Count %u, level %u)\n",
382                 h->pipe_node_id[0][0], NUM_PIPE_NODES, level_id);
383
384         return 0;
385 }
386
387 static int
388 softport_tm_tc_node_add(portid_t port_id,
389         struct tm_hierarchy *h,
390         struct rte_tm_error *error)
391 {
392         uint32_t tc_parent_node_id;
393         struct rte_tm_node_params tnp;
394         struct rte_tm_shaper_params tsp, tssp;
395         uint32_t shared_shaper_profile_id[TC_NODES_PER_PIPE];
396         uint32_t priority, weight, level_id, shaper_profile_id;
397         uint32_t pos, n_tc_nodes, i, j, k;
398
399         memset(&tsp, 0, sizeof(struct rte_tm_shaper_params));
400         memset(&tssp, 0, sizeof(struct rte_tm_shaper_params));
401         memset(&tnp, 0, sizeof(struct rte_tm_node_params));
402
403         shaper_profile_id = h->n_shapers;
404
405         /* Private Shaper Profile (TC) Parameters */
406         tsp.peak.rate = h->tc_node_shaper_rate;
407         tsp.peak.size = TOKEN_BUCKET_SIZE;
408         tsp.pkt_length_adjust = RTE_TM_ETH_FRAMING_OVERHEAD_FCS;
409
410         /* Shared Shaper Profile (TC) Parameters */
411         tssp.peak.rate = h->tc_node_shared_shaper_rate;
412         tssp.peak.size = TOKEN_BUCKET_SIZE;
413         tssp.pkt_length_adjust = RTE_TM_ETH_FRAMING_OVERHEAD_FCS;
414
415         /* TC Node Parameters */
416         weight = 1;
417         level_id = TM_NODE_LEVEL_TC;
418         tnp.n_shared_shapers = 1;
419         tnp.nonleaf.n_sp_priorities = 1;
420         tnp.stats_mask = STATS_MASK_DEFAULT;
421
422         /* Add Shared Shaper Profiles to TM Hierarchy */
423         for (i = 0; i < TC_NODES_PER_PIPE; i++) {
424                 shared_shaper_profile_id[i] = shaper_profile_id;
425
426                 if (rte_tm_shaper_profile_add(port_id,
427                         shared_shaper_profile_id[i], &tssp, error)) {
428                         printf("%s ERROR(%d)-%s!(Shared shaper profileid %u)\n",
429                                 __func__, error->type, error->message,
430                                 shared_shaper_profile_id[i]);
431
432                         return -1;
433                 }
434                 if (rte_tm_shared_shaper_add_update(port_id,  i,
435                         shared_shaper_profile_id[i], error)) {
436                         printf("%s ERROR(%d)-%s!(Shared shaper id %u)\n",
437                                 __func__, error->type, error->message, i);
438
439                         return -1;
440                 }
441                 shaper_profile_id++;
442         }
443
444         /* Add Shaper Profiles and Nodes to TM Hierarchy */
445         n_tc_nodes = 0;
446         for (i = 0; i < SUBPORT_NODES_PER_PORT; i++) {
447                 for (j = 0; j < PIPE_NODES_PER_SUBPORT; j++) {
448                         for (k = 0; k < TC_NODES_PER_PIPE ; k++) {
449                                 priority = k;
450                                 tc_parent_node_id = h->pipe_node_id[i][j];
451                                 tnp.shared_shaper_id =
452                                         (uint32_t *)calloc(1, sizeof(uint32_t));
453                                 if (tnp.shared_shaper_id == NULL) {
454                                         printf("Shared shaper mem alloc err\n");
455                                         return -1;
456                                 }
457                                 tnp.shared_shaper_id[0] = k;
458                                 pos = j + (i * PIPE_NODES_PER_SUBPORT);
459                                 h->tc_node_id[pos][k] =
460                                         TC_NODES_START_ID + n_tc_nodes;
461
462                                 if (rte_tm_shaper_profile_add(port_id,
463                                         shaper_profile_id, &tsp, error)) {
464                                         printf("%s ERROR(%d)-%s!(shaper %u)\n",
465                                                 __func__, error->type,
466                                                 error->message,
467                                                 shaper_profile_id);
468
469                                         free(tnp.shared_shaper_id);
470                                         return -1;
471                                 }
472                                 tnp.shaper_profile_id = shaper_profile_id;
473                                 if (rte_tm_node_add(port_id,
474                                                 h->tc_node_id[pos][k],
475                                                 tc_parent_node_id,
476                                                 priority, weight,
477                                                 level_id,
478                                                 &tnp, error)) {
479                                         printf("%s ERROR(%d)-%s!(node id %u)\n",
480                                                 __func__,
481                                                 error->type,
482                                                 error->message,
483                                                 h->tc_node_id[pos][k]);
484
485                                         free(tnp.shared_shaper_id);
486                                         return -1;
487                                 }
488                                 shaper_profile_id++;
489                                 n_tc_nodes++;
490                         }
491                 }
492         }
493         /* Update */
494         h->n_shapers = shaper_profile_id;
495
496         printf("  TC nodes added (Start id %u, Count %u, level %u)\n",
497                 h->tc_node_id[0][0], n_tc_nodes, level_id);
498
499         return 0;
500 }
501
502 static int
503 softport_tm_queue_node_add(portid_t port_id, struct tm_hierarchy *h,
504         struct rte_tm_error *error)
505 {
506         uint32_t queue_parent_node_id;
507         struct rte_tm_node_params qnp;
508         uint32_t priority, weight, level_id, pos;
509         uint32_t n_queue_nodes, i, j, k;
510
511         memset(&qnp, 0, sizeof(struct rte_tm_node_params));
512
513         /* Queue Node Parameters */
514         priority = 0;
515         weight = 1;
516         level_id = TM_NODE_LEVEL_QUEUE;
517         qnp.shaper_profile_id = RTE_TM_SHAPER_PROFILE_ID_NONE;
518         qnp.leaf.cman = RTE_TM_CMAN_TAIL_DROP;
519         qnp.stats_mask = STATS_MASK_QUEUE;
520
521         /* Add Queue Nodes to TM Hierarchy */
522         n_queue_nodes = 0;
523         for (i = 0; i < NUM_PIPE_NODES; i++) {
524                 for (j = 0; j < TC_NODES_PER_PIPE; j++) {
525                         queue_parent_node_id = h->tc_node_id[i][j];
526                         for (k = 0; k < QUEUE_NODES_PER_TC; k++) {
527                                 pos = j + (i * TC_NODES_PER_PIPE);
528                                 h->queue_node_id[pos][k] = n_queue_nodes;
529                                 if (rte_tm_node_add(port_id,
530                                                 h->queue_node_id[pos][k],
531                                                 queue_parent_node_id,
532                                                 priority,
533                                                 weight,
534                                                 level_id,
535                                                 &qnp, error)) {
536                                         printf("%s ERROR(%d)-%s!(node %u)\n",
537                                                 __func__,
538                                                 error->type,
539                                                 error->message,
540                                                 h->queue_node_id[pos][k]);
541
542                                         return -1;
543                                 }
544                                 n_queue_nodes++;
545                         }
546                 }
547         }
548         printf("  Queue nodes added (Start id %u, Count %u, level %u)\n",
549                 h->queue_node_id[0][0], n_queue_nodes, level_id);
550
551         return 0;
552 }
553
554 static int
555 softport_tm_hierarchy_specify(portid_t port_id,
556         struct rte_tm_error *error)
557 {
558
559         struct tm_hierarchy h;
560         int status;
561
562         memset(&h, 0, sizeof(struct tm_hierarchy));
563
564         /* TM hierarchy shapers rate */
565         status = set_tm_hiearchy_nodes_shaper_rate(port_id, &h);
566         if (status)
567                 return status;
568
569         /* Add root node (level 0) */
570         status = softport_tm_root_node_add(port_id, &h, error);
571         if (status)
572                 return status;
573
574         /* Add subport node (level 1) */
575         status = softport_tm_subport_node_add(port_id, &h, error);
576         if (status)
577                 return status;
578
579         /* Add pipe nodes (level 2) */
580         status = softport_tm_pipe_node_add(port_id, &h, error);
581         if (status)
582                 return status;
583
584         /* Add traffic class nodes (level 3) */
585         status = softport_tm_tc_node_add(port_id, &h, error);
586         if (status)
587                 return status;
588
589         /* Add queue nodes (level 4) */
590         status = softport_tm_queue_node_add(port_id, &h, error);
591         if (status)
592                 return status;
593
594         return 0;
595 }
596
597 /*
598  * Softnic TM default configuration
599  */
600 static void
601 softnic_tm_default_config(portid_t pi)
602 {
603         struct rte_port *port = &ports[pi];
604         struct rte_tm_error error;
605         int status;
606
607         /* Stop port */
608         rte_eth_dev_stop(pi);
609
610         /* TM hierarchy specification */
611         status = softport_tm_hierarchy_specify(pi, &error);
612         if (status) {
613                 printf("  TM Hierarchy built error(%d) - %s\n",
614                         error.type, error.message);
615                 return;
616         }
617         printf("\n  TM Hierarchy Specified!\n");
618
619         /* TM hierarchy commit */
620         status = rte_tm_hierarchy_commit(pi, 0, &error);
621         if (status) {
622                 printf("  Hierarchy commit error(%d) - %s\n",
623                         error.type, error.message);
624                 return;
625         }
626         printf("  Hierarchy Committed (port %u)!\n", pi);
627
628         /* Start port */
629         status = rte_eth_dev_start(pi);
630         if (status) {
631                 printf("\n  Port %u start error!\n", pi);
632                 return;
633         }
634
635         /* Reset the default hierarchy flag */
636         port->softport.default_tm_hierarchy_enable = 0;
637 }
638
639 /*
640  * Softnic forwarding init
641  */
642 static void
643 softnic_fwd_begin(portid_t pi)
644 {
645         struct rte_port *port = &ports[pi];
646         uint32_t lcore, fwd_core_present = 0, softnic_run_launch = 0;
647         int     status;
648
649         softnic_fwd_lcore = port->softport.fwd_lcore_arg[0];
650         softnic_port_id = pi;
651
652         /* Launch softnic_run function on lcores */
653         for (lcore = 0; lcore < RTE_MAX_LCORE; lcore++) {
654                 if (!rte_lcore_is_enabled(lcore))
655                         continue;
656
657                 if (lcore == rte_get_master_lcore())
658                         continue;
659
660                 if (fwd_core_present == 0) {
661                         fwd_core_present++;
662                         continue;
663                 }
664
665                 status = rte_eal_remote_launch(softnic_begin, NULL, lcore);
666                 if (status)
667                         printf("softnic launch on lcore %u failed (%d)\n",
668                                        lcore, status);
669
670                 softnic_run_launch = 1;
671         }
672
673         if (!softnic_run_launch)
674                 softnic_fwd_engine.packet_fwd = softnic_fwd_run;
675
676         /* Softnic TM default configuration */
677         if (port->softport.default_tm_hierarchy_enable == 1)
678                 softnic_tm_default_config(pi);
679 }
680
681 struct fwd_engine softnic_fwd_engine = {
682         .fwd_mode_name  = "softnic",
683         .port_fwd_begin = softnic_fwd_begin,
684         .port_fwd_end   = NULL,
685         .packet_fwd     = softnic_fwd,
686 };