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