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>
45 #include <sys/param.h>
47 #include <rte_common.h>
48 #include <rte_byteorder.h>
50 #include <rte_memory.h>
51 #include <rte_memcpy.h>
52 #include <rte_memzone.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>
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>
70 #include <rte_malloc.h>
74 #include <rte_string_fns.h>
78 #include <rte_ip_frag.h>
80 #define MAX_PKT_BURST 32
83 #define RTE_LOGTYPE_IP_RSMBL RTE_LOGTYPE_USER1
85 #define MAX_JUMBO_PKT_LEN 9600
87 #define BUF_SIZE RTE_MBUF_DEFAULT_DATAROOM
89 (BUF_SIZE + sizeof(struct rte_mbuf) + RTE_PKTMBUF_HEADROOM)
93 /* allow max jumbo frame 9.5 KB */
94 #define JUMBO_FRAME_MAX_SIZE 0x2600
96 #define MAX_FLOW_NUM UINT16_MAX
97 #define MIN_FLOW_NUM 1
98 #define DEF_FLOW_NUM 0x1000
100 /* TTL numbers are in ms. */
101 #define MAX_FLOW_TTL (3600 * MS_PER_S)
102 #define MIN_FLOW_TTL 1
103 #define DEF_FLOW_TTL MS_PER_S
105 #define MAX_FRAG_NUM RTE_LIBRTE_IP_FRAG_MAX_FRAG
107 /* Should be power of two. */
108 #define IP_FRAG_TBL_BUCKET_ENTRIES 16
110 static uint32_t max_flow_num
= DEF_FLOW_NUM
;
111 static uint32_t max_flow_ttl
= DEF_FLOW_TTL
;
113 #define BURST_TX_DRAIN_US 100 /* TX drain every ~100us */
117 /* Configure how many packets ahead to prefetch, when reading packets */
118 #define PREFETCH_OFFSET 3
121 * Configurable number of RX/TX ring descriptors
123 #define RTE_TEST_RX_DESC_DEFAULT 128
124 #define RTE_TEST_TX_DESC_DEFAULT 512
126 static uint16_t nb_rxd
= RTE_TEST_RX_DESC_DEFAULT
;
127 static uint16_t nb_txd
= RTE_TEST_TX_DESC_DEFAULT
;
129 /* ethernet addresses of ports */
130 static struct ether_addr ports_eth_addr
[RTE_MAX_ETHPORTS
];
133 #define IPv4_BYTES_FMT "%" PRIu8 ".%" PRIu8 ".%" PRIu8 ".%" PRIu8
134 #define IPv4_BYTES(addr) \
135 (uint8_t) (((addr) >> 24) & 0xFF),\
136 (uint8_t) (((addr) >> 16) & 0xFF),\
137 (uint8_t) (((addr) >> 8) & 0xFF),\
138 (uint8_t) ((addr) & 0xFF)
142 #define IPv6_BYTES_FMT "%02x%02x:%02x%02x:%02x%02x:%02x%02x:"\
143 "%02x%02x:%02x%02x:%02x%02x:%02x%02x"
144 #define IPv6_BYTES(addr) \
145 addr[0], addr[1], addr[2], addr[3], \
146 addr[4], addr[5], addr[6], addr[7], \
147 addr[8], addr[9], addr[10], addr[11],\
148 addr[12], addr[13],addr[14], addr[15]
151 #define IPV6_ADDR_LEN 16
153 /* mask of enabled ports */
154 static uint32_t enabled_port_mask
= 0;
156 static int rx_queue_per_lcore
= 1;
162 struct rte_mbuf
*m_table
[0];
166 struct rte_ip_frag_tbl
*frag_tbl
;
167 struct rte_mempool
*pool
;
169 struct rte_lpm6
*lpm6
;
173 struct tx_lcore_stat
{
180 #define MAX_RX_QUEUE_PER_LCORE 16
181 #define MAX_TX_QUEUE_PER_PORT 16
182 #define MAX_RX_QUEUE_PER_PORT 128
184 struct lcore_queue_conf
{
186 struct rx_queue rx_queue_list
[MAX_RX_QUEUE_PER_LCORE
];
187 uint16_t tx_queue_id
[RTE_MAX_ETHPORTS
];
188 struct rte_ip_frag_death_row death_row
;
189 struct mbuf_table
*tx_mbufs
[RTE_MAX_ETHPORTS
];
190 struct tx_lcore_stat tx_stat
;
191 } __rte_cache_aligned
;
192 static struct lcore_queue_conf lcore_queue_conf
[RTE_MAX_LCORE
];
194 static struct rte_eth_conf port_conf
= {
196 .mq_mode
= ETH_MQ_RX_RSS
,
197 .max_rx_pkt_len
= JUMBO_FRAME_MAX_SIZE
,
199 .header_split
= 0, /**< Header Split disabled */
200 .hw_ip_checksum
= 1, /**< IP checksum offload enabled */
201 .hw_vlan_filter
= 0, /**< VLAN filtering disabled */
202 .jumbo_frame
= 1, /**< Jumbo Frame Support disabled */
203 .hw_strip_crc
= 0, /**< CRC stripped by hardware */
208 .rss_hf
= ETH_RSS_IP
,
212 .mq_mode
= ETH_MQ_TX_NONE
,
217 * IPv4 forwarding table
219 struct l3fwd_ipv4_route
{
225 struct l3fwd_ipv4_route l3fwd_ipv4_route_array
[] = {
226 {IPv4(100,10,0,0), 16, 0},
227 {IPv4(100,20,0,0), 16, 1},
228 {IPv4(100,30,0,0), 16, 2},
229 {IPv4(100,40,0,0), 16, 3},
230 {IPv4(100,50,0,0), 16, 4},
231 {IPv4(100,60,0,0), 16, 5},
232 {IPv4(100,70,0,0), 16, 6},
233 {IPv4(100,80,0,0), 16, 7},
237 * IPv6 forwarding table
240 struct l3fwd_ipv6_route
{
241 uint8_t ip
[IPV6_ADDR_LEN
];
246 static struct l3fwd_ipv6_route l3fwd_ipv6_route_array
[] = {
247 {{1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1}, 48, 0},
248 {{2,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1}, 48, 1},
249 {{3,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1}, 48, 2},
250 {{4,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1}, 48, 3},
251 {{5,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1}, 48, 4},
252 {{6,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1}, 48, 5},
253 {{7,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1}, 48, 6},
254 {{8,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1}, 48, 7},
257 #define LPM_MAX_RULES 1024
258 #define LPM6_MAX_RULES 1024
259 #define LPM6_NUMBER_TBL8S (1 << 16)
261 struct rte_lpm6_config lpm6_config
= {
262 .max_rules
= LPM6_MAX_RULES
,
263 .number_tbl8s
= LPM6_NUMBER_TBL8S
,
267 static struct rte_lpm
*socket_lpm
[RTE_MAX_NUMA_NODES
];
268 static struct rte_lpm6
*socket_lpm6
[RTE_MAX_NUMA_NODES
];
270 #ifdef RTE_LIBRTE_IP_FRAG_TBL_STAT
271 #define TX_LCORE_STAT_UPDATE(s, f, v) ((s)->f += (v))
273 #define TX_LCORE_STAT_UPDATE(s, f, v) do {} while (0)
274 #endif /* RTE_LIBRTE_IP_FRAG_TBL_STAT */
277 * If number of queued packets reached given threahold, then
278 * send burst of packets on an output interface.
280 static inline uint32_t
281 send_burst(struct lcore_queue_conf
*qconf
, uint32_t thresh
, uint8_t port
)
283 uint32_t fill
, len
, k
, n
;
284 struct mbuf_table
*txmb
;
286 txmb
= qconf
->tx_mbufs
[port
];
289 if ((int32_t)(fill
= txmb
->head
- txmb
->tail
) < 0)
292 if (fill
>= thresh
) {
293 n
= RTE_MIN(len
- txmb
->tail
, fill
);
295 k
= rte_eth_tx_burst(port
, qconf
->tx_queue_id
[port
],
296 txmb
->m_table
+ txmb
->tail
, (uint16_t)n
);
298 TX_LCORE_STAT_UPDATE(&qconf
->tx_stat
, call
, 1);
299 TX_LCORE_STAT_UPDATE(&qconf
->tx_stat
, send
, k
);
302 if ((txmb
->tail
+= k
) == len
)
309 /* Enqueue a single packet, and send burst if queue is filled */
311 send_single_packet(struct rte_mbuf
*m
, uint8_t port
)
313 uint32_t fill
, lcore_id
, len
;
314 struct lcore_queue_conf
*qconf
;
315 struct mbuf_table
*txmb
;
317 lcore_id
= rte_lcore_id();
318 qconf
= &lcore_queue_conf
[lcore_id
];
320 txmb
= qconf
->tx_mbufs
[port
];
323 fill
= send_burst(qconf
, MAX_PKT_BURST
, port
);
325 if (fill
== len
- 1) {
326 TX_LCORE_STAT_UPDATE(&qconf
->tx_stat
, drop
, 1);
327 rte_pktmbuf_free(txmb
->m_table
[txmb
->tail
]);
328 if (++txmb
->tail
== len
)
332 TX_LCORE_STAT_UPDATE(&qconf
->tx_stat
, queue
, 1);
333 txmb
->m_table
[txmb
->head
] = m
;
334 if(++txmb
->head
== len
)
341 reassemble(struct rte_mbuf
*m
, uint8_t portid
, uint32_t queue
,
342 struct lcore_queue_conf
*qconf
, uint64_t tms
)
344 struct ether_hdr
*eth_hdr
;
345 struct rte_ip_frag_tbl
*tbl
;
346 struct rte_ip_frag_death_row
*dr
;
347 struct rx_queue
*rxq
;
349 uint32_t next_hop_ipv4
;
350 uint8_t next_hop_ipv6
, dst_port
;
352 rxq
= &qconf
->rx_queue_list
[queue
];
354 eth_hdr
= rte_pktmbuf_mtod(m
, struct ether_hdr
*);
358 /* if packet is IPv4 */
359 if (RTE_ETH_IS_IPV4_HDR(m
->packet_type
)) {
360 struct ipv4_hdr
*ip_hdr
;
363 ip_hdr
= (struct ipv4_hdr
*)(eth_hdr
+ 1);
365 /* if it is a fragmented packet, then try to reassemble. */
366 if (rte_ipv4_frag_pkt_is_fragmented(ip_hdr
)) {
370 dr
= &qconf
->death_row
;
372 /* prepare mbuf: setup l2_len/l3_len. */
373 m
->l2_len
= sizeof(*eth_hdr
);
374 m
->l3_len
= sizeof(*ip_hdr
);
376 /* process this fragment. */
377 mo
= rte_ipv4_frag_reassemble_packet(tbl
, dr
, m
, tms
, ip_hdr
);
379 /* no packet to send out. */
382 /* we have our packet reassembled. */
385 eth_hdr
= rte_pktmbuf_mtod(m
,
387 ip_hdr
= (struct ipv4_hdr
*)(eth_hdr
+ 1);
390 ip_dst
= rte_be_to_cpu_32(ip_hdr
->dst_addr
);
392 /* Find destination port */
393 if (rte_lpm_lookup(rxq
->lpm
, ip_dst
, &next_hop_ipv4
) == 0 &&
394 (enabled_port_mask
& 1 << next_hop_ipv4
) != 0) {
395 dst_port
= next_hop_ipv4
;
398 eth_hdr
->ether_type
= rte_be_to_cpu_16(ETHER_TYPE_IPv4
);
399 } else if (RTE_ETH_IS_IPV6_HDR(m
->packet_type
)) {
400 /* if packet is IPv6 */
401 struct ipv6_extension_fragment
*frag_hdr
;
402 struct ipv6_hdr
*ip_hdr
;
404 ip_hdr
= (struct ipv6_hdr
*)(eth_hdr
+ 1);
406 frag_hdr
= rte_ipv6_frag_get_ipv6_fragment_header(ip_hdr
);
408 if (frag_hdr
!= NULL
) {
412 dr
= &qconf
->death_row
;
414 /* prepare mbuf: setup l2_len/l3_len. */
415 m
->l2_len
= sizeof(*eth_hdr
);
416 m
->l3_len
= sizeof(*ip_hdr
) + sizeof(*frag_hdr
);
418 mo
= rte_ipv6_frag_reassemble_packet(tbl
, dr
, m
, tms
, ip_hdr
, frag_hdr
);
424 eth_hdr
= rte_pktmbuf_mtod(m
, struct ether_hdr
*);
425 ip_hdr
= (struct ipv6_hdr
*)(eth_hdr
+ 1);
429 /* Find destination port */
430 if (rte_lpm6_lookup(rxq
->lpm6
, ip_hdr
->dst_addr
, &next_hop_ipv6
) == 0 &&
431 (enabled_port_mask
& 1 << next_hop_ipv6
) != 0) {
432 dst_port
= next_hop_ipv6
;
435 eth_hdr
->ether_type
= rte_be_to_cpu_16(ETHER_TYPE_IPv6
);
437 /* if packet wasn't IPv4 or IPv6, it's forwarded to the port it came from */
439 /* 02:00:00:00:00:xx */
440 d_addr_bytes
= ð_hdr
->d_addr
.addr_bytes
[0];
441 *((uint64_t *)d_addr_bytes
) = 0x000000000002 + ((uint64_t)dst_port
<< 40);
444 ether_addr_copy(&ports_eth_addr
[dst_port
], ð_hdr
->s_addr
);
446 send_single_packet(m
, dst_port
);
449 /* main processing loop */
451 main_loop(__attribute__((unused
)) void *dummy
)
453 struct rte_mbuf
*pkts_burst
[MAX_PKT_BURST
];
455 uint64_t diff_tsc
, cur_tsc
, prev_tsc
;
458 struct lcore_queue_conf
*qconf
;
459 const uint64_t drain_tsc
= (rte_get_tsc_hz() + US_PER_S
- 1) / US_PER_S
* BURST_TX_DRAIN_US
;
463 lcore_id
= rte_lcore_id();
464 qconf
= &lcore_queue_conf
[lcore_id
];
466 if (qconf
->n_rx_queue
== 0) {
467 RTE_LOG(INFO
, IP_RSMBL
, "lcore %u has nothing to do\n", lcore_id
);
471 RTE_LOG(INFO
, IP_RSMBL
, "entering main loop on lcore %u\n", lcore_id
);
473 for (i
= 0; i
< qconf
->n_rx_queue
; i
++) {
475 portid
= qconf
->rx_queue_list
[i
].portid
;
476 RTE_LOG(INFO
, IP_RSMBL
, " -- lcoreid=%u portid=%hhu\n", lcore_id
,
482 cur_tsc
= rte_rdtsc();
485 * TX burst queue drain
487 diff_tsc
= cur_tsc
- prev_tsc
;
488 if (unlikely(diff_tsc
> drain_tsc
)) {
491 * This could be optimized (use queueid instead of
492 * portid), but it is not called so often
494 for (portid
= 0; portid
< RTE_MAX_ETHPORTS
; portid
++) {
495 if ((enabled_port_mask
& (1 << portid
)) != 0)
496 send_burst(qconf
, 1, portid
);
503 * Read packet from RX queues
505 for (i
= 0; i
< qconf
->n_rx_queue
; ++i
) {
507 portid
= qconf
->rx_queue_list
[i
].portid
;
509 nb_rx
= rte_eth_rx_burst(portid
, 0, pkts_burst
,
512 /* Prefetch first packets */
513 for (j
= 0; j
< PREFETCH_OFFSET
&& j
< nb_rx
; j
++) {
514 rte_prefetch0(rte_pktmbuf_mtod(
515 pkts_burst
[j
], void *));
518 /* Prefetch and forward already prefetched packets */
519 for (j
= 0; j
< (nb_rx
- PREFETCH_OFFSET
); j
++) {
520 rte_prefetch0(rte_pktmbuf_mtod(pkts_burst
[
521 j
+ PREFETCH_OFFSET
], void *));
522 reassemble(pkts_burst
[j
], portid
,
526 /* Forward remaining prefetched packets */
527 for (; j
< nb_rx
; j
++) {
528 reassemble(pkts_burst
[j
], portid
,
532 rte_ip_frag_free_death_row(&qconf
->death_row
,
540 print_usage(const char *prgname
)
542 printf("%s [EAL options] -- -p PORTMASK [-q NQ]"
543 " [--max-pkt-len PKTLEN]"
544 " [--maxflows=<flows>] [--flowttl=<ttl>[(s|ms)]]\n"
545 " -p PORTMASK: hexadecimal bitmask of ports to configure\n"
546 " -q NQ: number of RX queues per lcore\n"
547 " --maxflows=<flows>: optional, maximum number of flows "
549 " --flowttl=<ttl>[(s|ms)]: optional, maximum TTL for each "
555 parse_flow_num(const char *str
, uint32_t min
, uint32_t max
, uint32_t *val
)
560 /* parse decimal string */
562 v
= strtoul(str
, &end
, 10);
563 if (errno
!= 0 || *end
!= '\0')
566 if (v
< min
|| v
> max
)
574 parse_flow_ttl(const char *str
, uint32_t min
, uint32_t max
, uint32_t *val
)
579 static const char frmt_sec
[] = "s";
580 static const char frmt_msec
[] = "ms";
582 /* parse decimal string */
584 v
= strtoul(str
, &end
, 10);
589 if (strncmp(frmt_sec
, end
, sizeof(frmt_sec
)) == 0)
591 else if (strncmp(frmt_msec
, end
, sizeof (frmt_msec
)) != 0)
595 if (v
< min
|| v
> max
)
603 parse_portmask(const char *portmask
)
608 /* parse hexadecimal string */
609 pm
= strtoul(portmask
, &end
, 16);
610 if ((portmask
[0] == '\0') || (end
== NULL
) || (*end
!= '\0'))
620 parse_nqueue(const char *q_arg
)
625 printf("%p\n", q_arg
);
627 /* parse hexadecimal string */
628 n
= strtoul(q_arg
, &end
, 10);
629 if ((q_arg
[0] == '\0') || (end
== NULL
) || (*end
!= '\0'))
633 if (n
>= MAX_RX_QUEUE_PER_LCORE
)
639 /* Parse the argument given in the command line of the application */
641 parse_args(int argc
, char **argv
)
646 char *prgname
= argv
[0];
647 static struct option lgopts
[] = {
648 {"max-pkt-len", 1, 0, 0},
649 {"maxflows", 1, 0, 0},
650 {"flowttl", 1, 0, 0},
656 while ((opt
= getopt_long(argc
, argvopt
, "p:q:",
657 lgopts
, &option_index
)) != EOF
) {
662 enabled_port_mask
= parse_portmask(optarg
);
663 if (enabled_port_mask
== 0) {
664 printf("invalid portmask\n");
665 print_usage(prgname
);
672 rx_queue_per_lcore
= parse_nqueue(optarg
);
673 if (rx_queue_per_lcore
< 0) {
674 printf("invalid queue number\n");
675 print_usage(prgname
);
682 if (!strncmp(lgopts
[option_index
].name
,
684 if ((ret
= parse_flow_num(optarg
, MIN_FLOW_NUM
,
686 &max_flow_num
)) != 0) {
687 printf("invalid value: \"%s\" for "
690 lgopts
[option_index
].name
);
691 print_usage(prgname
);
696 if (!strncmp(lgopts
[option_index
].name
, "flowttl", 7)) {
697 if ((ret
= parse_flow_ttl(optarg
, MIN_FLOW_TTL
,
699 &max_flow_ttl
)) != 0) {
700 printf("invalid value: \"%s\" for "
703 lgopts
[option_index
].name
);
704 print_usage(prgname
);
712 print_usage(prgname
);
718 argv
[optind
-1] = prgname
;
721 optind
= 0; /* reset getopt lib */
726 print_ethaddr(const char *name
, const struct ether_addr
*eth_addr
)
728 char buf
[ETHER_ADDR_FMT_SIZE
];
729 ether_format_addr(buf
, ETHER_ADDR_FMT_SIZE
, eth_addr
);
730 printf("%s%s", name
, buf
);
733 /* Check the link status of all ports in up to 9s, and print them finally */
735 check_all_ports_link_status(uint8_t port_num
, uint32_t port_mask
)
737 #define CHECK_INTERVAL 100 /* 100ms */
738 #define MAX_CHECK_TIME 90 /* 9s (90 * 100ms) in total */
739 uint8_t portid
, count
, all_ports_up
, print_flag
= 0;
740 struct rte_eth_link link
;
742 printf("\nChecking link status");
744 for (count
= 0; count
<= MAX_CHECK_TIME
; count
++) {
746 for (portid
= 0; portid
< port_num
; portid
++) {
747 if ((port_mask
& (1 << portid
)) == 0)
749 memset(&link
, 0, sizeof(link
));
750 rte_eth_link_get_nowait(portid
, &link
);
751 /* print link status if flag set */
752 if (print_flag
== 1) {
753 if (link
.link_status
)
754 printf("Port %d Link Up - speed %u "
755 "Mbps - %s\n", (uint8_t)portid
,
756 (unsigned)link
.link_speed
,
757 (link
.link_duplex
== ETH_LINK_FULL_DUPLEX
) ?
758 ("full-duplex") : ("half-duplex\n"));
760 printf("Port %d Link Down\n",
764 /* clear all_ports_up flag if any link down */
765 if (link
.link_status
== ETH_LINK_DOWN
) {
770 /* after finally printing all link status, get out */
774 if (all_ports_up
== 0) {
777 rte_delay_ms(CHECK_INTERVAL
);
780 /* set the print_flag if all ports up or timeout */
781 if (all_ports_up
== 1 || count
== (MAX_CHECK_TIME
- 1)) {
789 init_routing_table(void)
792 struct rte_lpm6
*lpm6
;
796 for (socket
= 0; socket
< RTE_MAX_NUMA_NODES
; socket
++) {
797 if (socket_lpm
[socket
]) {
798 lpm
= socket_lpm
[socket
];
799 /* populate the LPM table */
800 for (i
= 0; i
< RTE_DIM(l3fwd_ipv4_route_array
); i
++) {
801 ret
= rte_lpm_add(lpm
,
802 l3fwd_ipv4_route_array
[i
].ip
,
803 l3fwd_ipv4_route_array
[i
].depth
,
804 l3fwd_ipv4_route_array
[i
].if_out
);
807 RTE_LOG(ERR
, IP_RSMBL
, "Unable to add entry %i to the l3fwd "
812 RTE_LOG(INFO
, IP_RSMBL
, "Socket %i: adding route " IPv4_BYTES_FMT
815 IPv4_BYTES(l3fwd_ipv4_route_array
[i
].ip
),
816 l3fwd_ipv4_route_array
[i
].depth
,
817 l3fwd_ipv4_route_array
[i
].if_out
);
821 if (socket_lpm6
[socket
]) {
822 lpm6
= socket_lpm6
[socket
];
823 /* populate the LPM6 table */
824 for (i
= 0; i
< RTE_DIM(l3fwd_ipv6_route_array
); i
++) {
825 ret
= rte_lpm6_add(lpm6
,
826 l3fwd_ipv6_route_array
[i
].ip
,
827 l3fwd_ipv6_route_array
[i
].depth
,
828 l3fwd_ipv6_route_array
[i
].if_out
);
831 RTE_LOG(ERR
, IP_RSMBL
, "Unable to add entry %i to the l3fwd "
836 RTE_LOG(INFO
, IP_RSMBL
, "Socket %i: adding route " IPv6_BYTES_FMT
839 IPv6_BYTES(l3fwd_ipv6_route_array
[i
].ip
),
840 l3fwd_ipv6_route_array
[i
].depth
,
841 l3fwd_ipv6_route_array
[i
].if_out
);
849 setup_port_tbl(struct lcore_queue_conf
*qconf
, uint32_t lcore
, int socket
,
852 struct mbuf_table
*mtb
;
856 n
= RTE_MAX(max_flow_num
, 2UL * MAX_PKT_BURST
);
857 sz
= sizeof (*mtb
) + sizeof (mtb
->m_table
[0]) * n
;
859 if ((mtb
= rte_zmalloc_socket(__func__
, sz
, RTE_CACHE_LINE_SIZE
,
861 RTE_LOG(ERR
, IP_RSMBL
, "%s() for lcore: %u, port: %u "
862 "failed to allocate %zu bytes\n",
863 __func__
, lcore
, port
, sz
);
868 qconf
->tx_mbufs
[port
] = mtb
;
874 setup_queue_tbl(struct rx_queue
*rxq
, uint32_t lcore
, uint32_t queue
)
878 uint64_t frag_cycles
;
879 char buf
[RTE_MEMPOOL_NAMESIZE
];
881 socket
= rte_lcore_to_socket_id(lcore
);
882 if (socket
== SOCKET_ID_ANY
)
885 frag_cycles
= (rte_get_tsc_hz() + MS_PER_S
- 1) / MS_PER_S
*
888 if ((rxq
->frag_tbl
= rte_ip_frag_table_create(max_flow_num
,
889 IP_FRAG_TBL_BUCKET_ENTRIES
, max_flow_num
, frag_cycles
,
891 RTE_LOG(ERR
, IP_RSMBL
, "ip_frag_tbl_create(%u) on "
892 "lcore: %u for queue: %u failed\n",
893 max_flow_num
, lcore
, queue
);
898 * At any given moment up to <max_flow_num * (MAX_FRAG_NUM)>
899 * mbufs could be stored int the fragment table.
900 * Plus, each TX queue can hold up to <max_flow_num> packets.
903 nb_mbuf
= RTE_MAX(max_flow_num
, 2UL * MAX_PKT_BURST
) * MAX_FRAG_NUM
;
904 nb_mbuf
*= (port_conf
.rxmode
.max_rx_pkt_len
+ BUF_SIZE
- 1) / BUF_SIZE
;
905 nb_mbuf
*= 2; /* ipv4 and ipv6 */
906 nb_mbuf
+= RTE_TEST_RX_DESC_DEFAULT
+ RTE_TEST_TX_DESC_DEFAULT
;
908 nb_mbuf
= RTE_MAX(nb_mbuf
, (uint32_t)NB_MBUF
);
910 snprintf(buf
, sizeof(buf
), "mbuf_pool_%u_%u", lcore
, queue
);
912 if ((rxq
->pool
= rte_mempool_create(buf
, nb_mbuf
, MBUF_SIZE
, 0,
913 sizeof(struct rte_pktmbuf_pool_private
),
914 rte_pktmbuf_pool_init
, NULL
, rte_pktmbuf_init
, NULL
,
915 socket
, MEMPOOL_F_SP_PUT
| MEMPOOL_F_SC_GET
)) == NULL
) {
916 RTE_LOG(ERR
, IP_RSMBL
, "mempool_create(%s) failed", buf
);
928 struct rte_lpm6
*lpm6
;
929 struct rte_lpm_config lpm_config
;
933 /* traverse through lcores and initialize structures on each socket */
935 for (lcore_id
= 0; lcore_id
< RTE_MAX_LCORE
; lcore_id
++) {
937 if (rte_lcore_is_enabled(lcore_id
) == 0)
940 socket
= rte_lcore_to_socket_id(lcore_id
);
942 if (socket
== SOCKET_ID_ANY
)
945 if (socket_lpm
[socket
] == NULL
) {
946 RTE_LOG(INFO
, IP_RSMBL
, "Creating LPM table on socket %i\n", socket
);
947 snprintf(buf
, sizeof(buf
), "IP_RSMBL_LPM_%i", socket
);
949 lpm_config
.max_rules
= LPM_MAX_RULES
;
950 lpm_config
.number_tbl8s
= 256;
951 lpm_config
.flags
= 0;
953 lpm
= rte_lpm_create(buf
, socket
, &lpm_config
);
955 RTE_LOG(ERR
, IP_RSMBL
, "Cannot create LPM table\n");
958 socket_lpm
[socket
] = lpm
;
961 if (socket_lpm6
[socket
] == NULL
) {
962 RTE_LOG(INFO
, IP_RSMBL
, "Creating LPM6 table on socket %i\n", socket
);
963 snprintf(buf
, sizeof(buf
), "IP_RSMBL_LPM_%i", socket
);
965 lpm6
= rte_lpm6_create(buf
, socket
, &lpm6_config
);
967 RTE_LOG(ERR
, IP_RSMBL
, "Cannot create LPM table\n");
970 socket_lpm6
[socket
] = lpm6
;
978 queue_dump_stat(void)
981 const struct lcore_queue_conf
*qconf
;
983 for (lcore
= 0; lcore
< RTE_MAX_LCORE
; lcore
++) {
984 if (rte_lcore_is_enabled(lcore
) == 0)
987 qconf
= &lcore_queue_conf
[lcore
];
988 for (i
= 0; i
< qconf
->n_rx_queue
; i
++) {
990 fprintf(stdout
, " -- lcoreid=%u portid=%hhu "
992 lcore
, qconf
->rx_queue_list
[i
].portid
);
993 rte_ip_frag_table_statistics_dump(stdout
,
994 qconf
->rx_queue_list
[i
].frag_tbl
);
995 fprintf(stdout
, "TX bursts:\t%" PRIu64
"\n"
996 "TX packets _queued:\t%" PRIu64
"\n"
997 "TX packets dropped:\t%" PRIu64
"\n"
998 "TX packets send:\t%" PRIu64
"\n",
1000 qconf
->tx_stat
.queue
,
1001 qconf
->tx_stat
.drop
,
1002 qconf
->tx_stat
.send
);
1008 signal_handler(int signum
)
1011 if (signum
!= SIGUSR1
)
1012 rte_exit(0, "received signal: %d, exiting\n", signum
);
1016 main(int argc
, char **argv
)
1018 struct lcore_queue_conf
*qconf
;
1019 struct rte_eth_dev_info dev_info
;
1020 struct rte_eth_txconf
*txconf
;
1021 struct rx_queue
*rxq
;
1025 unsigned lcore_id
= 0, rx_lcore_id
= 0;
1026 uint32_t n_tx_queue
, nb_lcores
;
1030 ret
= rte_eal_init(argc
, argv
);
1032 rte_exit(EXIT_FAILURE
, "Invalid EAL parameters\n");
1036 /* parse application arguments (after the EAL ones) */
1037 ret
= parse_args(argc
, argv
);
1039 rte_exit(EXIT_FAILURE
, "Invalid IP reassembly parameters\n");
1041 nb_ports
= rte_eth_dev_count();
1043 rte_exit(EXIT_FAILURE
, "No ports found!\n");
1045 nb_lcores
= rte_lcore_count();
1047 /* initialize structures (mempools, lpm etc.) */
1049 rte_panic("Cannot initialize memory structures!\n");
1051 /* check if portmask has non-existent ports */
1052 if (enabled_port_mask
& ~(RTE_LEN2MASK(nb_ports
, unsigned)))
1053 rte_exit(EXIT_FAILURE
, "Non-existent ports in portmask!\n");
1055 /* initialize all ports */
1056 for (portid
= 0; portid
< nb_ports
; portid
++) {
1057 /* skip ports that are not enabled */
1058 if ((enabled_port_mask
& (1 << portid
)) == 0) {
1059 printf("\nSkipping disabled port %d\n", portid
);
1063 qconf
= &lcore_queue_conf
[rx_lcore_id
];
1065 /* get the lcore_id for this port */
1066 while (rte_lcore_is_enabled(rx_lcore_id
) == 0 ||
1067 qconf
->n_rx_queue
== (unsigned)rx_queue_per_lcore
) {
1070 if (rx_lcore_id
>= RTE_MAX_LCORE
)
1071 rte_exit(EXIT_FAILURE
, "Not enough cores\n");
1073 qconf
= &lcore_queue_conf
[rx_lcore_id
];
1076 socket
= rte_lcore_to_socket_id(portid
);
1077 if (socket
== SOCKET_ID_ANY
)
1080 queueid
= qconf
->n_rx_queue
;
1081 rxq
= &qconf
->rx_queue_list
[queueid
];
1082 rxq
->portid
= portid
;
1083 rxq
->lpm
= socket_lpm
[socket
];
1084 rxq
->lpm6
= socket_lpm6
[socket
];
1085 if (setup_queue_tbl(rxq
, rx_lcore_id
, queueid
) < 0)
1086 rte_exit(EXIT_FAILURE
, "Failed to set up queue table\n");
1087 qconf
->n_rx_queue
++;
1090 printf("Initializing port %d ... ", portid
);
1093 n_tx_queue
= nb_lcores
;
1094 if (n_tx_queue
> MAX_TX_QUEUE_PER_PORT
)
1095 n_tx_queue
= MAX_TX_QUEUE_PER_PORT
;
1096 ret
= rte_eth_dev_configure(portid
, 1, (uint16_t)n_tx_queue
,
1100 rte_exit(EXIT_FAILURE
, "Cannot configure device: "
1101 "err=%d, port=%d\n",
1105 /* init one RX queue */
1106 ret
= rte_eth_rx_queue_setup(portid
, 0, nb_rxd
,
1111 rte_exit(EXIT_FAILURE
, "rte_eth_rx_queue_setup: "
1112 "err=%d, port=%d\n",
1116 rte_eth_macaddr_get(portid
, &ports_eth_addr
[portid
]);
1117 print_ethaddr(" Address:", &ports_eth_addr
[portid
]);
1120 /* init one TX queue per couple (lcore,port) */
1122 for (lcore_id
= 0; lcore_id
< RTE_MAX_LCORE
; lcore_id
++) {
1123 if (rte_lcore_is_enabled(lcore_id
) == 0)
1126 socket
= (int) rte_lcore_to_socket_id(lcore_id
);
1128 printf("txq=%u,%d,%d ", lcore_id
, queueid
, socket
);
1131 rte_eth_dev_info_get(portid
, &dev_info
);
1132 txconf
= &dev_info
.default_txconf
;
1133 txconf
->txq_flags
= 0;
1135 ret
= rte_eth_tx_queue_setup(portid
, queueid
, nb_txd
,
1138 rte_exit(EXIT_FAILURE
, "rte_eth_tx_queue_setup: err=%d, "
1139 "port=%d\n", ret
, portid
);
1141 qconf
= &lcore_queue_conf
[lcore_id
];
1142 qconf
->tx_queue_id
[portid
] = queueid
;
1143 setup_port_tbl(qconf
, lcore_id
, socket
, portid
);
1152 for (portid
= 0; portid
< nb_ports
; portid
++) {
1153 if ((enabled_port_mask
& (1 << portid
)) == 0) {
1157 ret
= rte_eth_dev_start(portid
);
1159 rte_exit(EXIT_FAILURE
, "rte_eth_dev_start: err=%d, port=%d\n",
1162 rte_eth_promiscuous_enable(portid
);
1165 if (init_routing_table() < 0)
1166 rte_exit(EXIT_FAILURE
, "Cannot init routing table\n");
1168 check_all_ports_link_status((uint8_t)nb_ports
, enabled_port_mask
);
1170 signal(SIGUSR1
, signal_handler
);
1171 signal(SIGTERM
, signal_handler
);
1172 signal(SIGINT
, signal_handler
);
1174 /* launch per-lcore init on every lcore */
1175 rte_eal_mp_remote_launch(main_loop
, NULL
, CALL_MASTER
);
1176 RTE_LCORE_FOREACH_SLAVE(lcore_id
) {
1177 if (rte_eal_wait_lcore(lcore_id
) < 0)