examples/pipeline: packet framework sample
[dpdk.git] / examples / ip_pipeline / config.c
1 /*-
2  *   BSD LICENSE
3  *
4  *   Copyright(c) 2010-2014 Intel Corporation. All rights reserved.
5  *   All rights reserved.
6  *
7  *   Redistribution and use in source and binary forms, with or without
8  *   modification, are permitted provided that the following conditions
9  *   are met:
10  *
11  *     * Redistributions of source code must retain the above copyright
12  *       notice, this list of conditions and the following disclaimer.
13  *     * Redistributions in binary form must reproduce the above copyright
14  *       notice, this list of conditions and the following disclaimer in
15  *       the documentation and/or other materials provided with the
16  *       distribution.
17  *     * Neither the name of Intel Corporation nor the names of its
18  *       contributors may be used to endorse or promote products derived
19  *       from this software without specific prior written permission.
20  *
21  *   THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
22  *   "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
23  *   LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
24  *   A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
25  *   OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
26  *   SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
27  *   LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
28  *   DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
29  *   THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
30  *   (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
31  *   OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
32  */
33
34 #include <stdio.h>
35 #include <stdlib.h>
36 #include <stdint.h>
37 #include <inttypes.h>
38 #include <sys/types.h>
39 #include <string.h>
40 #include <sys/queue.h>
41 #include <stdarg.h>
42 #include <errno.h>
43 #include <getopt.h>
44
45 #include <rte_common.h>
46 #include <rte_byteorder.h>
47 #include <rte_log.h>
48 #include <rte_memory.h>
49 #include <rte_memcpy.h>
50 #include <rte_memzone.h>
51 #include <rte_tailq.h>
52 #include <rte_eal.h>
53 #include <rte_per_lcore.h>
54 #include <rte_launch.h>
55 #include <rte_atomic.h>
56 #include <rte_cycles.h>
57 #include <rte_prefetch.h>
58 #include <rte_lcore.h>
59 #include <rte_per_lcore.h>
60 #include <rte_branch_prediction.h>
61 #include <rte_interrupts.h>
62 #include <rte_pci.h>
63 #include <rte_random.h>
64 #include <rte_debug.h>
65 #include <rte_ether.h>
66 #include <rte_ethdev.h>
67 #include <rte_ring.h>
68 #include <rte_mempool.h>
69 #include <rte_mbuf.h>
70 #include <rte_ip.h>
71 #include <rte_tcp.h>
72 #include <rte_lpm.h>
73 #include <rte_lpm6.h>
74 #include <rte_string_fns.h>
75 #include <rte_cfgfile.h>
76
77 #include "main.h"
78
79 struct app_params app;
80
81 static const char usage[] =
82         "Usage: %s EAL_OPTIONS-- -p PORT_MASK [-f CONFIG_FILE]\n";
83
84 void
85 app_print_usage(char *prgname)
86 {
87         printf(usage, prgname);
88 }
89
90 const char *
91 app_core_type_id_to_string(enum app_core_type id)
92 {
93         switch (id) {
94         case APP_CORE_NONE: return "NONE";
95         case APP_CORE_MASTER: return "MASTER";
96         case APP_CORE_RX: return "RX";
97         case APP_CORE_TX: return "TX";
98         case APP_CORE_PT: return "PT";
99         case APP_CORE_FC: return "FC";
100         case APP_CORE_FW: return "FW";
101         case APP_CORE_RT: return "RT";
102         case APP_CORE_TM: return "TM";
103         case APP_CORE_IPV4_FRAG: return "IPV4_FRAG";
104         case APP_CORE_IPV4_RAS: return "IPV4_RAS";
105         default: return NULL;
106         }
107 }
108
109 int
110 app_core_type_string_to_id(const char *string, enum app_core_type *id)
111 {
112         if (strcmp(string, "NONE") == 0) {
113                 *id = APP_CORE_NONE;
114                 return 0;
115         }
116         if (strcmp(string, "MASTER") == 0) {
117                 *id = APP_CORE_MASTER;
118                 return 0;
119         }
120         if (strcmp(string, "RX") == 0) {
121                 *id = APP_CORE_RX;
122                 return 0;
123         }
124         if (strcmp(string, "TX") == 0) {
125                 *id = APP_CORE_TX;
126                 return 0;
127         }
128         if (strcmp(string, "PT") == 0) {
129                 *id = APP_CORE_PT;
130                 return 0;
131         }
132         if (strcmp(string, "FC") == 0) {
133                 *id = APP_CORE_FC;
134                 return 0;
135         }
136         if (strcmp(string, "FW") == 0) {
137                 *id = APP_CORE_FW;
138                 return 0;
139         }
140         if (strcmp(string, "RT") == 0) {
141                 *id = APP_CORE_RT;
142                 return 0;
143         }
144         if (strcmp(string, "TM") == 0) {
145                 *id = APP_CORE_TM;
146                 return 0;
147         }
148         if (strcmp(string, "IPV4_FRAG") == 0) {
149                 *id = APP_CORE_IPV4_FRAG;
150                 return 0;
151         }
152         if (strcmp(string, "IPV4_RAS") == 0) {
153                 *id = APP_CORE_IPV4_RAS;
154                 return 0;
155         }
156
157         return -1;
158 }
159
160 static uint64_t
161 app_get_core_mask(void)
162 {
163         uint64_t core_mask = 0;
164         uint32_t i;
165
166         for (i = 0; i < RTE_MAX_LCORE; i++) {
167                 if (rte_lcore_is_enabled(i) == 0)
168                         continue;
169
170                 core_mask |= 1LLU << i;
171         }
172
173         return core_mask;
174 }
175
176 static int
177 app_install_coremask(uint64_t core_mask)
178 {
179         uint32_t n_cores, i;
180
181         for (n_cores = 0, i = 0; i < RTE_MAX_LCORE; i++)
182                 if (app.cores[i].core_type != APP_CORE_NONE)
183                         n_cores++;
184
185         if (n_cores != app.n_cores) {
186                 rte_panic("Number of cores in COREMASK should be %u instead "
187                         "of %u\n", n_cores, app.n_cores);
188                 return -1;
189         }
190
191         for (i = 0; i < RTE_MAX_LCORE; i++) {
192                 uint32_t core_id;
193
194                 if (app.cores[i].core_type == APP_CORE_NONE)
195                         continue;
196
197                 core_id = __builtin_ctzll(core_mask);
198                 core_mask &= ~(1LLU << core_id);
199
200                 app.cores[i].core_id = core_id;
201         }
202
203         return 0;
204 }
205 static int
206 app_install_cfgfile(const char *file_name)
207 {
208         struct rte_cfgfile *file;
209         uint32_t n_cores, i;
210
211         memset(app.cores, 0, sizeof(app.cores));
212
213         if (file_name[0] == '\0')
214                 return -1;
215
216         file = rte_cfgfile_load(file_name, 0);
217         if (file == NULL) {
218                 rte_panic("Config file %s not found\n", file_name);
219                 return -1;
220         }
221
222         n_cores = (uint32_t) rte_cfgfile_num_sections(file, "core",
223                 strnlen("core", 5));
224         if (n_cores < app.n_cores) {
225                 rte_panic("Config file parse error: not enough cores specified "
226                         "(%u cores missing)\n", app.n_cores - n_cores);
227                 return -1;
228         }
229         if (n_cores > app.n_cores) {
230                 rte_panic("Config file parse error: too many cores specified "
231                         "(%u cores too many)\n", n_cores - app.n_cores);
232                 return -1;
233         }
234
235         for (i = 0; i < n_cores; i++) {
236                 struct app_core_params *p = &app.cores[i];
237                 char section_name[16];
238                 const char *entry;
239                 uint32_t j;
240
241                 /* [core X] */
242                 rte_snprintf(section_name, sizeof(section_name), "core %u", i);
243                 if (!rte_cfgfile_has_section(file, section_name)) {
244                         rte_panic("Config file parse error: core IDs are not "
245                                 "sequential (core %u missing)\n", i);
246                         return -1;
247                 }
248
249                 /* type */
250                 entry = rte_cfgfile_get_entry(file, section_name, "type");
251                 if (!entry) {
252                         rte_panic("Config file parse error: core %u type not "
253                                 "defined\n", i);
254                         return -1;
255                 }
256                 if ((app_core_type_string_to_id(entry, &p->core_type) != 0) ||
257                     (p->core_type == APP_CORE_NONE)) {
258                         rte_panic("Config file parse error: core %u type "
259                                 "error\n", i);
260                         return -1;
261                 }
262
263                 /* queues in */
264                 entry = rte_cfgfile_get_entry(file, section_name, "queues in");
265                 if (!entry) {
266                         rte_panic("Config file parse error: core %u queues in "
267                                 "not defined\n", i);
268                         return -1;
269                 }
270
271                 for (j = 0; (j < APP_MAX_SWQ_PER_CORE) && (entry != NULL);
272                         j++) {
273                         char *next;
274
275                         p->swq_in[j] =  (uint32_t) strtol(entry, &next, 10);
276                         if (next == entry)
277                                 break;
278                         entry = next;
279                 }
280
281                 if ((j != APP_MAX_SWQ_PER_CORE) || (*entry != '\0')) {
282                         rte_panic("Config file parse error: core %u queues in "
283                                 "error\n", i);
284                         return -1;
285                 }
286
287                 /* queues out */
288                 entry = rte_cfgfile_get_entry(file, section_name, "queues out");
289                 if (!entry) {
290                         rte_panic("Config file parse error: core %u queues out "
291                                 "not defined\n", i);
292                         return -1;
293                 }
294
295                 for (j = 0; (j < APP_MAX_SWQ_PER_CORE) && (entry != NULL);
296                         j++) {
297                         char *next;
298
299                         p->swq_out[j] =  (uint32_t) strtol(entry, &next, 10);
300                         if (next == entry)
301                                 break;
302                         entry = next;
303                 }
304                 if ((j != APP_MAX_SWQ_PER_CORE) || (*entry != '\0')) {
305                         rte_panic("Config file parse error: core %u queues out "
306                                 "error\n", i);
307                         return -1;
308                 }
309         }
310
311         rte_cfgfile_close(file);
312
313         return 0;
314 }
315
316 void app_cores_config_print(void)
317 {
318         uint32_t i;
319
320         for (i = 0; i < RTE_MAX_LCORE; i++) {
321                 struct app_core_params *p = &app.cores[i];
322                 uint32_t j;
323
324                 if (app.cores[i].core_type == APP_CORE_NONE)
325                         continue;
326
327                 printf("---> core %u: id = %u type = %6s [", i, p->core_id,
328                         app_core_type_id_to_string(p->core_type));
329                 for (j = 0; j < APP_MAX_SWQ_PER_CORE; j++)
330                         printf("%2d ", (int) p->swq_in[j]);
331
332                 printf("] [");
333                 for (j = 0; j < APP_MAX_SWQ_PER_CORE; j++)
334                         printf("%2d ", (int) p->swq_out[j]);
335
336                 printf("]\n");
337         }
338 }
339
340 static int
341 app_install_port_mask(const char *arg)
342 {
343         char *end = NULL;
344         uint64_t port_mask;
345         uint32_t i;
346
347         if (arg[0] == '\0')
348                 return -1;
349
350         port_mask = strtoul(arg, &end, 16);
351         if ((end == NULL) || (*end != '\0'))
352                 return -2;
353
354         if (port_mask == 0)
355                 return -3;
356
357         app.n_ports = 0;
358         for (i = 0; i < 64; i++) {
359                 if ((port_mask & (1LLU << i)) == 0)
360                         continue;
361
362                 if (app.n_ports >= APP_MAX_PORTS)
363                         return -4;
364
365                 app.ports[app.n_ports] = i;
366                 app.n_ports++;
367         }
368
369         if (!rte_is_power_of_2(app.n_ports))
370                 return -5;
371
372         return 0;
373 }
374
375 int
376 app_parse_args(int argc, char **argv)
377 {
378         int opt, ret;
379         char **argvopt;
380         int option_index;
381         char *prgname = argv[0];
382         static struct option lgopts[] = {
383                 {NULL, 0, 0, 0}
384         };
385         uint64_t core_mask = app_get_core_mask();
386
387         app.n_cores = __builtin_popcountll(core_mask);
388
389         argvopt = argv;
390         while ((opt = getopt_long(argc, argvopt, "p:f:", lgopts,
391                         &option_index)) != EOF) {
392                 switch (opt) {
393                 case 'p':
394                         if (app_install_port_mask(optarg) != 0)
395                                 rte_panic("PORT_MASK should specify a number "
396                                         "of ports that is power of 2 less or "
397                                         "equal to %u\n", APP_MAX_PORTS);
398                         break;
399
400                 case 'f':
401                         app_install_cfgfile(optarg);
402                         break;
403
404                 default:
405                         return -1;
406                 }
407         }
408
409         app_install_coremask(core_mask);
410
411         app_cores_config_print();
412
413         if (optind >= 0)
414                 argv[optind - 1] = prgname;
415
416         ret = optind - 1;
417         optind = 0; /* reset getopt lib */
418
419         return ret;
420 }