ethdev: rename DCB field in config structs
[dpdk.git] / examples / vmdq_dcb / main.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 <stdint.h>
35 #include <sys/queue.h>
36 #include <stdlib.h>
37 #include <string.h>
38 #include <stdio.h>
39 #include <assert.h>
40 #include <errno.h>
41 #include <signal.h>
42 #include <stdarg.h>
43 #include <inttypes.h>
44 #include <getopt.h>
45
46 #include <rte_common.h>
47 #include <rte_log.h>
48 #include <rte_memory.h>
49 #include <rte_memcpy.h>
50 #include <rte_memzone.h>
51 #include <rte_eal.h>
52 #include <rte_per_lcore.h>
53 #include <rte_launch.h>
54 #include <rte_atomic.h>
55 #include <rte_cycles.h>
56 #include <rte_prefetch.h>
57 #include <rte_lcore.h>
58 #include <rte_per_lcore.h>
59 #include <rte_branch_prediction.h>
60 #include <rte_interrupts.h>
61 #include <rte_pci.h>
62 #include <rte_random.h>
63 #include <rte_debug.h>
64 #include <rte_ether.h>
65 #include <rte_ethdev.h>
66 #include <rte_ring.h>
67 #include <rte_log.h>
68 #include <rte_mempool.h>
69 #include <rte_mbuf.h>
70 #include <rte_memcpy.h>
71
72 /* basic constants used in application */
73 #define NUM_QUEUES 128
74
75 #define NUM_MBUFS 64*1024
76 #define MBUF_CACHE_SIZE 64
77
78 #define INVALID_PORT_ID 0xFF
79
80 /* mask of enabled ports */
81 static uint32_t enabled_port_mask = 0;
82
83 /* number of pools (if user does not specify any, 16 by default */
84 static enum rte_eth_nb_pools num_pools = ETH_16_POOLS;
85
86 /* empty vmdq+dcb configuration structure. Filled in programatically */
87 static const struct rte_eth_conf vmdq_dcb_conf_default = {
88         .rxmode = {
89                 .mq_mode        = ETH_MQ_RX_VMDQ_DCB,
90                 .split_hdr_size = 0,
91                 .header_split   = 0, /**< Header Split disabled */
92                 .hw_ip_checksum = 0, /**< IP checksum offload disabled */
93                 .hw_vlan_filter = 0, /**< VLAN filtering disabled */
94                 .jumbo_frame    = 0, /**< Jumbo Frame Support disabled */
95         },
96         .txmode = {
97                 .mq_mode = ETH_MQ_TX_NONE,
98         },
99         .rx_adv_conf = {
100                 /*
101                  * should be overridden separately in code with
102                  * appropriate values
103                  */
104                 .vmdq_dcb_conf = {
105                         .nb_queue_pools = ETH_16_POOLS,
106                         .enable_default_pool = 0,
107                         .default_pool = 0,
108                         .nb_pool_maps = 0,
109                         .pool_map = {{0, 0},},
110                         .dcb_tc = {0},
111                 },
112         },
113 };
114
115 static uint8_t ports[RTE_MAX_ETHPORTS];
116 static unsigned num_ports = 0;
117
118 /* array used for printing out statistics */
119 volatile unsigned long rxPackets[ NUM_QUEUES ] = {0};
120
121 const uint16_t vlan_tags[] = {
122         0,  1,  2,  3,  4,  5,  6,  7,
123         8,  9, 10, 11,  12, 13, 14, 15,
124         16, 17, 18, 19, 20, 21, 22, 23,
125         24, 25, 26, 27, 28, 29, 30, 31
126 };
127
128 /* Builds up the correct configuration for vmdq+dcb based on the vlan tags array
129  * given above, and the number of traffic classes available for use. */
130 static inline int
131 get_eth_conf(struct rte_eth_conf *eth_conf, enum rte_eth_nb_pools num_pools)
132 {
133         struct rte_eth_vmdq_dcb_conf conf;
134         unsigned i;
135
136         if (num_pools != ETH_16_POOLS && num_pools != ETH_32_POOLS ) return -1;
137
138         conf.nb_queue_pools = num_pools;
139         conf.enable_default_pool = 0;
140         conf.default_pool = 0; /* set explicit value, even if not used */
141         conf.nb_pool_maps = sizeof( vlan_tags )/sizeof( vlan_tags[ 0 ]);
142         for (i = 0; i < conf.nb_pool_maps; i++){
143                 conf.pool_map[i].vlan_id = vlan_tags[ i ];
144                 conf.pool_map[i].pools = 1 << (i % num_pools);
145         }
146         for (i = 0; i < ETH_DCB_NUM_USER_PRIORITIES; i++){
147                 conf.dcb_tc[i] = (uint8_t)(i % (NUM_QUEUES/num_pools));
148         }
149         (void)(rte_memcpy(eth_conf, &vmdq_dcb_conf_default, sizeof(*eth_conf)));
150         (void)(rte_memcpy(&eth_conf->rx_adv_conf.vmdq_dcb_conf, &conf,
151                    sizeof(eth_conf->rx_adv_conf.vmdq_dcb_conf)));
152         return 0;
153 }
154
155 /*
156  * Initialises a given port using global settings and with the rx buffers
157  * coming from the mbuf_pool passed as parameter
158  */
159 static inline int
160 port_init(uint8_t port, struct rte_mempool *mbuf_pool)
161 {
162         struct rte_eth_conf port_conf;
163         const uint16_t rxRings = ETH_VMDQ_DCB_NUM_QUEUES,
164                 txRings = (uint16_t)rte_lcore_count();
165         const uint16_t rxRingSize = 128, txRingSize = 512;
166         int retval;
167         uint16_t q;
168
169         retval = get_eth_conf(&port_conf, num_pools);
170         if (retval < 0)
171                 return retval;
172
173         if (port >= rte_eth_dev_count()) return -1;
174
175         retval = rte_eth_dev_configure(port, rxRings, txRings, &port_conf);
176         if (retval != 0)
177                 return retval;
178
179         for (q = 0; q < rxRings; q ++) {
180                 retval = rte_eth_rx_queue_setup(port, q, rxRingSize,
181                                                 rte_eth_dev_socket_id(port),
182                                                 NULL,
183                                                 mbuf_pool);
184                 if (retval < 0)
185                         return retval;
186         }
187
188         for (q = 0; q < txRings; q ++) {
189                 retval = rte_eth_tx_queue_setup(port, q, txRingSize,
190                                                 rte_eth_dev_socket_id(port),
191                                                 NULL);
192                 if (retval < 0)
193                         return retval;
194         }
195
196         retval  = rte_eth_dev_start(port);
197         if (retval < 0)
198                 return retval;
199
200         struct ether_addr addr;
201         rte_eth_macaddr_get(port, &addr);
202         printf("Port %u MAC: %02"PRIx8" %02"PRIx8" %02"PRIx8
203                         " %02"PRIx8" %02"PRIx8" %02"PRIx8"\n",
204                         (unsigned)port,
205                         addr.addr_bytes[0], addr.addr_bytes[1], addr.addr_bytes[2],
206                         addr.addr_bytes[3], addr.addr_bytes[4], addr.addr_bytes[5]);
207
208         return 0;
209 }
210
211 /* Check num_pools parameter and set it if OK*/
212 static int
213 vmdq_parse_num_pools(const char *q_arg)
214 {
215         char *end = NULL;
216         int n;
217
218         /* parse number string */
219         n = strtol(q_arg, &end, 10);
220         if ((q_arg[0] == '\0') || (end == NULL) || (*end != '\0'))
221                 return -1;
222         if (n != 16 && n != 32)
223                 return -1;
224         if (n == 16)
225                 num_pools = ETH_16_POOLS;
226         else
227                 num_pools = ETH_32_POOLS;
228
229         return 0;
230 }
231
232 static int
233 parse_portmask(const char *portmask)
234 {
235         char *end = NULL;
236         unsigned long pm;
237
238         /* parse hexadecimal string */
239         pm = strtoul(portmask, &end, 16);
240         if ((portmask[0] == '\0') || (end == NULL) || (*end != '\0'))
241                 return -1;
242
243         if (pm == 0)
244                 return -1;
245
246         return pm;
247 }
248
249 /* Display usage */
250 static void
251 vmdq_usage(const char *prgname)
252 {
253         printf("%s [EAL options] -- -p PORTMASK]\n"
254                "  --nb-pools NP: number of pools (16 default, 32)\n",
255                prgname);
256 }
257
258 /*  Parse the argument (num_pools) given in the command line of the application */
259 static int
260 vmdq_parse_args(int argc, char **argv)
261 {
262         int opt;
263         int option_index;
264         unsigned i;
265         const char *prgname = argv[0];
266         static struct option long_option[] = {
267                 {"nb-pools", required_argument, NULL, 0},
268                 {NULL, 0, 0, 0}
269         };
270
271         /* Parse command line */
272         while ((opt = getopt_long(argc, argv, "p:",long_option,&option_index)) != EOF) {
273                 switch (opt) {
274                 /* portmask */
275                 case 'p':
276                         enabled_port_mask = parse_portmask(optarg);
277                         if (enabled_port_mask == 0) {
278                                 printf("invalid portmask\n");
279                                 vmdq_usage(prgname);
280                                 return -1;
281                         }
282                         break;
283                 case 0:
284                         if (vmdq_parse_num_pools(optarg) == -1){
285                                 printf("invalid number of pools\n");
286                                 vmdq_usage(prgname);
287                                 return -1;
288                         }
289                         break;
290                 default:
291                         vmdq_usage(prgname);
292                         return -1;
293                 }
294         }
295
296         for(i = 0; i < RTE_MAX_ETHPORTS; i++)
297         {
298                 if (enabled_port_mask & (1 << i))
299                         ports[num_ports++] = (uint8_t)i;
300         }
301
302         if (num_ports < 2 || num_ports % 2) {
303                 printf("Current enabled port number is %u,"
304                         "but it should be even and at least 2\n",num_ports);
305                 return -1;
306         }
307
308         return 0;
309 }
310
311
312 /* When we receive a HUP signal, print out our stats */
313 static void
314 sighup_handler(int signum)
315 {
316         unsigned q;
317         for (q = 0; q < NUM_QUEUES; q ++) {
318                 if (q % (NUM_QUEUES/num_pools) == 0)
319                         printf("\nPool %u: ", q/(NUM_QUEUES/num_pools));
320                 printf("%lu ", rxPackets[ q ]);
321         }
322         printf("\nFinished handling signal %d\n", signum);
323 }
324
325 /*
326  * Main thread that does the work, reading from INPUT_PORT
327  * and writing to OUTPUT_PORT
328  */
329 static  __attribute__((noreturn)) int
330 lcore_main(void *arg)
331 {
332         const uintptr_t core_num = (uintptr_t)arg;
333         const unsigned num_cores = rte_lcore_count();
334         uint16_t startQueue = (uint16_t)(core_num * (NUM_QUEUES/num_cores));
335         uint16_t endQueue = (uint16_t)(startQueue + (NUM_QUEUES/num_cores));
336         uint16_t q, i, p;
337
338         printf("Core %u(lcore %u) reading queues %i-%i\n", (unsigned)core_num,
339                rte_lcore_id(), startQueue, endQueue - 1);
340
341         for (;;) {
342                 struct rte_mbuf *buf[32];
343                 const uint16_t buf_size = sizeof(buf) / sizeof(buf[0]);
344                 for (p = 0; p < num_ports; p++) {
345                         const uint8_t src = ports[p];
346                         const uint8_t dst = ports[p ^ 1]; /* 0 <-> 1, 2 <-> 3 etc */
347
348                         if ((src == INVALID_PORT_ID) || (dst == INVALID_PORT_ID))
349                                 continue;
350
351                         for (q = startQueue; q < endQueue; q++) {
352                                 const uint16_t rxCount = rte_eth_rx_burst(src,
353                                         q, buf, buf_size);
354                                 if (rxCount == 0)
355                                         continue;
356                                 rxPackets[q] += rxCount;
357
358                                 const uint16_t txCount = rte_eth_tx_burst(dst,
359                                         (uint16_t)core_num, buf, rxCount);
360                                 if (txCount != rxCount) {
361                                         for (i = txCount; i < rxCount; i++)
362                                                 rte_pktmbuf_free(buf[i]);
363                                 }
364                         }
365                 }
366         }
367 }
368
369 /*
370  * Update the global var NUM_PORTS and array PORTS according to system ports number
371  * and return valid ports number
372  */
373 static unsigned check_ports_num(unsigned nb_ports)
374 {
375         unsigned valid_num_ports = num_ports;
376         unsigned portid;
377
378         if (num_ports > nb_ports) {
379                 printf("\nSpecified port number(%u) exceeds total system port number(%u)\n",
380                         num_ports, nb_ports);
381                 num_ports = nb_ports;
382         }
383
384         for (portid = 0; portid < num_ports; portid ++) {
385                 if (ports[portid] >= nb_ports) {
386                         printf("\nSpecified port ID(%u) exceeds max system port ID(%u)\n",
387                                 ports[portid], (nb_ports - 1));
388                         ports[portid] = INVALID_PORT_ID;
389                         valid_num_ports --;
390                 }
391         }
392         return valid_num_ports;
393 }
394
395
396 /* Main function, does initialisation and calls the per-lcore functions */
397 int
398 main(int argc, char *argv[])
399 {
400         unsigned cores;
401         struct rte_mempool *mbuf_pool;
402         unsigned lcore_id;
403         uintptr_t i;
404         int ret;
405         unsigned nb_ports, valid_num_ports;
406         uint8_t portid;
407
408         signal(SIGHUP, sighup_handler);
409
410         /* init EAL */
411         ret = rte_eal_init(argc, argv);
412         if (ret < 0)
413                 rte_exit(EXIT_FAILURE, "Error with EAL initialization\n");
414         argc -= ret;
415         argv += ret;
416
417         /* parse app arguments */
418         ret = vmdq_parse_args(argc, argv);
419         if (ret < 0)
420                 rte_exit(EXIT_FAILURE, "Invalid VMDQ argument\n");
421
422         cores = rte_lcore_count();
423         if ((cores & (cores - 1)) != 0 || cores > 128) {
424                 rte_exit(EXIT_FAILURE,"This program can only run on an even"
425                                 "number of cores(1-128)\n\n");
426         }
427
428         nb_ports = rte_eth_dev_count();
429         if (nb_ports > RTE_MAX_ETHPORTS)
430                 nb_ports = RTE_MAX_ETHPORTS;
431
432         /*
433          * Update the global var NUM_PORTS and global array PORTS
434          * and get value of var VALID_NUM_PORTS according to system ports number
435          */
436         valid_num_ports = check_ports_num(nb_ports);
437
438         if (valid_num_ports < 2 || valid_num_ports % 2) {
439                 printf("Current valid ports number is %u\n", valid_num_ports);
440                 rte_exit(EXIT_FAILURE, "Error with valid ports number is not even or less than 2\n");
441         }
442
443         mbuf_pool = rte_pktmbuf_pool_create("MBUF_POOL", NUM_MBUFS * nb_ports,
444                 MBUF_CACHE_SIZE, 0, RTE_MBUF_DEFAULT_BUF_SIZE, rte_socket_id());
445         if (mbuf_pool == NULL)
446                 rte_exit(EXIT_FAILURE, "Cannot create mbuf pool\n");
447
448         /* initialize all ports */
449         for (portid = 0; portid < nb_ports; portid++) {
450                 /* skip ports that are not enabled */
451                 if ((enabled_port_mask & (1 << portid)) == 0) {
452                         printf("\nSkipping disabled port %d\n", portid);
453                         continue;
454                 }
455                 if (port_init(portid, mbuf_pool) != 0)
456                         rte_exit(EXIT_FAILURE, "Cannot initialize network ports\n");
457         }
458
459         /* call lcore_main() on every slave lcore */
460         i = 0;
461         RTE_LCORE_FOREACH_SLAVE(lcore_id) {
462                 rte_eal_remote_launch(lcore_main, (void*)i++, lcore_id);
463         }
464         /* call on master too */
465         (void) lcore_main((void*)i);
466
467         return 0;
468 }