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