24 #include <odp/helper/odph_api.h>
27 #define MAX_PKTIO_NAME 255
28 #define MAX_PKT_NUM 1024
30 ODP_STATIC_ASSERT(MAX_PKTIOS < UINT8_MAX,
"MAX_PKTIOS too large for index lookup");
32 typedef struct test_options_t {
38 char pktio_name[MAX_PKTIOS][MAX_PKTIO_NAME + 1];
42 typedef struct test_global_t {
50 odph_ethaddr_t eth_addr;
62 static test_global_t test_global;
64 static void sig_handler(
int signo)
71 static void print_usage(
void)
74 "ODP ping example. Replies to ICMPv4 ping requests.\n"
77 " -i, --interface <name> Packet IO interfaces (comma-separated, no spaces)\n"
78 " -n, --num_packet <number> Exit after this many packets. Use 0 to run infinitely. Default 0.\n"
79 " -t, --timeout <sec> Exit after this many seconds. Use 0 to run infinitely. Default 0.\n"
80 " -p, --promisc Set interface into promiscuous mode.\n"
81 " -v, --verbose Print extra packet information.\n"
82 " -h, --help Display help and exit.\n\n");
85 static int parse_options(
int argc,
char *argv[], test_global_t *global)
91 const struct option longopts[] = {
92 {
"interface", required_argument, NULL,
'i'},
93 {
"num_packet", required_argument, NULL,
'n'},
94 {
"timeout", required_argument, NULL,
't'},
95 {
"promisc", no_argument, NULL,
'p'},
96 {
"verbose", no_argument, NULL,
'v'},
97 {
"help", no_argument, NULL,
'h'},
100 const char *shortopts =
"+i:n:t:pvh";
104 opt = getopt_long(argc, argv, shortopts, longopts, NULL);
113 str_len = strlen(str);
115 while (str_len > 0) {
116 len = strcspn(str,
",");
119 if (i == MAX_PKTIOS) {
120 ODPH_ERR(
"Too many interfaces\n");
125 if (len > MAX_PKTIO_NAME) {
126 ODPH_ERR(
"Too long interface name: %s\n", str);
131 name = global->opt.pktio_name[i];
132 memcpy(name, str, len);
137 global->opt.num_pktio = i;
141 global->opt.num_packet = atoll(optarg);
144 global->opt.timeout = atoi(optarg);
147 global->opt.promisc = 1;
150 global->opt.verbose = 1;
159 if (global->opt.num_pktio == 0) {
160 ODPH_ERR(
"At least one pktio interface needed\n");
167 static int open_pktios(test_global_t *global)
181 uint32_t num_pkt = MAX_PKT_NUM;
183 num_pktio = global->opt.num_pktio;
186 ODPH_ERR(
"Pool capability failed\n");
194 pool_param.
pkt.
num = num_pkt;
202 ODPH_ERR(
"Pool create failed\n");
210 for (i = 0; i < num_pktio; i++)
214 for (i = 0; i < num_pktio; i++) {
215 name = global->opt.pktio_name[i];
219 ODPH_ERR(
"Pktio open failed: %s\n", name);
223 global->pktio[i].pktio = pktio;
226 ODPH_ERR(
"Packet IO capability failed\n");
231 &global->pktio[i].eth_addr.addr,
232 ODPH_ETHADDR_LEN) != ODPH_ETHADDR_LEN) {
233 ODPH_ERR(
"MAC address read failed: %s\n", name);
251 ODPH_ERR(
"Pktin config failed: %s\n", name);
259 ODPH_ERR(
"Pktout config failed: %s\n", name);
264 ODPH_ERR(
"Pktout queue request failed: %s\n", name);
268 global->pktio[i].pktout = pktout;
272 ODPH_ERR(
"Promiscuous mode cannot be set: %s\n", name);
277 ODPH_ERR(
"Promiscuous mode set failed: %s\n", name);
288 static int init_pktio_lookup_tbl(test_global_t *global)
290 for (
int i = 0; i < global->opt.num_pktio; i++) {
295 ODPH_ERR(
"odp_pktio_index() failed: %s\n", global->opt.pktio_name[i]);
299 global->pktio_from_idx[pktio_idx] = i;
304 static int start_pktios(test_global_t *global)
308 for (i = 0; i < global->opt.num_pktio; i++) {
310 ODPH_ERR(
"Pktio start failed: %s\n", global->opt.pktio_name[i]);
314 global->pktio[i].started = 1;
320 static int stop_pktios(test_global_t *global)
325 for (i = 0; i < global->opt.num_pktio; i++) {
326 pktio = global->pktio[i].pktio;
332 ODPH_ERR(
"Pktio stop failed: %s\n", global->opt.pktio_name[i]);
340 static void empty_queues(
void)
356 static int close_pktios(test_global_t *global)
362 for (i = 0; i < global->opt.num_pktio; i++) {
363 pktio = global->pktio[i].pktio;
369 ODPH_ERR(
"Pktio close failed: %s\n", global->opt.pktio_name[i]);
380 ODPH_ERR(
"Pool destroy failed\n");
387 static void print_mac_addr(uint8_t *addr)
389 printf(
"%02x:%02x:%02x:%02x:%02x:%02x\n",
390 addr[0], addr[1], addr[2], addr[3], addr[4], addr[5]);
393 static void print_ipv4_addr(uint8_t *addr)
395 printf(
"%u.%u.%u.%u\n",
396 addr[0], addr[1], addr[2], addr[3]);
399 static void print_data(
odp_packet_t pkt, uint32_t offset, uint32_t len)
401 const uint32_t bytes_per_row = 16;
402 const uint32_t num_char = 1 + (bytes_per_row * 3) + 1;
403 uint8_t data[bytes_per_row];
405 uint32_t copy_len, i, j;
408 if (offset > data_len)
411 if (offset + len > data_len)
412 len = data_len - offset;
417 if (len > bytes_per_row)
418 copy_len = bytes_per_row;
424 i += snprintf(&row[i], num_char - i,
" ");
426 for (j = 0; j < copy_len; j++)
427 i += snprintf(&row[i], num_char - i,
" %02x", data[j]);
437 static void print_packet(
odp_packet_t pkt, uint64_t num_packet)
463 printf(
"PACKET [%" PRIu64
"]\n", num_packet);
464 printf(
" time: %" PRIu64
".%09" PRIu64
" sec\n", sec, nsec);
466 printf(
" interface name: %s\n", pktio_info.
name);
468 printf(
" interface name: n/a\n");
473 printf(
" Ethernet offset: %u bytes\n", l2_offset);
475 if (offset + 6 <= seg_len) {
476 printf(
" dst address: ");
477 print_mac_addr(data + offset);
480 offset = l2_offset + 6;
481 if (offset + 6 <= seg_len) {
482 printf(
" src address: ");
483 print_mac_addr(data + offset);
486 printf(
" L2 (%i) offset: %u bytes\n",
492 printf(
" IPv4 offset: %u bytes\n", l3_offset);
493 offset = l3_offset + 12;
494 if (offset + 4 <= seg_len) {
495 printf(
" src address: ");
496 print_ipv4_addr(data + offset);
499 offset = l3_offset + 16;
500 if (offset + 4 <= seg_len) {
501 printf(
" dst address: ");
502 print_ipv4_addr(data + offset);
505 printf(
" IPv6 offset: %u bytes\n", l3_offset);
507 printf(
" L3 (%i) offset: %u bytes\n",
513 printf(
" ICMP offset: %u bytes\n", l4_offset);
518 if (u8 && len >= 2) {
519 printf(
" type: %u\n", u8[0]);
520 printf(
" code: %u\n", u8[1]);
524 printf(
" L4 (%i) offset: %u bytes\n",
528 print_data(pkt, 0, data_len);
534 static uint16_t update_chksum(uint16_t chksum, uint16_t old, uint16_t
new)
536 uint16_t chksum_comp = ~chksum;
537 uint16_t old_comp = ~old;
538 uint32_t sum = chksum_comp + old_comp +
new;
541 sum = (sum & 0xffff) + (sum >> 16);
546 static void icmp_reply(test_global_t *global,
odp_packet_t pkt)
549 odph_ipv4hdr_t *ip_hdr;
550 odph_ethhdr_t *eth_hdr;
555 odph_ethaddr_t *eth_addr = &global->pktio[index].eth_addr;
564 if (eth == 0 || ipv4 == 0 || icmp == 0)
568 if (icmp_hdr == NULL || len < 4)
571 if (icmp_hdr->type != ODPH_ICMP_ECHO || icmp_hdr->code != 0)
575 old = *(uint16_t *)(uintptr_t)icmp_hdr;
576 icmp_hdr->type = ODPH_ICMP_ECHOREPLY;
577 new = *(uint16_t *)(uintptr_t)icmp_hdr;
578 icmp_hdr->chksum = update_chksum(icmp_hdr->chksum, old,
new);
582 if (ip_hdr == NULL || len < 20)
585 dst_ip = ip_hdr->dst_addr;
586 ip_hdr->dst_addr = ip_hdr->src_addr;
587 ip_hdr->src_addr = dst_ip;
591 if (eth_hdr == NULL || len < 14)
594 eth_hdr->dst = eth_hdr->src;
595 eth_hdr->src = *eth_addr;
600 global->tx_replies++;
607 static void print_stat(test_global_t *global, uint64_t rx_packets,
610 uint64_t prev = global->rx_packets;
611 double per_sec = 1000000000.0 * (rx_packets - prev) / diff_ns;
613 printf(
"Received %" PRIu64
" packets (%.1f / sec). "
614 "Sent %" PRIu64
" replies.\n",
615 rx_packets, per_sec, global->tx_replies);
617 global->rx_packets = rx_packets;
620 static int receive_packets(test_global_t *global)
626 uint64_t num_packet = 0;
645 print_stat(global, num_packet, diff_ns);
665 if (global->opt.verbose)
666 print_packet(pkt, num_packet);
669 icmp_reply(global, pkt);
673 print_stat(global, num_packet, diff_ns);
677 if (global->opt.num_packet && num_packet >= global->opt.num_packet)
682 if (global->opt.num_packet && num_packet < global->opt.num_packet) {
683 ODPH_ERR(
"Received %" PRIu64
"/%" PRIu64
" packets\n",
684 num_packet, global->opt.num_packet);
691 int main(
int argc,
char *argv[])
694 test_global_t *global;
697 global = &test_global;
698 memset(global, 0,
sizeof(test_global_t));
701 signal(SIGINT, sig_handler);
703 if (parse_options(argc, argv, global))
708 ODPH_ERR(
"Global init failed\n");
714 ODPH_ERR(
"Local init failed\n");
724 if (open_pktios(global)) {
725 ODPH_ERR(
"Pktio open failed\n");
729 if (init_pktio_lookup_tbl(global)) {
730 ODPH_ERR(
"Mapping pktio indexes failed\n");
734 if (start_pktios(global)) {
735 ODPH_ERR(
"Pktio start failed\n");
739 if (receive_packets(global)) {
743 if (stop_pktios(global)) {
744 ODPH_ERR(
"Pktio stop failed\n");
750 if (close_pktios(global)) {
751 ODPH_ERR(
"Pktio close failed\n");
756 ODPH_ERR(
"Term local failed\n");
761 ODPH_ERR(
"Term global failed\n");
void odp_atomic_init_u32(odp_atomic_u32_t *atom, uint32_t val)
Initialize atomic uint32 variable.
uint32_t odp_atomic_load_u32(odp_atomic_u32_t *atom)
Load value of atomic uint32 variable.
void odp_atomic_store_u32(odp_atomic_u32_t *atom, uint32_t val)
Store value to atomic uint32 variable.
void odp_event_free(odp_event_t event)
Free event.
odp_event_type_t odp_event_type(odp_event_t event)
Event type of an event.
#define ODP_EVENT_INVALID
Invalid event.
#define ODP_STATIC_ASSERT(cond, msg)
Compile time assertion macro.
int odp_init_local(odp_instance_t instance, odp_thread_type_t thr_type)
Thread local ODP initialization.
int odp_init_global(odp_instance_t *instance, const odp_init_t *params, const odp_platform_init_t *platform_params)
Global ODP initialization.
int odp_term_local(void)
Thread local ODP termination.
int odp_term_global(odp_instance_t instance)
Global ODP termination.
uint64_t odp_instance_t
ODP instance ID.
int odp_pktio_mac_addr(odp_pktio_t pktio, void *mac_addr, int size)
Get the default MAC address of a packet IO interface.
void odp_pktin_queue_param_init(odp_pktin_queue_param_t *param)
Initialize packet input queue parameters.
void odp_pktio_param_init(odp_pktio_param_t *param)
Initialize pktio params.
int odp_pktio_promisc_mode(odp_pktio_t pktio)
Determine if promiscuous mode is enabled for a packet IO interface.
int odp_pktio_close(odp_pktio_t pktio)
Close a packet IO interface.
int odp_pktio_info(odp_pktio_t pktio, odp_pktio_info_t *info)
Retrieve information about a pktio.
int odp_pktout_queue(odp_pktio_t pktio, odp_pktout_queue_t queues[], int num)
Direct packet output queues.
int odp_pktio_promisc_mode_set(odp_pktio_t pktio, odp_bool_t enable)
Set promiscuous mode.
void odp_pktio_config_init(odp_pktio_config_t *config)
Initialize packet IO configuration options.
odp_pktio_t odp_pktio_open(const char *name, odp_pool_t pool, const odp_pktio_param_t *param)
Open a packet IO interface.
int odp_pktio_config(odp_pktio_t pktio, const odp_pktio_config_t *config)
Configure packet IO interface options.
void odp_pktio_print(odp_pktio_t pktio)
Print pktio info to the console.
int odp_pktio_start(odp_pktio_t pktio)
Start packet receive and transmit.
#define ODP_PKTIO_INVALID
Invalid packet IO handle.
void odp_pktout_queue_param_init(odp_pktout_queue_param_t *param)
Initialize packet output queue parameters.
int odp_pktio_stop(odp_pktio_t pktio)
Stop packet receive and transmit.
int odp_pktio_index(odp_pktio_t pktio)
Get pktio interface index.
int odp_pktio_capability(odp_pktio_t pktio, odp_pktio_capability_t *capa)
Query packet IO interface capabilities.
#define ODP_PKTIO_MAX_INDEX
Maximum packet IO interface index.
int odp_pktout_send(odp_pktout_queue_t queue, const odp_packet_t packets[], int num)
Send packets directly to an interface output queue.
int odp_pktin_queue_config(odp_pktio_t pktio, const odp_pktin_queue_param_t *param)
Configure packet input queues.
int odp_pktout_queue_config(odp_pktio_t pktio, const odp_pktout_queue_param_t *param)
Configure packet output queues.
@ ODP_PKTOUT_MODE_DIRECT
Direct packet output on the interface.
@ ODP_PKTIN_MODE_SCHED
Packet input through scheduler and scheduled event queues.
int odp_packet_has_l3(odp_packet_t pkt)
Check for layer 3 protocols.
odp_proto_l4_type_t odp_packet_l4_type(odp_packet_t pkt)
Layer 4 protocol type.
int odp_packet_has_ts(odp_packet_t pkt)
Check for packet timestamp.
int odp_packet_input_index(odp_packet_t pkt)
Packet input interface index.
uint32_t odp_packet_seg_len(odp_packet_t pkt)
Packet data length following the data pointer.
int odp_packet_has_icmp(odp_packet_t pkt)
Check for ICMP.
int odp_packet_has_ipv4(odp_packet_t pkt)
Check for IPv4.
uint32_t odp_packet_l4_offset(odp_packet_t pkt)
Layer 4 start offset.
void * odp_packet_data(odp_packet_t pkt)
Packet data pointer.
int odp_packet_has_eth(odp_packet_t pkt)
Check for Ethernet header.
odp_proto_l2_type_t odp_packet_l2_type(odp_packet_t pkt)
Layer 2 protocol type.
int odp_packet_has_l4(odp_packet_t pkt)
Check for layer 4 protocols.
uint32_t odp_packet_len(odp_packet_t pkt)
Packet data length.
int odp_packet_has_error(odp_packet_t pkt)
Check for all parse errors in packet.
int odp_packet_has_ipv6(odp_packet_t pkt)
Check for IPv6.
int odp_packet_has_l2(odp_packet_t pkt)
Check for layer 2 protocols.
odp_packet_t odp_packet_from_event(odp_event_t ev)
Get packet handle from event.
void odp_packet_free(odp_packet_t pkt)
Free packet.
void * odp_packet_l2_ptr(odp_packet_t pkt, uint32_t *len)
Layer 2 start pointer.
uint32_t odp_packet_l3_offset(odp_packet_t pkt)
Layer 3 start offset.
void * odp_packet_l4_ptr(odp_packet_t pkt, uint32_t *len)
Layer 4 start pointer.
odp_proto_l3_type_t odp_packet_l3_type(odp_packet_t pkt)
Layer 3 protocol type.
void * odp_packet_l3_ptr(odp_packet_t pkt, uint32_t *len)
Layer 3 start pointer.
int odp_packet_copy_to_mem(odp_packet_t pkt, uint32_t offset, uint32_t len, void *dst)
Copy data from packet to memory.
odp_time_t odp_packet_ts(odp_packet_t pkt)
Packet timestamp.
odp_pktio_t odp_packet_input(odp_packet_t pkt)
Packet input interface.
uint32_t odp_packet_l2_offset(odp_packet_t pkt)
Layer 2 start offset.
@ ODP_PROTO_LAYER_ALL
All layers.
odp_pool_t odp_pool_create(const char *name, const odp_pool_param_t *param)
Create a pool.
int odp_pool_capability(odp_pool_capability_t *capa)
Query pool capabilities.
void odp_pool_param_init(odp_pool_param_t *param)
Initialize pool params.
int odp_pool_destroy(odp_pool_t pool)
Destroy a pool previously created by odp_pool_create()
#define ODP_POOL_INVALID
Invalid pool.
@ ODP_POOL_PACKET
Packet pool.
#define ODP_SCHED_SYNC_ATOMIC
Atomic queue synchronization.
int odp_schedule_default_prio(void)
Default scheduling priority level.
int odp_schedule_config(const odp_schedule_config_t *config)
Global schedule configuration.
uint64_t odp_schedule_wait_time(uint64_t ns)
Schedule wait time.
odp_event_t odp_schedule(odp_queue_t *from, uint64_t wait)
Schedule an event.
#define ODP_SCHED_GROUP_ALL
Group of all threads.
void odp_sys_info_print(void)
Print system info.
@ ODP_THREAD_CONTROL
Control thread.
uint64_t odp_time_to_ns(odp_time_t time)
Convert time to nanoseconds.
#define ODP_TIME_SEC_IN_NS
A second in nanoseconds.
odp_time_t odp_time_local(void)
Current local time.
#define ODP_TIME_MSEC_IN_NS
A millisecond in nanoseconds.
uint64_t odp_time_diff_ns(odp_time_t t2, odp_time_t t1)
Time difference in nanoseconds.
Packet input queue parameters.
uint32_t num_queues
Number of input queues to be created.
odp_queue_param_t queue_param
Queue parameters.
odp_pktio_set_op_t set_op
Supported set operations.
Packet IO configuration options.
odp_pktio_parser_config_t parser
Packet input parser configuration.
odp_pktin_config_opt_t pktin
Packet input configuration options bit field.
const char * name
Packet IO device name.
odp_pktin_mode_t in_mode
Packet input mode.
odp_pktout_mode_t out_mode
Packet output mode.
odp_proto_layer_t layer
Protocol parsing level in packet input.
Packet output queue parameters.
uint32_t num_queues
Number of output queues to be created.
struct odp_pool_capability_t::@122 pkt
Packet pool capabilities
uint32_t max_num
Maximum number of buffers of any size.
uint32_t num
Number of buffers in the pool.
odp_pool_type_t type
Pool type.
struct odp_pool_param_t::@126 pkt
Parameters for packet pools.
odp_schedule_param_t sched
Scheduler parameters.
odp_schedule_group_t group
Thread group.
odp_schedule_prio_t prio
Priority level.
odp_schedule_sync_t sync
Synchronization method.
uint64_t ts_all
Timestamp all packets on packet input.
struct odp_pktin_config_opt_t::@100 bit
Option flags.
struct odp_pktio_set_op_t::@104 op
Operation flags.
uint32_t promisc_mode
Promiscuous mode.