static void test_txrx(odp_pktio_input_mode_t in_mode, int num_pkts) { int ret, i, if_b; pktio_info_t pktios[MAX_NUM_IFACES]; pktio_info_t *io; uint32_t mtu, min_mtu = UINT32_MAX; /* create pktios and associate input/output queues */ for (i = 0; i < num_ifaces; ++i) { io = &pktios[i]; io->name = iface_name[i]; io->id = create_pktio(i, in_mode, ODP_PKTOUT_MODE_SEND); if (io->id == ODP_PKTIO_INVALID) { CU_FAIL("failed to open iface"); return; } io->outq = odp_pktio_outq_getdef(io->id); io->in_mode = in_mode; if (in_mode == ODP_PKTIN_MODE_POLL) { create_inq(io->id, ODP_QUEUE_TYPE_POLL); io->inq = odp_pktio_inq_getdef(io->id); } else if (in_mode == ODP_PKTIN_MODE_SCHED) { create_inq(io->id, ODP_QUEUE_TYPE_SCHED); io->inq = ODP_QUEUE_INVALID; } } for (i = 0; i < num_ifaces; ++i) { io = &pktios[i]; ret = odp_pktio_start(io->id); CU_ASSERT(ret == 0); mtu = odp_pktio_mtu(io->id); if (mtu < min_mtu) min_mtu = mtu; } /* Skip test if packet len is larger than the MTU */ if (min_mtu >= packet_len) { /* if we have two interfaces then send through one and receive * on another but if there's only one assume it's a loopback */ if_b = (num_ifaces == 1) ? 0 : 1; pktio_txrx_multi(&pktios[0], &pktios[if_b], num_pkts); } for (i = 0; i < num_ifaces; ++i) { ret = odp_pktio_stop(pktios[i].id); CU_ASSERT(ret == 0); if (in_mode != ODP_PKTIN_MODE_RECV) destroy_inq(pktios[i].id); ret = odp_pktio_close(pktios[i].id); CU_ASSERT(ret == 0); } }
static inline void enqueue_loop_interface(odp_packet_t pkt) { odp_event_t ev; odp_queue_t defqueue = odp_pktio_outq_getdef(pktio_loop); ev = odp_packet_to_event(pkt); if (!(CU_ASSERT(odp_queue_enq(defqueue, ev) == 0))) odp_packet_free(pkt); }
void enqueue_pktio_interface(odp_packet_t pkt, odp_pktio_t pktio) { odp_event_t ev; odp_queue_t defqueue; defqueue = odp_pktio_outq_getdef(pktio); CU_ASSERT(defqueue != ODP_QUEUE_INVALID); ev = odp_packet_to_event(pkt); CU_ASSERT(odp_queue_enq(defqueue, ev) == 0); }
/** * Lookup the destination pktio for a given packet */ static inline odp_queue_t lookup_dest_q(odp_packet_t pkt) { int i, src_idx, dst_idx; odp_pktio_t pktio_src, pktio_dst; pktio_src = odp_packet_input(pkt); for (src_idx = -1, i = 0; gbl_args->pktios[i] != ODP_PKTIO_INVALID; ++i) if (gbl_args->pktios[i] == pktio_src) src_idx = i; if (src_idx == -1) LOG_ABORT("Failed to determine pktio input\n"); dst_idx = (src_idx % 2 == 0) ? src_idx+1 : src_idx-1; pktio_dst = gbl_args->pktios[dst_idx]; return odp_pktio_outq_getdef(pktio_dst); }
static int send_recv(odp_packet_t packet, int send_nb, int expt_nb) { static int test_id = 0; printf("send_recv %d\n", test_id++); odp_pktio_t pktio; odp_queue_t outq_def; odp_packet_t pkt_tbl[MAX_PKT_BURST]; pktio = odp_pktio_lookup(pktio_valid_name); if (pktio == ODP_PKTIO_INVALID) { printf("Error: lookup of pktio %s failed\n", pktio_valid_name); return 1; } outq_def = odp_pktio_outq_getdef(pktio); if (outq_def == ODP_QUEUE_INVALID) { printf("Error: def output-Q query\n"); return 1; } int i; for ( i = 0; i < send_nb; ++i ) { odp_queue_enq(outq_def, (odp_event_t)packet); } int ret = 0; int start = __k1_read_dsu_timestamp(); while ( ret >= 0 && ret < expt_nb && ( __k1_read_dsu_timestamp() - start ) < 10 * __bsp_frequency ) { int n_pkt = odp_pktio_recv(pktio, pkt_tbl, MAX_PKT_BURST); ret += n_pkt; if (n_pkt > 0) odp_packet_free_multi(pkt_tbl, n_pkt); } test_assert_ret(ret == expt_nb); odp_packet_free(packet); printf("send_recv %d OK\n", test_id); return 0; }
/** * Initialize interface * * Initialize ODP pktio and queues, query MAC address and update * forwarding database. * * @param intf Interface name string */ static void initialize_intf(char *intf) { odp_pktio_t pktio; odp_queue_t outq_def; odp_queue_t inq_def; char inq_name[ODP_QUEUE_NAME_LEN]; odp_queue_param_t qparam; int ret; uint8_t src_mac[ODPH_ETHADDR_LEN]; char src_mac_str[MAX_STRING]; odp_pktio_param_t pktio_param; odp_pktio_param_init(&pktio_param); if (getenv("ODP_IPSEC_USE_POLL_QUEUES")) pktio_param.in_mode = ODP_PKTIN_MODE_QUEUE; else pktio_param.in_mode = ODP_PKTIN_MODE_SCHED; /* * Open a packet IO instance for thread and get default output queue */ pktio = odp_pktio_open(intf, pkt_pool, &pktio_param); if (ODP_PKTIO_INVALID == pktio) { EXAMPLE_ERR("Error: pktio create failed for %s\n", intf); exit(EXIT_FAILURE); } outq_def = odp_pktio_outq_getdef(pktio); /* * Create and set the default INPUT queue associated with the 'pktio' * resource */ odp_queue_param_init(&qparam); qparam.type = ODP_QUEUE_TYPE_PKTIN; qparam.sched.prio = ODP_SCHED_PRIO_DEFAULT; qparam.sched.sync = ODP_SCHED_SYNC_ATOMIC; qparam.sched.group = ODP_SCHED_GROUP_ALL; snprintf(inq_name, sizeof(inq_name), "%" PRIu64 "-pktio_inq_def", odp_pktio_to_u64(pktio)); inq_name[ODP_QUEUE_NAME_LEN - 1] = '\0'; inq_def = queue_create(inq_name, &qparam); if (ODP_QUEUE_INVALID == inq_def) { EXAMPLE_ERR("Error: pktio queue creation failed for %s\n", intf); exit(EXIT_FAILURE); } ret = odp_pktio_inq_setdef(pktio, inq_def); if (ret) { EXAMPLE_ERR("Error: default input-Q setup for %s\n", intf); exit(EXIT_FAILURE); } ret = odp_pktio_start(pktio); if (ret) { EXAMPLE_ERR("Error: unable to start %s\n", intf); exit(EXIT_FAILURE); } /* Read the source MAC address for this interface */ ret = odp_pktio_mac_addr(pktio, src_mac, sizeof(src_mac)); if (ret <= 0) { EXAMPLE_ERR("Error: failed during MAC address get for %s\n", intf); exit(EXIT_FAILURE); } printf("Created pktio:%02" PRIu64 ", queue mode (ATOMIC queues)\n" " default pktio%02" PRIu64 "-INPUT queue:%" PRIu64 "\n" " source mac address %s\n", odp_pktio_to_u64(pktio), odp_pktio_to_u64(pktio), odp_queue_to_u64(inq_def), mac_addr_str(src_mac_str, src_mac)); /* Resolve any routes using this interface for output */ resolve_fwd_db(intf, outq_def, src_mac); }
/** * Packet IO loopback worker thread using ODP queues * * @param arg thread arguments of type 'thread_args_t *' */ static void *pktio_queue_thread(void *arg) { int thr; odp_buffer_pool_t pkt_pool; odp_pktio_t pktio; thread_args_t *thr_args; odp_queue_t outq_def; odp_queue_t inq_def; char inq_name[ODP_QUEUE_NAME_LEN]; odp_queue_param_t qparam; odp_packet_t pkt; odp_buffer_t buf; int ret; unsigned long pkt_cnt = 0; unsigned long err_cnt = 0; odp_pktio_params_t params; socket_params_t *sock_params = ¶ms.sock_params; thr = odp_thread_id(); thr_args = arg; printf("Pktio thread [%02i] starts, pktio_dev:%s\n", thr, thr_args->pktio_dev); /* Lookup the packet pool */ pkt_pool = odp_buffer_pool_lookup("packet_pool"); if (pkt_pool == ODP_BUFFER_POOL_INVALID || pkt_pool != thr_args->pool) { ODP_ERR(" [%02i] Error: pkt_pool not found\n", thr); return NULL; } /* Open a packet IO instance for this thread */ sock_params->type = thr_args->type; sock_params->fanout = thr_args->fanout; pktio = odp_pktio_open(thr_args->pktio_dev, pkt_pool, ¶ms); if (pktio == ODP_PKTIO_INVALID) { ODP_ERR(" [%02i] Error: pktio create failed\n", thr); return NULL; } /* * Create and set the default INPUT queue associated with the 'pktio' * resource */ qparam.sched.prio = ODP_SCHED_PRIO_DEFAULT; qparam.sched.sync = ODP_SCHED_SYNC_ATOMIC; qparam.sched.group = ODP_SCHED_GROUP_DEFAULT; snprintf(inq_name, sizeof(inq_name), "%i-pktio_inq_def", (int)pktio); inq_name[ODP_QUEUE_NAME_LEN - 1] = '\0'; inq_def = odp_queue_create(inq_name, ODP_QUEUE_TYPE_PKTIN, &qparam); if (inq_def == ODP_QUEUE_INVALID) { ODP_ERR(" [%02i] Error: pktio queue creation failed\n", thr); return NULL; } ret = odp_pktio_inq_setdef(pktio, inq_def); if (ret != 0) { ODP_ERR(" [%02i] Error: default input-Q setup\n", thr); return NULL; } printf(" [%02i] created pktio:%02i, queue mode (ATOMIC queues)\n" " default pktio%02i-INPUT queue:%u\n", thr, pktio, pktio, inq_def); /* Loop packets */ for (;;) { odp_pktio_t pktio_tmp; #if 1 /* Use schedule to get buf from any input queue */ buf = odp_schedule(NULL, ODP_SCHED_WAIT); #else /* Always dequeue from the same input queue */ buf = odp_queue_deq(inq_def); if (!odp_buffer_is_valid(buf)) continue; #endif pkt = odp_packet_from_buffer(buf); /* Drop packets with errors */ if (odp_unlikely(drop_err_pkts(&pkt, 1) == 0)) { ODP_ERR("Drop frame - err_cnt:%lu\n", ++err_cnt); continue; } pktio_tmp = odp_pktio_get_input(pkt); outq_def = odp_pktio_outq_getdef(pktio_tmp); if (outq_def == ODP_QUEUE_INVALID) { ODP_ERR(" [%02i] Error: def output-Q query\n", thr); return NULL; } /* Swap Eth MACs and possibly IP-addrs before sending back */ swap_pkt_addrs(&pkt, 1); /* Enqueue the packet for output */ odp_queue_enq(outq_def, buf); /* Print packet counts every once in a while */ if (odp_unlikely(pkt_cnt++ % 100000 == 0)) { printf(" [%02i] pkt_cnt:%lu\n", thr, pkt_cnt); fflush(NULL); } } /* unreachable */ }
/* * Main packet transmit routine. Transmit packets at a fixed rate for * specified length of time. */ static void *run_thread_tx(void *arg) { test_globals_t *globals; int thr_id; odp_queue_t outq; pkt_tx_stats_t *stats; uint64_t next_tx_cycles, end_cycles, cur_cycles; uint64_t burst_gap_cycles; uint32_t batch_len; int unsent_pkts = 0; odp_event_t tx_event[BATCH_LEN_MAX]; uint64_t idle_start = 0; thread_args_t *targs = arg; batch_len = targs->batch_len; if (batch_len > BATCH_LEN_MAX) batch_len = BATCH_LEN_MAX; thr_id = odp_thread_id(); globals = odp_shm_addr(odp_shm_lookup("test_globals")); stats = &globals->tx_stats[thr_id]; outq = odp_pktio_outq_getdef(globals->pktio_tx); if (outq == ODP_QUEUE_INVALID) LOG_ABORT("Failed to get output queue for thread %d\n", thr_id); burst_gap_cycles = odp_time_ns_to_cycles( (ODP_TIME_SEC * 999) / (1000 * targs->pps / (targs->batch_len))); odp_barrier_wait(&globals->tx_barrier); cur_cycles = odp_time_cycles(); next_tx_cycles = cur_cycles; end_cycles = cur_cycles + odp_time_ns_to_cycles(targs->duration * ODP_TIME_SEC); while (cur_cycles < end_cycles) { unsigned alloc_cnt = 0, tx_cnt; if (cur_cycles < next_tx_cycles) { cur_cycles = odp_time_cycles(); if (idle_start == 0) idle_start = cur_cycles; continue; } if (idle_start) { stats->s.idle_cycles += odp_time_diff_cycles( idle_start, cur_cycles); idle_start = 0; } next_tx_cycles += burst_gap_cycles; alloc_cnt = alloc_packets(tx_event, batch_len - unsent_pkts); if (alloc_cnt != batch_len) stats->s.alloc_failures++; tx_cnt = send_packets(outq, tx_event, alloc_cnt); unsent_pkts = alloc_cnt - tx_cnt; stats->s.enq_failures += unsent_pkts; stats->s.tx_cnt += tx_cnt; cur_cycles = odp_time_cycles(); } VPRINT(" %02d: TxPkts %-8"PRIu64" EnqFail %-6"PRIu64 " AllocFail %-6"PRIu64" Idle %"PRIu64"ms\n", thr_id, stats->s.tx_cnt, stats->s.enq_failures, stats->s.alloc_failures, odp_time_cycles_to_ns(stats->s.idle_cycles)/1000/1000); return NULL; }
static void *gen_send_thread(void *arg) { int thr; odp_pktio_t pktio; thread_args_t *thr_args; odp_queue_t outq_def; odp_packet_t pkt[PKT_BURST_SZ]; thr = odp_thread_id(); thr_args = arg; pktio = odp_pktio_lookup(thr_args->pktio_dev); if (pktio == ODP_PKTIO_INVALID) { EXAMPLE_ERR(" [%02i] Error: lookup of pktio %s failed\n", thr, thr_args->pktio_dev); return NULL; } outq_def = odp_pktio_outq_getdef(pktio); if (outq_def == ODP_QUEUE_INVALID) { EXAMPLE_ERR(" [%02i] Error: def output-Q query\n", thr); return NULL; } printf(" [%02i] created mode: SEND\n", thr); for (int i = 0; i < PKT_BURST_SZ; ++i) { if (args->appl.mode == APPL_MODE_UDP) pkt[i] = pack_udp_pkt(thr_args->pool); else if (args->appl.mode == APPL_MODE_PING) pkt[i] = pack_icmp_pkt(thr_args->pool); else pkt[i] = ODP_PACKET_INVALID; if (!odp_packet_is_valid(pkt[i])) { EXAMPLE_ERR(" [%2i] alloc_single failed\n", thr); return NULL; } } for (;;) { int err; err = odp_queue_enq_multi(outq_def, (odp_event_t*)pkt, PKT_BURST_SZ); if (err != PKT_BURST_SZ) { /* EXAMPLE_ERR(" [%02i] send pkt err!\n", thr); */ /* return NULL; */ } static uint64_t toto = 0; if (args->appl.interval != 0) { printf(" [%02i] send pkt no:%"PRIu64" seq %"PRIu64"\n", thr, odp_atomic_load_u64(&counters.seq), toto++); usleep(args->appl.interval); /* millisleep(args->appl.interval, */ /* thr_args->tp, */ /* thr_args->tim, */ /* thr_args->tq, */ /* thr_args->tmo_ev); */ } } printf("Done\n"); _exit(0); /* receive number of reply pks until timeout */ if (args->appl.mode == APPL_MODE_PING && args->appl.number > 0) { while (args->appl.timeout >= 0) { if (odp_atomic_load_u64(&counters.icmp) >= (unsigned int)args->appl.number) break; millisleep(DEFAULT_PKT_INTERVAL, thr_args->tp, thr_args->tim, thr_args->tq, thr_args->tmo_ev); args->appl.timeout--; } } return arg; }
void pktio_test_start_stop(void) { odp_pktio_t pktio[MAX_NUM_IFACES]; odp_packet_t pkt; odp_event_t tx_ev[100]; odp_event_t ev; int i, pkts, ret, alloc = 0; odp_queue_t outq; uint64_t wait = odp_schedule_wait_time(ODP_TIME_MSEC_IN_NS); for (i = 0; i < num_ifaces; i++) { pktio[i] = create_pktio(i, ODP_PKTIN_MODE_SCHED, ODP_PKTOUT_MODE_SEND); CU_ASSERT_FATAL(pktio[i] != ODP_PKTIO_INVALID); create_inq(pktio[i], ODP_QUEUE_TYPE_SCHED); } outq = odp_pktio_outq_getdef(pktio[0]); /* Interfaces are stopped by default, * Check that stop when stopped generates an error */ ret = odp_pktio_stop(pktio[0]); CU_ASSERT(ret <= 0); /* start first */ ret = odp_pktio_start(pktio[0]); CU_ASSERT(ret == 0); /* Check that start when started generates an error */ ret = odp_pktio_start(pktio[0]); CU_ASSERT(ret < 0); /* Test Rx on a stopped interface. Only works if there are 2 */ if (num_ifaces > 1) { for (alloc = 0; alloc < 100; alloc++) { pkt = odp_packet_alloc(default_pkt_pool, packet_len); if (pkt == ODP_PACKET_INVALID) break; pktio_init_packet(pkt); pktio_pkt_set_macs(pkt, pktio[0], pktio[1]); if (pktio_fixup_checksums(pkt) != 0) { odp_packet_free(pkt); break; } tx_ev[alloc] = odp_packet_to_event(pkt); } for (pkts = 0; pkts != alloc; ) { ret = odp_queue_enq_multi(outq, &tx_ev[pkts], alloc - pkts); if (ret < 0) { CU_FAIL("unable to enqueue packet\n"); break; } pkts += ret; } /* check that packets did not arrive */ for (i = 0, pkts = 0; i < 1000; i++) { ev = odp_schedule(NULL, wait); if (ev == ODP_EVENT_INVALID) continue; if (odp_event_type(ev) == ODP_EVENT_PACKET) { pkt = odp_packet_from_event(ev); if (pktio_pkt_seq(pkt) != TEST_SEQ_INVALID) pkts++; } odp_event_free(ev); } if (pkts) CU_FAIL("pktio stopped, received unexpected events"); /* start both, send and get packets */ /* 0 already started */ ret = odp_pktio_start(pktio[1]); CU_ASSERT(ret == 0); /* flush packets with magic number in pipes */ for (i = 0; i < 1000; i++) { ev = odp_schedule(NULL, wait); if (ev != ODP_EVENT_INVALID) odp_event_free(ev); } } /* alloc */ for (alloc = 0; alloc < 100; alloc++) { pkt = odp_packet_alloc(default_pkt_pool, packet_len); if (pkt == ODP_PACKET_INVALID) break; pktio_init_packet(pkt); if (num_ifaces > 1) { pktio_pkt_set_macs(pkt, pktio[0], pktio[1]); if (pktio_fixup_checksums(pkt) != 0) { odp_packet_free(pkt); break; } } tx_ev[alloc] = odp_packet_to_event(pkt); } /* send */ for (pkts = 0; pkts != alloc; ) { ret = odp_queue_enq_multi(outq, &tx_ev[pkts], alloc - pkts); if (ret < 0) { CU_FAIL("unable to enqueue packet\n"); break; } pkts += ret; } /* get */ for (i = 0, pkts = 0; i < 100; i++) { ev = odp_schedule(NULL, wait); if (ev != ODP_EVENT_INVALID) { if (odp_event_type(ev) == ODP_EVENT_PACKET) { pkt = odp_packet_from_event(ev); if (pktio_pkt_seq(pkt) != TEST_SEQ_INVALID) pkts++; } odp_event_free(ev); } } CU_ASSERT(pkts == alloc); for (i = 0; i < num_ifaces; i++) { CU_ASSERT(odp_pktio_stop(pktio[i]) == 0); destroy_inq(pktio[i]); CU_ASSERT(odp_pktio_close(pktio[i]) == 0); } }
/* * Main packet transmit routine. Transmit packets at a fixed rate for * specified length of time. */ static void *run_thread_tx(void *arg) { test_globals_t *globals; int thr_id; odp_queue_t outq; pkt_tx_stats_t *stats; odp_time_t cur_time, send_time_end, send_duration; odp_time_t burst_gap_end, burst_gap; uint32_t batch_len; int unsent_pkts = 0; odp_event_t tx_event[BATCH_LEN_MAX]; odp_time_t idle_start = ODP_TIME_NULL; thread_args_t *targs = arg; batch_len = targs->batch_len; if (batch_len > BATCH_LEN_MAX) batch_len = BATCH_LEN_MAX; thr_id = odp_thread_id(); globals = odp_shm_addr(odp_shm_lookup("test_globals")); stats = &globals->tx_stats[thr_id]; outq = odp_pktio_outq_getdef(globals->pktio_tx); if (outq == ODP_QUEUE_INVALID) LOG_ABORT("Failed to get output queue for thread %d\n", thr_id); burst_gap = odp_time_local_from_ns( ODP_TIME_SEC_IN_NS / (targs->pps / targs->batch_len)); send_duration = odp_time_local_from_ns(targs->duration * ODP_TIME_SEC_IN_NS); odp_barrier_wait(&globals->tx_barrier); cur_time = odp_time_local(); send_time_end = odp_time_sum(cur_time, send_duration); burst_gap_end = cur_time; while (odp_time_cmp(send_time_end, cur_time) > 0) { unsigned alloc_cnt = 0, tx_cnt; if (odp_time_cmp(burst_gap_end, cur_time) > 0) { cur_time = odp_time_local(); if (!odp_time_cmp(idle_start, ODP_TIME_NULL)) idle_start = cur_time; continue; } if (odp_time_cmp(idle_start, ODP_TIME_NULL) > 0) { odp_time_t diff = odp_time_diff(cur_time, idle_start); stats->s.idle_ticks = odp_time_sum(diff, stats->s.idle_ticks); idle_start = ODP_TIME_NULL; } burst_gap_end = odp_time_sum(burst_gap_end, burst_gap); alloc_cnt = alloc_packets(tx_event, batch_len - unsent_pkts); if (alloc_cnt != batch_len) stats->s.alloc_failures++; tx_cnt = send_packets(outq, tx_event, alloc_cnt); unsent_pkts = alloc_cnt - tx_cnt; stats->s.enq_failures += unsent_pkts; stats->s.tx_cnt += tx_cnt; cur_time = odp_time_local(); } VPRINT(" %02d: TxPkts %-8"PRIu64" EnqFail %-6"PRIu64 " AllocFail %-6"PRIu64" Idle %"PRIu64"ms\n", thr_id, stats->s.tx_cnt, stats->s.enq_failures, stats->s.alloc_failures, odp_time_to_ns(stats->s.idle_ticks) / (uint64_t)ODP_TIME_MSEC_IN_NS); return NULL; }