examples: numa updates
[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         return 0;
229 }
230
231 /* Check num_pools parameter and set it if OK*/
232 static int
233 vmdq_parse_num_pools(const char *q_arg)
234 {
235         char *end = NULL;
236         int n;
237
238         /* parse number string */
239         n = strtol(q_arg, &end, 10);
240         if ((q_arg[0] == '\0') || (end == NULL) || (*end != '\0'))
241                 return -1;
242         if (n != 16 && n != 32)
243                 return -1;
244         if (n == 16)
245                 num_pools = ETH_16_POOLS;
246         else
247                 num_pools = ETH_32_POOLS;
248
249         return 0;
250 }
251
252 /* Display usage */
253 static void
254 vmdq_usage(const char *prgname)
255 {
256         printf("%s [EAL options] -- [-nb-pools NP]\n"
257                "  -nb-pools NP: number of pools (16 default, 32)\n",
258                prgname);
259 }
260
261 /*  Parse the argument (num_pools) given in the command line of the application */
262 static int
263 vmdq_parse_args(int argc, char **argv)
264 {
265         int opt;
266         int option_index;
267         const char *prgname = argv[0];
268
269         static struct option long_option[] = {
270                 {"nb-pools", required_argument, NULL, 0},
271                 {NULL, 0, 0, 0}
272         };
273
274         /* Parse command line */
275         while ((opt = getopt_long_only(argc, argv, "",long_option,&option_index)) != EOF) {
276                 switch (opt) {
277                 case 0:
278                         if (vmdq_parse_num_pools(optarg) == -1){
279                                 printf("invalid number of pools\n");
280                                 vmdq_usage(prgname);
281                                 return -1;
282                         }
283                         break;
284                 default:
285                         vmdq_usage(prgname);
286                         return -1;
287                 }
288         }
289         return 0;
290
291
292 }
293
294
295 #ifndef RTE_EXEC_ENV_BAREMETAL
296 /* When we receive a HUP signal, print out our stats */
297 static void
298 sighup_handler(int signum)
299 {
300         unsigned q;
301         for (q = 0; q < NUM_QUEUES; q ++) {
302                 if (q % (NUM_QUEUES/num_pools) == 0)
303                         printf("\nPool %u: ", q/(NUM_QUEUES/num_pools));
304                 printf("%lu ", rxPackets[ q ]);
305         }
306         printf("\nFinished handling signal %d\n", signum);
307 }
308 #endif
309
310 /*
311  * Main thread that does the work, reading from INPUT_PORT
312  * and writing to OUTPUT_PORT
313  */
314 static  __attribute__((noreturn)) int
315 lcore_main(void *arg)
316 {
317         const uintptr_t core_num = (uintptr_t)arg;
318         const unsigned num_cores = rte_lcore_count();
319         uint16_t startQueue = (uint16_t)(core_num * (NUM_QUEUES/num_cores));
320         uint16_t endQueue = (uint16_t)(startQueue + (NUM_QUEUES/num_cores));
321         uint16_t q, i;
322
323         printf("Core %u(lcore %u) reading queues %i-%i\n", (unsigned)core_num,
324                rte_lcore_id(), startQueue, endQueue - 1);
325
326         for (;;) {
327                 struct rte_mbuf *buf[32];
328                 const uint16_t buf_size = sizeof(buf) / sizeof(buf[0]);
329
330                 for (q = startQueue; q < endQueue; q++) {
331                         const uint16_t rxCount = rte_eth_rx_burst(RX_PORT,
332                                         q, buf, buf_size);
333                         if (rxCount == 0)
334                                 continue;
335                         rxPackets[q] += rxCount;
336
337                         const uint16_t txCount = rte_eth_tx_burst(TX_PORT,
338                                         (uint16_t)core_num, buf, rxCount);
339                         if (txCount != rxCount) {
340                                 for (i = txCount; i < rxCount; i++)
341                                         rte_pktmbuf_free(buf[i]);
342                         }
343                 }
344         }
345 }
346
347 /* Main function, does initialisation and calls the per-lcore functions */
348 int
349 MAIN(int argc, char *argv[])
350 {
351         unsigned cores;
352         struct rte_mempool *mbuf_pool;
353         unsigned lcore_id;
354         uintptr_t i;
355         int ret;
356
357 #ifndef RTE_EXEC_ENV_BAREMETAL
358         signal(SIGHUP, sighup_handler);
359 #endif
360
361         /* init EAL */
362         ret = rte_eal_init(argc, argv);
363         if (ret < 0)
364                 rte_exit(EXIT_FAILURE, "Error with EAL initialization\n");
365         argc -= ret;
366         argv += ret;
367
368         /* parse app arguments */
369         ret = vmdq_parse_args(argc, argv);
370         if (ret < 0)
371                 rte_exit(EXIT_FAILURE, "Invalid VMDQ argument\n");
372
373         if (rte_ixgbe_pmd_init() != 0 ||
374                         rte_eal_pci_probe() != 0)
375                 rte_exit(EXIT_FAILURE, "Error with NIC driver initialization\n");
376
377         cores = rte_lcore_count();
378         if ((cores & (cores - 1)) != 0 || cores > 16) {
379                 rte_exit(EXIT_FAILURE,
380                          "This program can only run on 2,4,8 or 16 cores\n\n");
381         }
382
383         mbuf_pool = rte_mempool_create("MBUF_POOL", NUM_MBUFS,
384                                        MBUF_SIZE, MBUF_CACHE_SIZE,
385                                        sizeof(struct rte_pktmbuf_pool_private),
386                                        rte_pktmbuf_pool_init, NULL,
387                                        rte_pktmbuf_init, NULL,
388                                        rte_socket_id(), 0);
389         if (mbuf_pool == NULL)
390                 rte_exit(EXIT_FAILURE, "Cannot create mbuf pool\n");
391
392         if (port_init(RX_PORT, mbuf_pool) != 0 ||
393             port_init(TX_PORT, mbuf_pool) != 0)
394                 rte_exit(EXIT_FAILURE, "Cannot initialize network ports\n");
395
396         /* call lcore_main() on every slave lcore */
397         i = 0;
398         RTE_LCORE_FOREACH_SLAVE(lcore_id) {
399                 rte_eal_remote_launch(lcore_main, (void*)i++, lcore_id);
400         }
401         /* call on master too */
402         (void) lcore_main((void*)i);
403
404         return 0;
405 }