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