/** * 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_pktout_queue_t pktout; odp_queue_t inq; int ret; uint8_t src_mac[ODPH_ETHADDR_LEN]; char src_mac_str[MAX_STRING]; odp_pktio_param_t pktio_param; odp_pktin_queue_param_t pktin_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); } odp_pktin_queue_param_init(&pktin_param); pktin_param.queue_param.sched.sync = ODP_SCHED_SYNC_ATOMIC; if (odp_pktin_queue_config(pktio, &pktin_param)) { EXAMPLE_ERR("Error: pktin config failed for %s\n", intf); exit(EXIT_FAILURE); } if (odp_pktout_queue_config(pktio, NULL)) { EXAMPLE_ERR("Error: pktout config failed for %s\n", intf); exit(EXIT_FAILURE); } if (odp_pktin_event_queue(pktio, &inq, 1) != 1) { EXAMPLE_ERR("Error: failed to get input queue for %s\n", intf); exit(EXIT_FAILURE); } if (odp_pktout_queue(pktio, &pktout, 1) != 1) { EXAMPLE_ERR("Error: failed to get pktout queue 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), mac_addr_str(src_mac_str, src_mac)); /* Resolve any routes using this interface for output */ resolve_fwd_db(intf, pktout, src_mac); }
/** * Create a pktio handle * * @param dev Name of device to open * @param index Pktio index * @param num_rx Number of RX queues * @param num_tx Number of TX queues * @param pool Pool to associate with device for packet RX/TX * * @retval 0 on success * @retval -1 on failure */ static int create_pktio(const char *dev, int idx, int num_rx, int num_tx, odp_pool_t pool) { odp_pktio_t pktio; odp_pktio_param_t pktio_param; odp_pktio_capability_t capa; odp_pktin_queue_param_t pktin_param; odp_pktout_queue_param_t pktout_param; odp_pktio_op_mode_t mode_rx; odp_pktio_op_mode_t mode_tx; odp_pktio_param_init(&pktio_param); pktio = odp_pktio_open(dev, pool, &pktio_param); if (pktio == ODP_PKTIO_INVALID) { printf("Error: failed to open %s\n", dev); return -1; } printf("created pktio %" PRIu64 " (%s)\n", odp_pktio_to_u64(pktio), dev); if (odp_pktio_capability(pktio, &capa)) { printf("Error: capability query failed %s\n", dev); return -1; } odp_pktin_queue_param_init(&pktin_param); odp_pktout_queue_param_init(&pktout_param); mode_tx = ODP_PKTIO_OP_MT_UNSAFE; mode_rx = ODP_PKTIO_OP_MT_UNSAFE; if (num_rx > (int)capa.max_input_queues) { printf("Sharing %i input queues between %i workers\n", capa.max_input_queues, num_rx); num_rx = capa.max_input_queues; mode_rx = ODP_PKTIO_OP_MT; } if (num_tx > (int)capa.max_output_queues) { printf("Sharing %i output queues between %i workers\n", capa.max_output_queues, num_tx); num_tx = capa.max_output_queues; mode_tx = ODP_PKTIO_OP_MT; } pktin_param.hash_enable = 1; pktin_param.hash_proto.proto.ipv4 = 1; pktin_param.hash_proto.proto.ipv4_tcp = 1; pktin_param.hash_proto.proto.ipv4_udp = 1; pktin_param.num_queues = num_rx; pktin_param.op_mode = mode_rx; pktout_param.op_mode = mode_tx; pktout_param.num_queues = num_tx; if (odp_pktin_queue_config(pktio, &pktin_param)) { printf("Error: input queue config failed %s\n", dev); return -1; } if (odp_pktout_queue_config(pktio, &pktout_param)) { printf("Error: output queue config failed %s\n", dev); return -1; } if (odp_pktin_queue(pktio, gbl_args->pktios[idx].pktin, num_rx) != num_rx) { printf("Error: pktin queue query failed %s\n", dev); return -1; } if (odp_pktout_queue(pktio, gbl_args->pktios[idx].pktout, num_tx) != num_tx) { printf("Error: pktout queue query failed %s\n", dev); return -1; } printf("created %i input and %i output queues on (%s)\n", num_rx, num_tx, dev); gbl_args->pktios[idx].num_rx_queue = num_rx; gbl_args->pktios[idx].num_tx_queue = num_tx; gbl_args->pktios[idx].pktio = pktio; return 0; }
static int netmap_start(pktio_entry_t *pktio_entry) { pkt_netmap_t *pkt_nm = &pktio_entry->s.pkt_nm; netmap_ring_t *desc_ring; struct nm_desc base_desc; unsigned i; unsigned j; unsigned num_rx_desc = 0; uint64_t flags; odp_pktin_mode_t in_mode = pktio_entry->s.param.in_mode; odp_pktout_mode_t out_mode = pktio_entry->s.param.out_mode; /* If no pktin/pktout queues have been configured. Configure one * for each direction. */ if (!pktio_entry->s.num_in_queue && in_mode != ODP_PKTIN_MODE_DISABLED) { odp_pktin_queue_param_t param; odp_pktin_queue_param_init(¶m); param.num_queues = 1; if (odp_pktin_queue_config(pktio_entry->s.handle, ¶m)) return -1; } if (!pktio_entry->s.num_out_queue && out_mode == ODP_PKTOUT_MODE_DIRECT) { odp_pktout_queue_param_t param; odp_pktout_queue_param_init(¶m); param.num_queues = 1; if (odp_pktout_queue_config(pktio_entry->s.handle, ¶m)) return -1; } if (pkt_nm->num_rx_desc_rings == pktio_entry->s.num_in_queue && pkt_nm->num_tx_desc_rings == pktio_entry->s.num_out_queue) return (netmap_wait_for_link(pktio_entry) == 1) ? 0 : -1; netmap_close_descriptors(pktio_entry); /* Map pktin/pktout queues to netmap rings */ if (pktio_entry->s.num_in_queue) { /* In single queue case only one netmap descriptor is * required. */ num_rx_desc = (pktio_entry->s.num_in_queue == 1) ? 1 : pkt_nm->num_rx_rings; map_netmap_rings(pkt_nm->rx_desc_ring, pktio_entry->s.num_in_queue, num_rx_desc); } if (pktio_entry->s.num_out_queue) /* Enough to map only one netmap tx ring per pktout queue */ map_netmap_rings(pkt_nm->tx_desc_ring, pktio_entry->s.num_out_queue, pktio_entry->s.num_out_queue); base_desc.self = &base_desc; base_desc.mem = NULL; memcpy(base_desc.req.nr_name, pktio_entry->s.name, sizeof(pktio_entry->s.name)); base_desc.req.nr_flags &= ~NR_REG_MASK; if (num_rx_desc == 1) base_desc.req.nr_flags |= NR_REG_ALL_NIC; else base_desc.req.nr_flags |= NR_REG_ONE_NIC; base_desc.req.nr_ringid = 0; /* Only the first rx descriptor does mmap */ desc_ring = pkt_nm->rx_desc_ring; flags = NM_OPEN_IFNAME | NETMAP_NO_TX_POLL; desc_ring[0].s.desc[0] = nm_open(pkt_nm->nm_name, NULL, flags, &base_desc); if (desc_ring[0].s.desc[0] == NULL) { ODP_ERR("nm_start(%s) failed\n", pkt_nm->nm_name); goto error; } /* Open rest of the rx descriptors (one per netmap ring) */ flags = NM_OPEN_IFNAME | NETMAP_NO_TX_POLL | NM_OPEN_NO_MMAP; for (i = 0; i < pktio_entry->s.num_in_queue; i++) for (j = desc_ring[i].s.first; j <= desc_ring[i].s.last; j++) { if (i == 0 && j == 0) { /* First already opened */ if (num_rx_desc > 1) continue; else break; } base_desc.req.nr_ringid = j; desc_ring[i].s.desc[j] = nm_open(pkt_nm->nm_name, NULL, flags, &base_desc); if (desc_ring[i].s.desc[j] == NULL) { ODP_ERR("nm_start(%s) failed\n", pkt_nm->nm_name); goto error; } } /* Open tx descriptors */ desc_ring = pkt_nm->tx_desc_ring; flags = NM_OPEN_IFNAME | NM_OPEN_NO_MMAP; base_desc.req.nr_flags &= !NR_REG_ALL_NIC; base_desc.req.nr_flags |= NR_REG_ONE_NIC; for (i = 0; i < pktio_entry->s.num_out_queue; i++) for (j = desc_ring[i].s.first; j <= desc_ring[i].s.last; j++) { base_desc.req.nr_ringid = j; desc_ring[i].s.desc[j] = nm_open(pkt_nm->nm_name, NULL, flags, &base_desc); if (desc_ring[i].s.desc[j] == NULL) { ODP_ERR("nm_start(%s) failed\n", pkt_nm->nm_name); goto error; } } pkt_nm->num_rx_desc_rings = pktio_entry->s.num_in_queue; pkt_nm->num_tx_desc_rings = pktio_entry->s.num_out_queue; /* Wait for the link to come up */ return (netmap_wait_for_link(pktio_entry) == 1) ? 0 : -1; error: netmap_close_descriptors(pktio_entry); return -1; }
/** main() Application entry point * * @param argc int * @param argv[] char* * @return int * */ int main(int argc, char *argv[]) { odph_linux_pthread_t thread_tbl[MAX_WORKERS], dispatcher_thread; appl_args_t params; int core_count, num_workers; odp_cpumask_t cpu_mask; int first_cpu, i; struct pktio_thr_arg pktio_thr_args[MAX_WORKERS]; odp_pktio_param_t pktio_param; odp_pktin_queue_param_t pktin_param; odp_pktout_queue_param_t pktout_param; odp_pktio_t pktio; int port, queue_id; odph_linux_thr_params_t thr_params; odp_instance_t instance; struct pktin_table_s { int num_in_queue; odp_pktin_queue_t in_queue[OFP_PKTIN_QUEUE_MAX]; } pktin_table[OFP_FP_INTERFACE_MAX]; /* Parse and store the application arguments */ parse_args(argc, argv, ¶ms); if (params.if_count > OFP_FP_INTERFACE_MAX) { printf("Error: Invalid number of interfaces: maximum %d\n", OFP_FP_INTERFACE_MAX); exit(EXIT_FAILURE); } if (odp_init_global(&instance, NULL, NULL)) { OFP_ERR("Error: ODP global init failed.\n"); exit(EXIT_FAILURE); } if (odp_init_local(instance, ODP_THREAD_CONTROL)) { OFP_ERR("Error: ODP local init failed.\n"); exit(EXIT_FAILURE); } /* Print both system and application information */ print_info(NO_PATH(argv[0]), ¶ms); core_count = odp_cpu_count(); num_workers = core_count; if (params.core_count && params.core_count < core_count) num_workers = params.core_count; if (num_workers > MAX_WORKERS) num_workers = MAX_WORKERS; /* * By default core #0 runs Linux kernel background tasks. * Start mapping thread from core #1 */ if (num_workers > 1) { num_workers--; first_cpu = 1; } else { OFP_ERR("Burst mode requires multiple cores.\n"); exit(EXIT_FAILURE); } if (num_workers < params.if_count) { OFP_ERR("At least %u fastpath cores required.\n", params.if_count); exit(EXIT_FAILURE); } printf("Num worker threads: %i\n", num_workers); printf("first CPU: %i\n", first_cpu); memset(&app_init_params, 0, sizeof(app_init_params)); app_init_params.linux_core_id = 0; if (ofp_init_global(instance, &app_init_params)) { OFP_ERR("Error: OFP global init failed.\n"); exit(EXIT_FAILURE); } if (ofp_init_local()) { OFP_ERR("Error: OFP local init failed.\n"); exit(EXIT_FAILURE); } odp_pktio_param_init(&pktio_param); pktio_param.in_mode = ODP_PKTIN_MODE_DIRECT; pktio_param.out_mode = ODP_PKTOUT_MODE_DIRECT; odp_pktin_queue_param_init(&pktin_param); pktin_param.op_mode = ODP_PKTIO_OP_MT; pktin_param.hash_enable = 0; pktin_param.hash_proto.all_bits = 0; pktin_param.num_queues = 1; odp_pktout_queue_param_init(&pktout_param); pktout_param.num_queues = 1; pktout_param.op_mode = ODP_PKTIO_OP_MT; for (i = 0; i < params.if_count; i++) { if (ofp_ifnet_create(instance, params.if_names[i], &pktio_param, &pktin_param, &pktout_param) < 0) { OFP_ERR("Failed to init interface %s", params.if_names[i]); exit(EXIT_FAILURE); } pktio = odp_pktio_lookup(params.if_names[i]); if (pktio == ODP_PKTIO_INVALID) { OFP_ERR("Failed locate pktio %s", params.if_names[i]); exit(EXIT_FAILURE); } pktin_table[i].num_in_queue = odp_pktin_queue(pktio, pktin_table[i].in_queue, OFP_PKTIN_QUEUE_MAX); if (pktin_table[i].num_in_queue < 0) { OFP_ERR("Failed get input queues for %s", params.if_names[i]); exit(EXIT_FAILURE); } } memset(thread_tbl, 0, sizeof(thread_tbl)); memset(pktio_thr_args, 0, sizeof(pktio_thr_args)); for (i = 0; i < num_workers; ++i) { pktio_thr_args[i].pkt_func = ofp_eth_vlan_processing; port = i % params.if_count; queue_id = (i / params.if_count) % pktin_table[port].num_in_queue; pktio_thr_args[i].pktin = pktin_table[port].in_queue[queue_id]; odp_cpumask_zero(&cpu_mask); odp_cpumask_set(&cpu_mask, first_cpu + i); thr_params.start = pkt_io_recv; thr_params.arg = &pktio_thr_args[i]; thr_params.thr_type = ODP_THREAD_WORKER; thr_params.instance = instance; odph_linux_pthread_create(&thread_tbl[i], &cpu_mask, &thr_params); } odp_cpumask_zero(&cpu_mask); odp_cpumask_set(&cpu_mask, app_init_params.linux_core_id); thr_params.start = event_dispatcher; thr_params.arg = NULL; thr_params.thr_type = ODP_THREAD_WORKER; thr_params.instance = instance; odph_linux_pthread_create(&dispatcher_thread, &cpu_mask, &thr_params); /* Start CLI */ ofp_start_cli_thread(instance, app_init_params.linux_core_id, params.conf_file); odph_linux_pthread_join(thread_tbl, num_workers); printf("End Main()\n"); return 0; }