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.
38 #include <sys/types.h>
40 #include <sys/queue.h>
46 #include <rte_common.h>
47 #include <rte_byteorder.h>
49 #include <rte_memory.h>
50 #include <rte_memcpy.h>
51 #include <rte_memzone.h>
53 #include <rte_per_lcore.h>
54 #include <rte_launch.h>
55 #include <rte_atomic.h>
56 #include <rte_spinlock.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>
64 #include <rte_random.h>
65 #include <rte_debug.h>
66 #include <rte_ether.h>
67 #include <rte_ethdev.h>
68 #include <rte_mempool.h>
73 #include <rte_string_fns.h>
75 #define APP_LOOKUP_EXACT_MATCH 0
76 #define APP_LOOKUP_LPM 1
77 #define DO_RFC_1812_CHECKS
79 //#define APP_LOOKUP_METHOD APP_LOOKUP_EXACT_MATCH
80 #ifndef APP_LOOKUP_METHOD
81 #define APP_LOOKUP_METHOD APP_LOOKUP_LPM
84 #if (APP_LOOKUP_METHOD == APP_LOOKUP_EXACT_MATCH)
86 #elif (APP_LOOKUP_METHOD == APP_LOOKUP_LPM)
89 #error "APP_LOOKUP_METHOD set to incorrect value"
92 #define RTE_LOGTYPE_L3FWD RTE_LOGTYPE_USER1
94 #define MEMPOOL_CACHE_SIZE 256
97 * This expression is used to calculate the number of mbufs needed depending on user input, taking
98 * into account memory for rx and tx hardware rings, cache per lcore and mtable per port per lcore.
99 * RTE_MAX is used to ensure that NB_MBUF never goes below a minimum value of 8192
102 #define NB_MBUF RTE_MAX ( \
103 (nb_ports*nb_rx_queue*RTE_TEST_RX_DESC_DEFAULT + \
104 nb_ports*nb_lcores*MAX_PKT_BURST + \
105 nb_ports*n_tx_queue*RTE_TEST_TX_DESC_DEFAULT + \
106 nb_lcores*MEMPOOL_CACHE_SIZE), \
110 * RX and TX Prefetch, Host, and Write-back threshold values should be
111 * carefully set for optimal performance. Consult the network
112 * controller's datasheet and supporting DPDK documentation for guidance
113 * on how these parameters should be set.
115 #define RX_PTHRESH 8 /**< Default values of RX prefetch threshold reg. */
116 #define RX_HTHRESH 8 /**< Default values of RX host threshold reg. */
117 #define RX_WTHRESH 4 /**< Default values of RX write-back threshold reg. */
120 * These default values are optimized for use with the Intel(R) 82599 10 GbE
121 * Controller and the DPDK ixgbe PMD. Consider using other values for other
122 * network controllers and/or network drivers.
124 #define TX_PTHRESH 36 /**< Default values of TX prefetch threshold reg. */
125 #define TX_HTHRESH 0 /**< Default values of TX host threshold reg. */
126 #define TX_WTHRESH 0 /**< Default values of TX write-back threshold reg. */
128 #define MAX_PKT_BURST 32
129 #define BURST_TX_DRAIN_US 100 /* TX drain every ~100us */
135 /* Configure how many packets ahead to prefetch, when reading packets */
136 #define PREFETCH_OFFSET 3
139 * Configurable number of RX/TX ring descriptors
141 #define RTE_TEST_RX_DESC_DEFAULT 128
142 #define RTE_TEST_TX_DESC_DEFAULT 512
143 static uint16_t nb_rxd
= RTE_TEST_RX_DESC_DEFAULT
;
144 static uint16_t nb_txd
= RTE_TEST_TX_DESC_DEFAULT
;
146 /* ethernet addresses of ports */
147 static struct ether_addr ports_eth_addr
[RTE_MAX_ETHPORTS
];
149 /* mask of enabled ports */
150 static uint32_t enabled_port_mask
= 0;
151 static int numa_on
= 1; /**< NUMA is enabled by default. */
155 struct rte_mbuf
*m_table
[MAX_PKT_BURST
];
158 struct lcore_rx_queue
{
161 } __rte_cache_aligned
;
163 #define MAX_RX_QUEUE_PER_LCORE 16
164 #define MAX_TX_QUEUE_PER_PORT 1
165 #define MAX_RX_QUEUE_PER_PORT 1
167 #define MAX_LCORE_PARAMS 1024
168 struct lcore_params
{
172 } __rte_cache_aligned
;
174 static struct lcore_params lcore_params_array
[MAX_LCORE_PARAMS
];
175 static struct lcore_params lcore_params_array_default
[] = {
187 static struct lcore_params
* lcore_params
= lcore_params_array_default
;
188 static uint16_t nb_lcore_params
= sizeof(lcore_params_array_default
) /
189 sizeof(lcore_params_array_default
[0]);
191 static struct rte_eth_conf port_conf
= {
193 .mq_mode
= ETH_MQ_RX_RSS
,
194 .max_rx_pkt_len
= ETHER_MAX_LEN
,
196 .header_split
= 0, /**< Header Split disabled */
197 .hw_ip_checksum
= 1, /**< IP checksum offload enabled */
198 .hw_vlan_filter
= 0, /**< VLAN filtering disabled */
199 .jumbo_frame
= 0, /**< Jumbo Frame Support disabled */
200 .hw_strip_crc
= 0, /**< CRC stripped by hardware */
205 .rss_hf
= ETH_RSS_IP
,
209 .mq_mode
= ETH_MQ_TX_NONE
,
213 static struct rte_mempool
* pktmbuf_pool
[NB_SOCKETS
];
216 #if (APP_LOOKUP_METHOD == APP_LOOKUP_EXACT_MATCH)
218 #ifdef RTE_MACHINE_CPUFLAG_SSE4_2
219 #include <rte_hash_crc.h>
220 #define DEFAULT_HASH_FUNC rte_hash_crc
222 #include <rte_jhash.h>
223 #define DEFAULT_HASH_FUNC rte_jhash
232 } __attribute__((__packed__
));
235 struct ipv4_5tuple key
;
239 static struct l3fwd_route l3fwd_route_array
[] = {
240 {{IPv4(100,10,0,1), IPv4(200,10,0,1), 101, 11, IPPROTO_TCP
}, 0},
241 {{IPv4(100,20,0,2), IPv4(200,20,0,2), 102, 12, IPPROTO_TCP
}, 1},
242 {{IPv4(100,30,0,3), IPv4(200,30,0,3), 103, 13, IPPROTO_TCP
}, 2},
243 {{IPv4(100,40,0,4), IPv4(200,40,0,4), 104, 14, IPPROTO_TCP
}, 3},
246 typedef struct rte_hash lookup_struct_t
;
247 static lookup_struct_t
*l3fwd_lookup_struct
[NB_SOCKETS
];
249 #define L3FWD_HASH_ENTRIES 1024
250 struct rte_hash_parameters l3fwd_hash_params
= {
251 .name
= "l3fwd_hash_0",
252 .entries
= L3FWD_HASH_ENTRIES
,
253 .key_len
= sizeof(struct ipv4_5tuple
),
254 .hash_func
= DEFAULT_HASH_FUNC
,
255 .hash_func_init_val
= 0,
256 .socket_id
= SOCKET0
,
259 #define L3FWD_NUM_ROUTES \
260 (sizeof(l3fwd_route_array) / sizeof(l3fwd_route_array[0]))
262 static uint8_t l3fwd_out_if
[L3FWD_HASH_ENTRIES
] __rte_cache_aligned
;
265 #if (APP_LOOKUP_METHOD == APP_LOOKUP_LPM)
272 static struct l3fwd_route l3fwd_route_array
[] = {
273 {IPv4(1,1,1,0), 24, 0},
274 {IPv4(2,1,1,0), 24, 1},
275 {IPv4(3,1,1,0), 24, 2},
276 {IPv4(4,1,1,0), 24, 3},
277 {IPv4(5,1,1,0), 24, 4},
278 {IPv4(6,1,1,0), 24, 5},
279 {IPv4(7,1,1,0), 24, 6},
280 {IPv4(8,1,1,0), 24, 7},
283 #define L3FWD_NUM_ROUTES \
284 (sizeof(l3fwd_route_array) / sizeof(l3fwd_route_array[0]))
286 #define L3FWD_LPM_MAX_RULES 1024
288 typedef struct rte_lpm lookup_struct_t
;
289 static lookup_struct_t
*l3fwd_lookup_struct
[NB_SOCKETS
];
294 struct lcore_rx_queue rx_queue_list
[MAX_RX_QUEUE_PER_LCORE
];
295 uint16_t tx_queue_id
;
296 struct mbuf_table tx_mbufs
[RTE_MAX_ETHPORTS
];
297 lookup_struct_t
* lookup_struct
;
298 } __rte_cache_aligned
;
300 static struct lcore_conf lcore_conf
[RTE_MAX_LCORE
];
301 static rte_spinlock_t spinlock_conf
[RTE_MAX_ETHPORTS
] = {RTE_SPINLOCK_INITIALIZER
};
302 /* Send burst of packets on an output interface */
304 send_burst(struct lcore_conf
*qconf
, uint16_t n
, uint8_t port
)
306 struct rte_mbuf
**m_table
;
310 queueid
= qconf
->tx_queue_id
;
311 m_table
= (struct rte_mbuf
**)qconf
->tx_mbufs
[port
].m_table
;
313 rte_spinlock_lock(&spinlock_conf
[port
]);
314 ret
= rte_eth_tx_burst(port
, queueid
, m_table
, n
);
315 rte_spinlock_unlock(&spinlock_conf
[port
]);
317 if (unlikely(ret
< n
)) {
319 rte_pktmbuf_free(m_table
[ret
]);
326 /* Enqueue a single packet, and send burst if queue is filled */
328 send_single_packet(struct rte_mbuf
*m
, uint8_t port
)
332 struct lcore_conf
*qconf
;
334 lcore_id
= rte_lcore_id();
336 qconf
= &lcore_conf
[lcore_id
];
337 len
= qconf
->tx_mbufs
[port
].len
;
338 qconf
->tx_mbufs
[port
].m_table
[len
] = m
;
341 /* enough pkts to be sent */
342 if (unlikely(len
== MAX_PKT_BURST
)) {
343 send_burst(qconf
, MAX_PKT_BURST
, port
);
347 qconf
->tx_mbufs
[port
].len
= len
;
351 #ifdef DO_RFC_1812_CHECKS
353 is_valid_ipv4_pkt(struct ipv4_hdr
*pkt
, uint32_t link_len
)
355 /* From http://www.rfc-editor.org/rfc/rfc1812.txt section 5.2.2 */
357 * 1. The packet length reported by the Link Layer must be large
358 * enough to hold the minimum length legal IP datagram (20 bytes).
360 if (link_len
< sizeof(struct ipv4_hdr
))
363 /* 2. The IP checksum must be correct. */
364 /* this is checked in H/W */
367 * 3. The IP version number must be 4. If the version number is not 4
368 * then the packet may be another version of IP, such as IPng or
371 if (((pkt
->version_ihl
) >> 4) != 4)
374 * 4. The IP header length field must be large enough to hold the
375 * minimum length legal IP datagram (20 bytes = 5 words).
377 if ((pkt
->version_ihl
& 0xf) < 5)
381 * 5. The IP total length field must be large enough to hold the IP
382 * datagram header, whose length is specified in the IP header length
385 if (rte_cpu_to_be_16(pkt
->total_length
) < sizeof(struct ipv4_hdr
))
392 #if (APP_LOOKUP_METHOD == APP_LOOKUP_EXACT_MATCH)
394 print_key(struct ipv4_5tuple key
)
396 printf("IP dst = %08x, IP src = %08x, port dst = %d, port src = %d, proto = %d\n",
397 (unsigned)key
.ip_dst
, (unsigned)key
.ip_src
, key
.port_dst
, key
.port_src
, key
.proto
);
400 static inline uint8_t
401 get_dst_port(struct ipv4_hdr
*ipv4_hdr
, uint8_t portid
, lookup_struct_t
* l3fwd_lookup_struct
)
403 struct ipv4_5tuple key
;
408 key
.ip_dst
= rte_be_to_cpu_32(ipv4_hdr
->dst_addr
);
409 key
.ip_src
= rte_be_to_cpu_32(ipv4_hdr
->src_addr
);
410 key
.proto
= ipv4_hdr
->next_proto_id
;
412 switch (ipv4_hdr
->next_proto_id
) {
414 tcp
= (struct tcp_hdr
*)((unsigned char *) ipv4_hdr
+
415 sizeof(struct ipv4_hdr
));
416 key
.port_dst
= rte_be_to_cpu_16(tcp
->dst_port
);
417 key
.port_src
= rte_be_to_cpu_16(tcp
->src_port
);
421 udp
= (struct udp_hdr
*)((unsigned char *) ipv4_hdr
+
422 sizeof(struct ipv4_hdr
));
423 key
.port_dst
= rte_be_to_cpu_16(udp
->dst_port
);
424 key
.port_src
= rte_be_to_cpu_16(udp
->src_port
);
432 /* Find destination port */
433 ret
= rte_hash_lookup(l3fwd_lookup_struct
, (const void *)&key
);
434 return (uint8_t)((ret
< 0)? portid
: l3fwd_out_if
[ret
]);
438 #if (APP_LOOKUP_METHOD == APP_LOOKUP_LPM)
439 static inline uint8_t
440 get_dst_port(struct ipv4_hdr
*ipv4_hdr
, uint8_t portid
, lookup_struct_t
* l3fwd_lookup_struct
)
444 return (uint8_t) ((rte_lpm_lookup(l3fwd_lookup_struct
,
445 rte_be_to_cpu_32(ipv4_hdr
->dst_addr
), &next_hop
) == 0)?
451 l3fwd_simple_forward(struct rte_mbuf
*m
, uint8_t portid
, lookup_struct_t
* l3fwd_lookup_struct
)
453 struct ether_hdr
*eth_hdr
;
454 struct ipv4_hdr
*ipv4_hdr
;
458 eth_hdr
= rte_pktmbuf_mtod(m
, struct ether_hdr
*);
460 ipv4_hdr
= rte_pktmbuf_mtod_offset(m
, struct ipv4_hdr
*,
461 sizeof(struct ether_hdr
));
463 #ifdef DO_RFC_1812_CHECKS
464 /* Check to make sure the packet is valid (RFC1812) */
465 if (is_valid_ipv4_pkt(ipv4_hdr
, m
->pkt_len
) < 0) {
471 dst_port
= get_dst_port(ipv4_hdr
, portid
, l3fwd_lookup_struct
);
472 if (dst_port
>= RTE_MAX_ETHPORTS
|| (enabled_port_mask
& 1 << dst_port
) == 0)
475 /* 02:00:00:00:00:xx */
476 tmp
= ð_hdr
->d_addr
.addr_bytes
[0];
477 *((uint64_t *)tmp
) = 0x000000000002 + ((uint64_t)dst_port
<< 40);
479 #ifdef DO_RFC_1812_CHECKS
480 /* Update time to live and header checksum */
481 --(ipv4_hdr
->time_to_live
);
482 ++(ipv4_hdr
->hdr_checksum
);
486 ether_addr_copy(&ports_eth_addr
[dst_port
], ð_hdr
->s_addr
);
488 send_single_packet(m
, dst_port
);
492 /* main processing loop */
494 main_loop(__attribute__((unused
)) void *dummy
)
496 struct rte_mbuf
*pkts_burst
[MAX_PKT_BURST
];
498 uint64_t prev_tsc
, diff_tsc
, cur_tsc
;
500 uint8_t portid
, queueid
;
501 struct lcore_conf
*qconf
;
502 const uint64_t drain_tsc
= (rte_get_tsc_hz() + US_PER_S
- 1) / US_PER_S
* BURST_TX_DRAIN_US
;
506 lcore_id
= rte_lcore_id();
507 qconf
= &lcore_conf
[lcore_id
];
509 if (qconf
->n_rx_queue
== 0) {
510 RTE_LOG(INFO
, L3FWD
, "lcore %u has nothing to do\n", lcore_id
);
514 RTE_LOG(INFO
, L3FWD
, "entering main loop on lcore %u\n", lcore_id
);
516 for (i
= 0; i
< qconf
->n_rx_queue
; i
++) {
518 portid
= qconf
->rx_queue_list
[i
].port_id
;
519 queueid
= qconf
->rx_queue_list
[i
].queue_id
;
520 RTE_LOG(INFO
, L3FWD
, " -- lcoreid=%u portid=%hhu rxqueueid=%hhu\n", lcore_id
,
526 cur_tsc
= rte_rdtsc();
529 * TX burst queue drain
531 diff_tsc
= cur_tsc
- prev_tsc
;
532 if (unlikely(diff_tsc
> drain_tsc
)) {
535 * This could be optimized (use queueid instead of
536 * portid), but it is not called so often
538 for (portid
= 0; portid
< RTE_MAX_ETHPORTS
; portid
++) {
539 if (qconf
->tx_mbufs
[portid
].len
== 0)
541 send_burst(&lcore_conf
[lcore_id
],
542 qconf
->tx_mbufs
[portid
].len
,
544 qconf
->tx_mbufs
[portid
].len
= 0;
551 * Read packet from RX queues
553 for (i
= 0; i
< qconf
->n_rx_queue
; ++i
) {
555 portid
= qconf
->rx_queue_list
[i
].port_id
;
556 queueid
= qconf
->rx_queue_list
[i
].queue_id
;
557 nb_rx
= rte_eth_rx_burst(portid
, queueid
, pkts_burst
, MAX_PKT_BURST
);
559 /* Prefetch first packets */
560 for (j
= 0; j
< PREFETCH_OFFSET
&& j
< nb_rx
; j
++) {
561 rte_prefetch0(rte_pktmbuf_mtod(
562 pkts_burst
[j
], void *));
565 /* Prefetch and forward already prefetched packets */
566 for (j
= 0; j
< (nb_rx
- PREFETCH_OFFSET
); j
++) {
567 rte_prefetch0(rte_pktmbuf_mtod(pkts_burst
[
568 j
+ PREFETCH_OFFSET
], void *));
569 l3fwd_simple_forward(pkts_burst
[j
], portid
, qconf
->lookup_struct
);
572 /* Forward remaining prefetched packets */
573 for (; j
< nb_rx
; j
++) {
574 l3fwd_simple_forward(pkts_burst
[j
], portid
, qconf
->lookup_struct
);
581 check_lcore_params(void)
583 uint8_t queue
, lcore
;
587 for (i
= 0; i
< nb_lcore_params
; ++i
) {
588 queue
= lcore_params
[i
].queue_id
;
589 if (queue
>= MAX_RX_QUEUE_PER_PORT
) {
590 printf("invalid queue number: %hhu\n", queue
);
593 lcore
= lcore_params
[i
].lcore_id
;
594 if (!rte_lcore_is_enabled(lcore
)) {
595 printf("error: lcore %hhu is not enabled in lcore mask\n", lcore
);
598 if ((socketid
= rte_lcore_to_socket_id(lcore
) != 0) &&
600 printf("warning: lcore %hhu is on socket %d with numa off \n",
608 check_port_config(const unsigned nb_ports
)
613 for (i
= 0; i
< nb_lcore_params
; ++i
) {
614 portid
= lcore_params
[i
].port_id
;
615 if ((enabled_port_mask
& (1 << portid
)) == 0) {
616 printf("port %u is not enabled in port mask\n", portid
);
619 if (portid
>= nb_ports
) {
620 printf("port %u is not present on the board\n", portid
);
628 get_port_n_rx_queues(const uint8_t port
)
633 for (i
= 0; i
< nb_lcore_params
; ++i
) {
634 if (lcore_params
[i
].port_id
== port
&& lcore_params
[i
].queue_id
> queue
)
635 queue
= lcore_params
[i
].queue_id
;
637 return (uint8_t)(++queue
);
641 init_lcore_rx_queues(void)
643 uint16_t i
, nb_rx_queue
;
646 for (i
= 0; i
< nb_lcore_params
; ++i
) {
647 lcore
= lcore_params
[i
].lcore_id
;
648 nb_rx_queue
= lcore_conf
[lcore
].n_rx_queue
;
649 if (nb_rx_queue
>= MAX_RX_QUEUE_PER_LCORE
) {
650 printf("error: too many queues (%u) for lcore: %u\n",
651 (unsigned)nb_rx_queue
+ 1, (unsigned)lcore
);
654 lcore_conf
[lcore
].rx_queue_list
[nb_rx_queue
].port_id
=
655 lcore_params
[i
].port_id
;
656 lcore_conf
[lcore
].rx_queue_list
[nb_rx_queue
].queue_id
=
657 lcore_params
[i
].queue_id
;
658 lcore_conf
[lcore
].n_rx_queue
++;
666 print_usage(const char *prgname
)
668 printf ("%s [EAL options] -- -p PORTMASK"
669 " [--config (port,queue,lcore)[,(port,queue,lcore]]\n"
670 " -p PORTMASK: hexadecimal bitmask of ports to configure\n"
671 " --config (port,queue,lcore): rx queues configuration\n"
672 " --no-numa: optional, disable numa awareness\n",
676 /* Custom handling of signals to handle process terminal */
678 signal_handler(int signum
)
681 uint8_t nb_ports
= rte_eth_dev_count();
683 /* When we receive a SIGINT signal */
684 if (signum
== SIGINT
) {
685 for (portid
= 0; portid
< nb_ports
; portid
++) {
686 /* skip ports that are not enabled */
687 if ((enabled_port_mask
& (1 << portid
)) == 0)
689 rte_eth_dev_close(portid
);
692 rte_exit(EXIT_SUCCESS
, "\n User forced exit\n");
695 parse_portmask(const char *portmask
)
700 /* parse hexadecimal string */
701 pm
= strtoul(portmask
, &end
, 16);
702 if ((portmask
[0] == '\0') || (end
== NULL
) || (*end
!= '\0'))
712 parse_config(const char *q_arg
)
715 const char *p
, *p0
= q_arg
;
723 unsigned long int_fld
[_NUM_FLD
];
724 char *str_fld
[_NUM_FLD
];
730 while ((p
= strchr(p0
,'(')) != NULL
) {
732 if((p0
= strchr(p
,')')) == NULL
)
736 if(size
>= sizeof(s
))
739 snprintf(s
, sizeof(s
), "%.*s", size
, p
);
740 if (rte_strsplit(s
, sizeof(s
), str_fld
, _NUM_FLD
, ',') != _NUM_FLD
)
742 for (i
= 0; i
< _NUM_FLD
; i
++){
744 int_fld
[i
] = strtoul(str_fld
[i
], &end
, 0);
745 if (errno
!= 0 || end
== str_fld
[i
] || int_fld
[i
] > 255)
748 if (nb_lcore_params
>= MAX_LCORE_PARAMS
) {
749 printf("exceeded max number of lcore params: %hu\n",
753 lcore_params_array
[nb_lcore_params
].port_id
= (uint8_t)int_fld
[FLD_PORT
];
754 lcore_params_array
[nb_lcore_params
].queue_id
= (uint8_t)int_fld
[FLD_QUEUE
];
755 lcore_params_array
[nb_lcore_params
].lcore_id
= (uint8_t)int_fld
[FLD_LCORE
];
758 lcore_params
= lcore_params_array
;
762 /* Parse the argument given in the command line of the application */
764 parse_args(int argc
, char **argv
)
769 char *prgname
= argv
[0];
770 static struct option lgopts
[] = {
772 {"no-numa", 0, 0, 0},
778 while ((opt
= getopt_long(argc
, argvopt
, "p:",
779 lgopts
, &option_index
)) != EOF
) {
784 enabled_port_mask
= parse_portmask(optarg
);
785 if (enabled_port_mask
== 0) {
786 printf("invalid portmask\n");
787 print_usage(prgname
);
794 if (!strcmp(lgopts
[option_index
].name
, "config")) {
795 ret
= parse_config(optarg
);
797 printf("invalid config\n");
798 print_usage(prgname
);
803 if (!strcmp(lgopts
[option_index
].name
, "no-numa")) {
804 printf("numa is disabled \n");
810 print_usage(prgname
);
816 argv
[optind
-1] = prgname
;
819 optind
= 0; /* reset getopt lib */
824 print_ethaddr(const char *name
, const struct ether_addr
*eth_addr
)
826 char buf
[ETHER_ADDR_FMT_SIZE
];
827 ether_format_addr(buf
, ETHER_ADDR_FMT_SIZE
, eth_addr
);
828 printf("%s%s", name
, buf
);
831 #if (APP_LOOKUP_METHOD == APP_LOOKUP_EXACT_MATCH)
833 setup_hash(int socketid
)
840 snprintf(s
, sizeof(s
), "l3fwd_hash_%d", socketid
);
841 l3fwd_hash_params
.name
= s
;
842 l3fwd_hash_params
.socket_id
= socketid
;
843 l3fwd_lookup_struct
[socketid
] = rte_hash_create(&l3fwd_hash_params
);
844 if (l3fwd_lookup_struct
[socketid
] == NULL
)
845 rte_exit(EXIT_FAILURE
, "Unable to create the l3fwd hash on "
846 "socket %d\n", socketid
);
848 /* populate the hash */
849 for (i
= 0; i
< L3FWD_NUM_ROUTES
; i
++) {
850 ret
= rte_hash_add_key (l3fwd_lookup_struct
[socketid
],
851 (void *) &l3fwd_route_array
[i
].key
);
853 rte_exit(EXIT_FAILURE
, "Unable to add entry %u to the"
854 "l3fwd hash on socket %d\n", i
, socketid
);
856 l3fwd_out_if
[ret
] = l3fwd_route_array
[i
].if_out
;
857 printf("Hash: Adding key\n");
858 print_key(l3fwd_route_array
[i
].key
);
863 #if (APP_LOOKUP_METHOD == APP_LOOKUP_LPM)
865 setup_lpm(int socketid
)
871 struct rte_lpm_config lpm_ipv4_config
;
873 lpm_ipv4_config
.max_rules
= L3FWD_LPM_MAX_RULES
;
874 lpm_ipv4_config
.number_tbl8s
= 256;
875 lpm_ipv4_config
.flags
= 0;
877 /* create the LPM table */
878 snprintf(s
, sizeof(s
), "L3FWD_LPM_%d", socketid
);
879 l3fwd_lookup_struct
[socketid
] =
880 rte_lpm_create(s
, socketid
, &lpm_ipv4_config
);
881 if (l3fwd_lookup_struct
[socketid
] == NULL
)
882 rte_exit(EXIT_FAILURE
, "Unable to create the l3fwd LPM table"
883 " on socket %d\n", socketid
);
885 /* populate the LPM table */
886 for (i
= 0; i
< L3FWD_NUM_ROUTES
; i
++) {
887 ret
= rte_lpm_add(l3fwd_lookup_struct
[socketid
],
888 l3fwd_route_array
[i
].ip
,
889 l3fwd_route_array
[i
].depth
,
890 l3fwd_route_array
[i
].if_out
);
893 rte_exit(EXIT_FAILURE
, "Unable to add entry %u to the "
894 "l3fwd LPM table on socket %d\n",
898 printf("LPM: Adding route 0x%08x / %d (%d)\n",
899 (unsigned)l3fwd_route_array
[i
].ip
,
900 l3fwd_route_array
[i
].depth
,
901 l3fwd_route_array
[i
].if_out
);
907 init_mem(unsigned nb_mbuf
)
909 struct lcore_conf
*qconf
;
914 for (lcore_id
= 0; lcore_id
< RTE_MAX_LCORE
; lcore_id
++) {
915 if (rte_lcore_is_enabled(lcore_id
) == 0)
919 socketid
= rte_lcore_to_socket_id(lcore_id
);
923 if (socketid
>= NB_SOCKETS
) {
924 rte_exit(EXIT_FAILURE
, "Socket %d of lcore %u is out of range %d\n",
925 socketid
, lcore_id
, NB_SOCKETS
);
927 if (pktmbuf_pool
[socketid
] == NULL
) {
928 snprintf(s
, sizeof(s
), "mbuf_pool_%d", socketid
);
929 pktmbuf_pool
[socketid
] = rte_pktmbuf_pool_create(s
,
930 nb_mbuf
, MEMPOOL_CACHE_SIZE
, 0,
931 RTE_MBUF_DEFAULT_BUF_SIZE
, socketid
);
932 if (pktmbuf_pool
[socketid
] == NULL
)
933 rte_exit(EXIT_FAILURE
, "Cannot init mbuf pool on socket %d\n", socketid
);
935 printf("Allocated mbuf pool on socket %d\n", socketid
);
937 #if (APP_LOOKUP_METHOD == APP_LOOKUP_LPM)
940 setup_hash(socketid
);
943 qconf
= &lcore_conf
[lcore_id
];
944 qconf
->lookup_struct
= l3fwd_lookup_struct
[socketid
];
950 main(int argc
, char **argv
)
952 struct lcore_conf
*qconf
;
953 struct rte_eth_dev_info dev_info
;
954 struct rte_eth_txconf
*txconf
;
961 uint8_t portid
, nb_rx_queue
, queue
, socketid
;
963 signal(SIGINT
, signal_handler
);
965 ret
= rte_eal_init(argc
, argv
);
967 rte_exit(EXIT_FAILURE
, "Invalid EAL parameters\n");
971 /* parse application arguments (after the EAL ones) */
972 ret
= parse_args(argc
, argv
);
974 rte_exit(EXIT_FAILURE
, "Invalid L3FWD-VF parameters\n");
976 if (check_lcore_params() < 0)
977 rte_exit(EXIT_FAILURE
, "check_lcore_params failed\n");
979 ret
= init_lcore_rx_queues();
981 rte_exit(EXIT_FAILURE
, "init_lcore_rx_queues failed\n");
983 nb_ports
= rte_eth_dev_count();
985 if (check_port_config(nb_ports
) < 0)
986 rte_exit(EXIT_FAILURE
, "check_port_config failed\n");
988 nb_lcores
= rte_lcore_count();
990 /* initialize all ports */
991 for (portid
= 0; portid
< nb_ports
; portid
++) {
992 /* skip ports that are not enabled */
993 if ((enabled_port_mask
& (1 << portid
)) == 0) {
994 printf("\nSkipping disabled port %d\n", portid
);
999 printf("Initializing port %d ... ", portid
);
1002 /* must always equal(=1) */
1003 nb_rx_queue
= get_port_n_rx_queues(portid
);
1004 n_tx_queue
= MAX_TX_QUEUE_PER_PORT
;
1006 printf("Creating queues: nb_rxq=%d nb_txq=%u... ",
1007 nb_rx_queue
, (unsigned)1 );
1008 ret
= rte_eth_dev_configure(portid
, nb_rx_queue
, n_tx_queue
, &port_conf
);
1010 rte_exit(EXIT_FAILURE
, "Cannot configure device: err=%d, port=%d\n",
1013 rte_eth_macaddr_get(portid
, &ports_eth_addr
[portid
]);
1014 print_ethaddr(" Address:", &ports_eth_addr
[portid
]);
1017 ret
= init_mem(NB_MBUF
);
1019 rte_exit(EXIT_FAILURE
, "init_mem failed\n");
1021 /* init one TX queue */
1022 socketid
= (uint8_t)rte_lcore_to_socket_id(rte_get_master_lcore());
1024 printf("txq=%d,%d,%d ", portid
, 0, socketid
);
1027 rte_eth_dev_info_get(portid
, &dev_info
);
1028 txconf
= &dev_info
.default_txconf
;
1029 if (port_conf
.rxmode
.jumbo_frame
)
1030 txconf
->txq_flags
= 0;
1031 ret
= rte_eth_tx_queue_setup(portid
, 0, nb_txd
,
1034 rte_exit(EXIT_FAILURE
, "rte_eth_tx_queue_setup: err=%d, "
1035 "port=%d\n", ret
, portid
);
1040 for (lcore_id
= 0; lcore_id
< RTE_MAX_LCORE
; lcore_id
++) {
1041 if (rte_lcore_is_enabled(lcore_id
) == 0)
1043 qconf
= &lcore_conf
[lcore_id
];
1044 qconf
->tx_queue_id
= 0;
1046 printf("\nInitializing rx queues on lcore %u ... ", lcore_id
);
1048 /* init RX queues */
1049 for(queue
= 0; queue
< qconf
->n_rx_queue
; ++queue
) {
1050 portid
= qconf
->rx_queue_list
[queue
].port_id
;
1051 queueid
= qconf
->rx_queue_list
[queue
].queue_id
;
1054 socketid
= (uint8_t)rte_lcore_to_socket_id(lcore_id
);
1058 printf("rxq=%d,%d,%d ", portid
, queueid
, socketid
);
1061 ret
= rte_eth_rx_queue_setup(portid
, queueid
, nb_rxd
,
1063 pktmbuf_pool
[socketid
]);
1065 rte_exit(EXIT_FAILURE
, "rte_eth_rx_queue_setup: err=%d,"
1066 "port=%d\n", ret
, portid
);
1072 for (portid
= 0; portid
< nb_ports
; portid
++) {
1073 if ((enabled_port_mask
& (1 << portid
)) == 0) {
1077 ret
= rte_eth_dev_start(portid
);
1079 rte_exit(EXIT_FAILURE
, "rte_eth_dev_start: err=%d, port=%d\n",
1082 printf("done: Port %d\n", portid
);
1086 /* launch per-lcore init on every lcore */
1087 rte_eal_mp_remote_launch(main_loop
, NULL
, CALL_MASTER
);
1088 RTE_LCORE_FOREACH_SLAVE(lcore_id
) {
1089 if (rte_eal_wait_lcore(lcore_id
) < 0)