/** * Set up the DPDK rings which will be used to pass packets, via * pointers, between the multi-process server and client processes. * Each client needs one RX queue. */ static int init_shm_rings(void) { unsigned i; const unsigned ringsize = CLIENT_QUEUE_RINGSIZE; clients = rte_malloc("client details", sizeof(*clients) * num_clients, 0); if (clients == NULL) rte_exit(EXIT_FAILURE, "Cannot allocate memory for client program details\n"); port_queues = rte_malloc("port_txq details", sizeof(*port_queues) * ports->num_ports, 0); if (port_queues == NULL) rte_exit(EXIT_FAILURE, "Cannot allocate memory for port tx_q details\n"); for (i = 0; i < num_clients; i++) { /* Create an RX queue for each client */ clients[i].rx_q = rte_ring_create(get_rx_queue_name(i), ringsize, SOCKET0, NO_FLAGS); /* multi producer multi consumer*/ if (clients[i].rx_q == NULL) rte_exit(EXIT_FAILURE, "Cannot create rx ring for client %u\n", i); clients[i].tx_q = rte_ring_create(get_tx_queue_name(i), ringsize, SOCKET0, NO_FLAGS); /* multi producer multi consumer*/ if (clients[i].tx_q == NULL) rte_exit(EXIT_FAILURE, "Cannot create tx ring for client %u\n", i); } for (i = 0; i < ports->num_ports; i++) { /* Create an RX queue for each ports */ port_queues[i].tx_q = rte_ring_create(get_port_tx_queue_name(i), ringsize, SOCKET0, RING_F_SC_DEQ); /* multi producer single consumer*/ if (port_queues[i].tx_q == NULL) rte_exit(EXIT_FAILURE, "Cannot create tx ring for port %u\n", i); } vswitch_packet_ring = rte_ring_create(PACKET_RING_NAME, DAEMON_PKT_QUEUE_RINGSIZE, SOCKET0, NO_FLAGS); if (vswitch_packet_ring == NULL) rte_exit(EXIT_FAILURE, "Cannot create packet ring for vswitchd"); return 0; }
/** * Set up the DPDK rings which will be used to pass packets, via * pointers, between the multi-process server and NF processes. * Each NF needs one RX queue. */ static int init_shm_rings(void) { unsigned i; unsigned socket_id; const char * rq_name; const char * tq_name; const char * msg_q_name; const unsigned ringsize = NF_QUEUE_RINGSIZE; const unsigned msgringsize = NF_MSG_QUEUE_SIZE; // use calloc since we allocate for all possible NFs // ensure that all fields are init to 0 to avoid reading garbage // TODO plopreiato, move to creation when a NF starts for (i = 0; i < MAX_NFS; i++) { /* Create an RX queue for each NF */ socket_id = rte_socket_id(); rq_name = get_rx_queue_name(i); tq_name = get_tx_queue_name(i); msg_q_name = get_msg_queue_name(i); nfs[i].instance_id = i; nfs[i].rx_q = rte_ring_create(rq_name, ringsize, socket_id, RING_F_SC_DEQ); /* multi prod, single cons */ nfs[i].tx_q = rte_ring_create(tq_name, ringsize, socket_id, RING_F_SC_DEQ); /* multi prod, single cons */ nfs[i].msg_q = rte_ring_create(msg_q_name, msgringsize, socket_id, RING_F_SC_DEQ); /* multi prod, single cons */ if (nfs[i].rx_q == NULL) rte_exit(EXIT_FAILURE, "Cannot create rx ring queue for NF %u\n", i); if (nfs[i].tx_q == NULL) rte_exit(EXIT_FAILURE, "Cannot create tx ring queue for NF %u\n", i); if (nfs[i].msg_q == NULL) rte_exit(EXIT_FAILURE, "Cannot create msg queue for NF %u\n", i); } return 0; }
/* * Application main function - loops through * receiving and processing packets. Never returns */ int main(int argc, char *argv[]) { struct rte_ring *rx_ring = NULL; struct rte_ring *tx_ring = NULL; int retval = 0; void *pkts[PKT_READ_SIZE]; int rslt = 0; if ((retval = rte_eal_init(argc, argv)) < 0) { return -1; } argc -= retval; argv += retval; if (parse_app_args(argc, argv) < 0) { rte_exit(EXIT_FAILURE, "Invalid command-line arguments\n"); } rx_ring = rte_ring_lookup(get_rx_queue_name(client_id)); if (rx_ring == NULL) { rte_exit(EXIT_FAILURE, "Cannot get RX ring - is server process running?\n"); } tx_ring = rte_ring_lookup(get_tx_queue_name(client_id)); if (tx_ring == NULL) { rte_exit(EXIT_FAILURE, "Cannot get TX ring - is server process running?\n"); } RTE_LOG(INFO, APP, "Finished Process Init.\n"); printf("\nClient process %d handling packets\n", client_id); printf("[Press Ctrl-C to quit ...]\n"); for (;;) { unsigned rx_pkts = PKT_READ_SIZE; /* Try dequeuing max possible packets first, if that fails, get the * most we can. Loop body should only execute once, maximum. */ while (unlikely(rte_ring_dequeue_bulk(rx_ring, pkts, rx_pkts) != 0) && rx_pkts > 0) { rx_pkts = (uint16_t)RTE_MIN(rte_ring_count(rx_ring), PKT_READ_SIZE); } if (rx_pkts > 0) { pkt++; /* blocking enqueue */ do { rslt = rte_ring_enqueue_bulk(tx_ring, pkts, rx_pkts); } while (rslt == -ENOBUFS); } else { no_pkt++; } if (!(pkt % 100000)) { printf("pkt %d %d\n", pkt, no_pkt); pkt = no_pkt = 0; } } }
/** * CALLED BY NF: * Initialises everything we need * * Returns the number of arguments parsed by both rte_eal_init and * parse_nflib_args offset by 1. This is used by getopt in the NF's * code. The offsetting by one accounts for getopt parsing "--" which * increments optind by 1 each time. */ int onvm_nf_init(int argc, char *argv[], const char *nf_tag) { const struct rte_memzone *mz; const struct rte_memzone *mz_scp; struct rte_mempool *mp; struct onvm_service_chain **scp; int retval_eal, retval_parse, retval_final; if ((retval_eal = rte_eal_init(argc, argv)) < 0) return -1; /* Modify argc and argv to conform to getopt rules for parse_nflib_args */ argc -= retval_eal; argv += retval_eal; /* Reset getopt global variables opterr and optind to their default values */ opterr = 0; optind = 1; if ((retval_parse = parse_nflib_args(argc, argv)) < 0) rte_exit(EXIT_FAILURE, "Invalid command-line arguments\n"); /* * Calculate the offset that the nf will use to modify argc and argv for its * getopt call. This is the sum of the number of arguments parsed by * rte_eal_init and parse_nflib_args. This will be decremented by 1 to assure * getopt is looking at the correct index since optind is incremented by 1 each * time "--" is parsed. * This is the value that will be returned if initialization succeeds. */ retval_final = (retval_eal + retval_parse) - 1; /* Reset getopt global variables opterr and optind to their default values */ opterr = 0; optind = 1; /* Lookup mempool for nf_info struct */ nf_info_mp = rte_mempool_lookup(_NF_MEMPOOL_NAME); if (nf_info_mp == NULL) rte_exit(EXIT_FAILURE, "No Client Info mempool - bye\n"); /* Initialize the info struct */ nf_info = ovnm_nf_info_init(nf_tag); mp = rte_mempool_lookup(PKTMBUF_POOL_NAME); if (mp == NULL) rte_exit(EXIT_FAILURE, "Cannot get mempool for mbufs\n"); mz = rte_memzone_lookup(MZ_CLIENT_INFO); if (mz == NULL) rte_exit(EXIT_FAILURE, "Cannot get tx info structure\n"); tx_stats = mz->addr; mz_scp = rte_memzone_lookup(MZ_SCP_INFO); if (mz_scp == NULL) rte_exit(EXIT_FAILURE, "Cannot get service chain info structre\n"); scp = mz_scp->addr; default_chain = *scp; onvm_sc_print(default_chain); nf_info_ring = rte_ring_lookup(_NF_QUEUE_NAME); if (nf_info_ring == NULL) rte_exit(EXIT_FAILURE, "Cannot get nf_info ring"); /* Put this NF's info struct onto queue for manager to process startup */ if (rte_ring_enqueue(nf_info_ring, nf_info) < 0) { rte_mempool_put(nf_info_mp, nf_info); // give back mermory rte_exit(EXIT_FAILURE, "Cannot send nf_info to manager"); } /* Wait for a client id to be assigned by the manager */ RTE_LOG(INFO, APP, "Waiting for manager to assign an ID...\n"); for (; nf_info->status == (uint16_t)NF_WAITING_FOR_ID ;) { sleep(1); } /* This NF is trying to declare an ID already in use. */ if (nf_info->status == NF_ID_CONFLICT) { rte_mempool_put(nf_info_mp, nf_info); rte_exit(NF_ID_CONFLICT, "Selected ID already in use. Exiting...\n"); } else if(nf_info->status == NF_NO_IDS) { rte_mempool_put(nf_info_mp, nf_info); rte_exit(NF_NO_IDS, "There are no ids available for this NF\n"); } else if(nf_info->status != NF_STARTING) { rte_mempool_put(nf_info_mp, nf_info); rte_exit(EXIT_FAILURE, "Error occurred during manager initialization\n"); } RTE_LOG(INFO, APP, "Using Instance ID %d\n", nf_info->instance_id); RTE_LOG(INFO, APP, "Using Service ID %d\n", nf_info->service_id); /* Now, map rx and tx rings into client space */ rx_ring = rte_ring_lookup(get_rx_queue_name(nf_info->instance_id)); if (rx_ring == NULL) rte_exit(EXIT_FAILURE, "Cannot get RX ring - is server process running?\n"); tx_ring = rte_ring_lookup(get_tx_queue_name(nf_info->instance_id)); if (tx_ring == NULL) rte_exit(EXIT_FAILURE, "Cannot get TX ring - is server process running?\n"); /* Tell the manager we're ready to recieve packets */ nf_info->status = NF_RUNNING; RTE_LOG(INFO, APP, "Finished Process Init.\n"); return retval_final; }