1 /* SPDX-License-Identifier: BSD-3-Clause
2 * Copyright(c) 2010-2014 Intel Corporation
12 #include <sys/queue.h>
14 #include <netinet/ip.h>
17 #include <rte_common.h>
18 #include <rte_memory.h>
20 #include <rte_launch.h>
21 #include <rte_per_lcore.h>
22 #include <rte_lcore.h>
23 #include <rte_branch_prediction.h>
24 #include <rte_atomic.h>
27 #include <rte_debug.h>
28 #include <rte_mempool.h>
29 #include <rte_memcpy.h>
31 #include <rte_ether.h>
32 #include <rte_interrupts.h>
33 #include <rte_ethdev.h>
34 #include <rte_byteorder.h>
35 #include <rte_malloc.h>
36 #include <rte_string_fns.h>
43 * When doing reads from the NIC or the client queues,
46 #define PACKET_READ_SIZE 32
49 * Local buffers to put packets in, used to send packets in bursts to the
52 struct client_rx_buf
{
53 struct rte_mbuf
*buffer
[PACKET_READ_SIZE
];
57 /* One buffer per client rx queue - dynamically allocate array */
58 static struct client_rx_buf
*cl_rx_buf
;
61 get_printable_mac_addr(uint16_t port
)
63 static const char err_address
[] = "00:00:00:00:00:00";
64 static char addresses
[RTE_MAX_ETHPORTS
][sizeof(err_address
)];
66 if (unlikely(port
>= RTE_MAX_ETHPORTS
))
68 if (unlikely(addresses
[port
][0]=='\0')){
69 struct ether_addr mac
;
70 rte_eth_macaddr_get(port
, &mac
);
71 snprintf(addresses
[port
], sizeof(addresses
[port
]),
72 "%02x:%02x:%02x:%02x:%02x:%02x\n",
73 mac
.addr_bytes
[0], mac
.addr_bytes
[1], mac
.addr_bytes
[2],
74 mac
.addr_bytes
[3], mac
.addr_bytes
[4], mac
.addr_bytes
[5]);
76 return addresses
[port
];
80 * This function displays the recorded statistics for each port
81 * and for each client. It uses ANSI terminal codes to clear
82 * screen when called. It is called from a single non-master
83 * thread in the server process, when the process is run with more
84 * than one lcore enabled.
87 do_stats_display(void)
90 const char clr
[] = { 27, '[', '2', 'J', '\0' };
91 const char topLeft
[] = { 27, '[', '1', ';', '1', 'H','\0' };
92 uint64_t port_tx
[RTE_MAX_ETHPORTS
], port_tx_drop
[RTE_MAX_ETHPORTS
];
93 uint64_t client_tx
[MAX_CLIENTS
], client_tx_drop
[MAX_CLIENTS
];
95 /* to get TX stats, we need to do some summing calculations */
96 memset(port_tx
, 0, sizeof(port_tx
));
97 memset(port_tx_drop
, 0, sizeof(port_tx_drop
));
98 memset(client_tx
, 0, sizeof(client_tx
));
99 memset(client_tx_drop
, 0, sizeof(client_tx_drop
));
101 for (i
= 0; i
< num_clients
; i
++){
102 const volatile struct tx_stats
*tx
= &ports
->tx_stats
[i
];
103 for (j
= 0; j
< ports
->num_ports
; j
++){
104 /* assign to local variables here, save re-reading volatile vars */
105 const uint64_t tx_val
= tx
->tx
[ports
->id
[j
]];
106 const uint64_t drop_val
= tx
->tx_drop
[ports
->id
[j
]];
107 port_tx
[j
] += tx_val
;
108 port_tx_drop
[j
] += drop_val
;
109 client_tx
[i
] += tx_val
;
110 client_tx_drop
[i
] += drop_val
;
114 /* Clear screen and move to top left */
115 printf("%s%s", clr
, topLeft
);
119 for (i
= 0; i
< ports
->num_ports
; i
++)
120 printf("Port %u: '%s'\t", (unsigned)ports
->id
[i
],
121 get_printable_mac_addr(ports
->id
[i
]));
123 for (i
= 0; i
< ports
->num_ports
; i
++){
124 printf("Port %u - rx: %9"PRIu64
"\t"
126 (unsigned)ports
->id
[i
], ports
->rx_stats
.rx
[i
],
130 printf("\nCLIENTS\n");
132 for (i
= 0; i
< num_clients
; i
++){
133 const unsigned long long rx
= clients
[i
].stats
.rx
;
134 const unsigned long long rx_drop
= clients
[i
].stats
.rx_drop
;
135 printf("Client %2u - rx: %9llu, rx_drop: %9llu\n"
136 " tx: %9"PRIu64
", tx_drop: %9"PRIu64
"\n",
137 i
, rx
, rx_drop
, client_tx
[i
], client_tx_drop
[i
]);
144 * The function called from each non-master lcore used by the process.
145 * The test_and_set function is used to randomly pick a single lcore on which
146 * the code to display the statistics will run. Otherwise, the code just
150 sleep_lcore(__attribute__((unused
)) void *dummy
)
152 /* Used to pick a display thread - static, so zero-initialised */
153 static rte_atomic32_t display_stats
;
155 /* Only one core should display stats */
156 if (rte_atomic32_test_and_set(&display_stats
)) {
157 const unsigned sleeptime
= 1;
158 printf("Core %u displaying statistics\n", rte_lcore_id());
160 /* Longer initial pause so above printf is seen */
161 sleep(sleeptime
* 3);
163 /* Loop forever: sleep always returns 0 or <= param */
164 while (sleep(sleeptime
) <= sleeptime
)
171 * Function to set all the client statistic values to zero.
172 * Called at program startup.
179 for (i
= 0; i
< num_clients
; i
++)
180 clients
[i
].stats
.rx
= clients
[i
].stats
.rx_drop
= 0;
184 * send a burst of traffic to a client, assuming there are packets
185 * available to be sent to this client
188 flush_rx_queue(uint16_t client
)
193 if (cl_rx_buf
[client
].count
== 0)
196 cl
= &clients
[client
];
197 if (rte_ring_enqueue_bulk(cl
->rx_q
, (void **)cl_rx_buf
[client
].buffer
,
198 cl_rx_buf
[client
].count
, NULL
) == 0){
199 for (j
= 0; j
< cl_rx_buf
[client
].count
; j
++)
200 rte_pktmbuf_free(cl_rx_buf
[client
].buffer
[j
]);
201 cl
->stats
.rx_drop
+= cl_rx_buf
[client
].count
;
204 cl
->stats
.rx
+= cl_rx_buf
[client
].count
;
206 cl_rx_buf
[client
].count
= 0;
210 * marks a packet down to be sent to a particular client process
213 enqueue_rx_packet(uint8_t client
, struct rte_mbuf
*buf
)
215 cl_rx_buf
[client
].buffer
[cl_rx_buf
[client
].count
++] = buf
;
219 * This function takes a group of packets and routes them
220 * individually to the client process. Very simply round-robins the packets
221 * without checking any of the packet contents.
224 process_packets(uint32_t port_num __rte_unused
,
225 struct rte_mbuf
*pkts
[], uint16_t rx_count
)
230 for (i
= 0; i
< rx_count
; i
++) {
231 enqueue_rx_packet(client
, pkts
[i
]);
233 if (++client
== num_clients
)
237 for (i
= 0; i
< num_clients
; i
++)
242 * Function called by the master lcore of the DPDK process.
245 do_packet_forwarding(void)
247 unsigned port_num
= 0; /* indexes the port[] array */
250 struct rte_mbuf
*buf
[PACKET_READ_SIZE
];
254 rx_count
= rte_eth_rx_burst(ports
->id
[port_num
], 0, \
255 buf
, PACKET_READ_SIZE
);
256 ports
->rx_stats
.rx
[port_num
] += rx_count
;
258 /* Now process the NIC packets read */
259 if (likely(rx_count
> 0))
260 process_packets(port_num
, buf
, rx_count
);
262 /* move to next port */
263 if (++port_num
== ports
->num_ports
)
269 signal_handler(int signal
)
273 if (signal
== SIGINT
)
274 RTE_ETH_FOREACH_DEV(port_id
) {
275 rte_eth_dev_stop(port_id
);
276 rte_eth_dev_close(port_id
);
282 main(int argc
, char *argv
[])
284 signal(SIGINT
, signal_handler
);
285 /* initialise the system */
286 if (init(argc
, argv
) < 0 )
288 RTE_LOG(INFO
, APP
, "Finished Process Init.\n");
290 cl_rx_buf
= calloc(num_clients
, sizeof(cl_rx_buf
[0]));
292 /* clear statistics */
295 /* put all other cores to sleep bar master */
296 rte_eal_mp_remote_launch(sleep_lcore
, NULL
, SKIP_MASTER
);
298 do_packet_forwarding();