4 * Copyright(c) 2010-2014 Intel Corporation. All rights reserved.
7 * Redistribution and use in source and binary forms, with or without
8 * modification, are permitted provided that the following conditions
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
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.
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.
35 #include <sys/queue.h>
46 #include <rte_common.h>
48 #include <rte_memory.h>
49 #include <rte_memcpy.h>
50 #include <rte_memzone.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>
62 #include <rte_random.h>
63 #include <rte_debug.h>
64 #include <rte_ether.h>
65 #include <rte_ethdev.h>
68 #include <rte_mempool.h>
70 #include <rte_memcpy.h>
72 /* basic constants used in application */
73 #define NUM_QUEUES 128
75 #define NUM_MBUFS 64*1024
76 #define MBUF_CACHE_SIZE 64
77 #define MBUF_SIZE (2048 + sizeof(struct rte_mbuf) + RTE_PKTMBUF_HEADROOM)
79 #define INVALID_PORT_ID 0xFF
81 /* mask of enabled ports */
82 static uint32_t enabled_port_mask = 0;
84 /* number of pools (if user does not specify any, 16 by default */
85 static enum rte_eth_nb_pools num_pools = ETH_16_POOLS;
87 /* empty vmdq+dcb configuration structure. Filled in programatically */
88 static const struct rte_eth_conf vmdq_dcb_conf_default = {
90 .mq_mode = ETH_MQ_RX_VMDQ_DCB,
92 .header_split = 0, /**< Header Split disabled */
93 .hw_ip_checksum = 0, /**< IP checksum offload disabled */
94 .hw_vlan_filter = 0, /**< VLAN filtering disabled */
95 .jumbo_frame = 0, /**< Jumbo Frame Support disabled */
98 .mq_mode = ETH_MQ_TX_NONE,
102 * should be overridden separately in code with
106 .nb_queue_pools = ETH_16_POOLS,
107 .enable_default_pool = 0,
110 .pool_map = {{0, 0},},
116 static uint8_t ports[RTE_MAX_ETHPORTS];
117 static unsigned num_ports = 0;
119 /* array used for printing out statistics */
120 volatile unsigned long rxPackets[ NUM_QUEUES ] = {0};
122 const uint16_t vlan_tags[] = {
123 0, 1, 2, 3, 4, 5, 6, 7,
124 8, 9, 10, 11, 12, 13, 14, 15,
125 16, 17, 18, 19, 20, 21, 22, 23,
126 24, 25, 26, 27, 28, 29, 30, 31
129 /* Builds up the correct configuration for vmdq+dcb based on the vlan tags array
130 * given above, and the number of traffic classes available for use. */
132 get_eth_conf(struct rte_eth_conf *eth_conf, enum rte_eth_nb_pools num_pools)
134 struct rte_eth_vmdq_dcb_conf conf;
137 if (num_pools != ETH_16_POOLS && num_pools != ETH_32_POOLS ) return -1;
139 conf.nb_queue_pools = num_pools;
140 conf.enable_default_pool = 0;
141 conf.default_pool = 0; /* set explicit value, even if not used */
142 conf.nb_pool_maps = sizeof( vlan_tags )/sizeof( vlan_tags[ 0 ]);
143 for (i = 0; i < conf.nb_pool_maps; i++){
144 conf.pool_map[i].vlan_id = vlan_tags[ i ];
145 conf.pool_map[i].pools = 1 << (i % num_pools);
147 for (i = 0; i < ETH_DCB_NUM_USER_PRIORITIES; i++){
148 conf.dcb_queue[i] = (uint8_t)(i % (NUM_QUEUES/num_pools));
150 (void)(rte_memcpy(eth_conf, &vmdq_dcb_conf_default, sizeof(*eth_conf)));
151 (void)(rte_memcpy(ð_conf->rx_adv_conf.vmdq_dcb_conf, &conf,
152 sizeof(eth_conf->rx_adv_conf.vmdq_dcb_conf)));
157 * Initialises a given port using global settings and with the rx buffers
158 * coming from the mbuf_pool passed as parameter
161 port_init(uint8_t port, struct rte_mempool *mbuf_pool)
163 struct rte_eth_conf port_conf;
164 const uint16_t rxRings = ETH_VMDQ_DCB_NUM_QUEUES,
165 txRings = (uint16_t)rte_lcore_count();
166 const uint16_t rxRingSize = 128, txRingSize = 512;
170 retval = get_eth_conf(&port_conf, num_pools);
174 if (port >= rte_eth_dev_count()) return -1;
176 retval = rte_eth_dev_configure(port, rxRings, txRings, &port_conf);
180 for (q = 0; q < rxRings; q ++) {
181 retval = rte_eth_rx_queue_setup(port, q, rxRingSize,
182 rte_eth_dev_socket_id(port),
189 for (q = 0; q < txRings; q ++) {
190 retval = rte_eth_tx_queue_setup(port, q, txRingSize,
191 rte_eth_dev_socket_id(port),
197 retval = rte_eth_dev_start(port);
201 struct ether_addr addr;
202 rte_eth_macaddr_get(port, &addr);
203 printf("Port %u MAC: %02"PRIx8" %02"PRIx8" %02"PRIx8
204 " %02"PRIx8" %02"PRIx8" %02"PRIx8"\n",
206 addr.addr_bytes[0], addr.addr_bytes[1], addr.addr_bytes[2],
207 addr.addr_bytes[3], addr.addr_bytes[4], addr.addr_bytes[5]);
212 /* Check num_pools parameter and set it if OK*/
214 vmdq_parse_num_pools(const char *q_arg)
219 /* parse number string */
220 n = strtol(q_arg, &end, 10);
221 if ((q_arg[0] == '\0') || (end == NULL) || (*end != '\0'))
223 if (n != 16 && n != 32)
226 num_pools = ETH_16_POOLS;
228 num_pools = ETH_32_POOLS;
234 parse_portmask(const char *portmask)
239 /* parse hexadecimal string */
240 pm = strtoul(portmask, &end, 16);
241 if ((portmask[0] == '\0') || (end == NULL) || (*end != '\0'))
252 vmdq_usage(const char *prgname)
254 printf("%s [EAL options] -- -p PORTMASK]\n"
255 " --nb-pools NP: number of pools (16 default, 32)\n",
259 /* Parse the argument (num_pools) given in the command line of the application */
261 vmdq_parse_args(int argc, char **argv)
266 const char *prgname = argv[0];
267 static struct option long_option[] = {
268 {"nb-pools", required_argument, NULL, 0},
272 /* Parse command line */
273 while ((opt = getopt_long(argc, argv, "p:",long_option,&option_index)) != EOF) {
277 enabled_port_mask = parse_portmask(optarg);
278 if (enabled_port_mask == 0) {
279 printf("invalid portmask\n");
285 if (vmdq_parse_num_pools(optarg) == -1){
286 printf("invalid number of pools\n");
297 for(i = 0; i < RTE_MAX_ETHPORTS; i++)
299 if (enabled_port_mask & (1 << i))
300 ports[num_ports++] = (uint8_t)i;
303 if (num_ports < 2 || num_ports % 2) {
304 printf("Current enabled port number is %u,"
305 "but it should be even and at least 2\n",num_ports);
313 /* When we receive a HUP signal, print out our stats */
315 sighup_handler(int signum)
318 for (q = 0; q < NUM_QUEUES; q ++) {
319 if (q % (NUM_QUEUES/num_pools) == 0)
320 printf("\nPool %u: ", q/(NUM_QUEUES/num_pools));
321 printf("%lu ", rxPackets[ q ]);
323 printf("\nFinished handling signal %d\n", signum);
327 * Main thread that does the work, reading from INPUT_PORT
328 * and writing to OUTPUT_PORT
330 static __attribute__((noreturn)) int
331 lcore_main(void *arg)
333 const uintptr_t core_num = (uintptr_t)arg;
334 const unsigned num_cores = rte_lcore_count();
335 uint16_t startQueue = (uint16_t)(core_num * (NUM_QUEUES/num_cores));
336 uint16_t endQueue = (uint16_t)(startQueue + (NUM_QUEUES/num_cores));
339 printf("Core %u(lcore %u) reading queues %i-%i\n", (unsigned)core_num,
340 rte_lcore_id(), startQueue, endQueue - 1);
343 struct rte_mbuf *buf[32];
344 const uint16_t buf_size = sizeof(buf) / sizeof(buf[0]);
345 for (p = 0; p < num_ports; p++) {
346 const uint8_t src = ports[p];
347 const uint8_t dst = ports[p ^ 1]; /* 0 <-> 1, 2 <-> 3 etc */
349 if ((src == INVALID_PORT_ID) || (dst == INVALID_PORT_ID))
352 for (q = startQueue; q < endQueue; q++) {
353 const uint16_t rxCount = rte_eth_rx_burst(src,
357 rxPackets[q] += rxCount;
359 const uint16_t txCount = rte_eth_tx_burst(dst,
360 (uint16_t)core_num, buf, rxCount);
361 if (txCount != rxCount) {
362 for (i = txCount; i < rxCount; i++)
363 rte_pktmbuf_free(buf[i]);
371 * Update the global var NUM_PORTS and array PORTS according to system ports number
372 * and return valid ports number
374 static unsigned check_ports_num(unsigned nb_ports)
376 unsigned valid_num_ports = num_ports;
379 if (num_ports > nb_ports) {
380 printf("\nSpecified port number(%u) exceeds total system port number(%u)\n",
381 num_ports, nb_ports);
382 num_ports = nb_ports;
385 for (portid = 0; portid < num_ports; portid ++) {
386 if (ports[portid] >= nb_ports) {
387 printf("\nSpecified port ID(%u) exceeds max system port ID(%u)\n",
388 ports[portid], (nb_ports - 1));
389 ports[portid] = INVALID_PORT_ID;
393 return valid_num_ports;
397 /* Main function, does initialisation and calls the per-lcore functions */
399 main(int argc, char *argv[])
402 struct rte_mempool *mbuf_pool;
406 unsigned nb_ports, valid_num_ports;
409 signal(SIGHUP, sighup_handler);
412 ret = rte_eal_init(argc, argv);
414 rte_exit(EXIT_FAILURE, "Error with EAL initialization\n");
418 /* parse app arguments */
419 ret = vmdq_parse_args(argc, argv);
421 rte_exit(EXIT_FAILURE, "Invalid VMDQ argument\n");
423 cores = rte_lcore_count();
424 if ((cores & (cores - 1)) != 0 || cores > 128) {
425 rte_exit(EXIT_FAILURE,"This program can only run on an even"
426 "number of cores(1-128)\n\n");
429 nb_ports = rte_eth_dev_count();
430 if (nb_ports > RTE_MAX_ETHPORTS)
431 nb_ports = RTE_MAX_ETHPORTS;
434 * Update the global var NUM_PORTS and global array PORTS
435 * and get value of var VALID_NUM_PORTS according to system ports number
437 valid_num_ports = check_ports_num(nb_ports);
439 if (valid_num_ports < 2 || valid_num_ports % 2) {
440 printf("Current valid ports number is %u\n", valid_num_ports);
441 rte_exit(EXIT_FAILURE, "Error with valid ports number is not even or less than 2\n");
444 mbuf_pool = rte_mempool_create("MBUF_POOL", NUM_MBUFS * nb_ports,
445 MBUF_SIZE, MBUF_CACHE_SIZE,
446 sizeof(struct rte_pktmbuf_pool_private),
447 rte_pktmbuf_pool_init, NULL,
448 rte_pktmbuf_init, NULL,
450 if (mbuf_pool == NULL)
451 rte_exit(EXIT_FAILURE, "Cannot create mbuf pool\n");
453 /* initialize all ports */
454 for (portid = 0; portid < nb_ports; portid++) {
455 /* skip ports that are not enabled */
456 if ((enabled_port_mask & (1 << portid)) == 0) {
457 printf("\nSkipping disabled port %d\n", portid);
460 if (port_init(portid, mbuf_pool) != 0)
461 rte_exit(EXIT_FAILURE, "Cannot initialize network ports\n");
464 /* call lcore_main() on every slave lcore */
466 RTE_LCORE_FOREACH_SLAVE(lcore_id) {
467 rte_eal_remote_launch(lcore_main, (void*)i++, lcore_id);
469 /* call on master too */
470 (void) lcore_main((void*)i);