Beispiel #1
0
/**
 * main() Application entry point
 *
 * This is the main function of the FPM application, it's a minimalistic
 * example, see 'usage' function for available arguments and usage.
 *
 * Using the number of available cores as input, this example sets up
 * ODP dispatcher threads executing OFP VLAN processesing and starts
 * a CLI function on a managment core.
 *
 * @param argc int
 * @param argv[] char*
 * @return int
 *
 */
int main(int argc, char *argv[])
{
	odph_linux_pthread_t thread_tbl[MAX_WORKERS];
	appl_args_t params;
	int core_count, num_workers, ret_val;
	odp_cpumask_t cpumask;
	char cpumaskstr[64];
	odph_linux_thr_params_t thr_params;
	odp_instance_t instance;

	/* Parse and store the application arguments */
	if (parse_args(argc, argv, &params) != EXIT_SUCCESS)
		return EXIT_FAILURE;

	if (ofp_sigactions_set(ofp_sig_func_stop)) {
		printf("Error: failed to set signal actions.\n");
		return EXIT_FAILURE;
	}

	/*
	 * Before any ODP API functions can be called, we must first init the ODP
	 * globals, e.g. availale accelerators or software implementations for
	 * shared memory, threads, pool, qeueus, sheduler, pktio, timer, crypto
	 * and classification.
	 */
	if (odp_init_global(&instance, NULL, NULL)) {
		printf("Error: ODP global init failed.\n");
		return EXIT_FAILURE;
	}

	/*
	 * When the gloabel ODP level init has been done, we can now issue a
	 * local init per thread. This must also be done before any other ODP API
	 * calls may be made. Local inits are made here for shared memory,
	 * threads, pktio and scheduler.
	 */
	if (odp_init_local(instance, ODP_THREAD_CONTROL) != 0) {
		printf("Error: ODP local init failed.\n");
		odp_term_global(instance);
		return EXIT_FAILURE;
	}

	/* Print both system and application information */
	print_info(NO_PATH(argv[0]), &params);

	/*
	 * Get the number of cores available to ODP, one run-to-completion thread
	 * will be created per core.
	 */
	core_count = odp_cpu_count();
	num_workers = core_count;

	if (params.core_count)
		num_workers = params.core_count;
	if (num_workers > MAX_WORKERS)
		num_workers = MAX_WORKERS;

	/*
	 * This example assumes that core #0 runs Linux kernel background tasks.
	 * By default, cores #1 and beyond will be populated with a OFP
	 * processing thread each.
	 */
	memset(&app_init_params, 0, sizeof(app_init_params));

	app_init_params.linux_core_id = 0;

	if (core_count > 1)
		num_workers--;

	/*
	 * Initializes cpumask with CPUs available for worker threads.
	 * Sets up to 'num' CPUs and returns the count actually set.
	 * Use zero for all available CPUs.
	 */
	num_workers = odp_cpumask_default_worker(&cpumask, num_workers);
	if (odp_cpumask_to_str(&cpumask, cpumaskstr, sizeof(cpumaskstr)) < 0) {
		printf("Error: Too small buffer provided to "
			"odp_cpumask_to_str\n");
		odp_term_local();
		odp_term_global(instance);
		return EXIT_FAILURE;
	}

	printf("Num worker threads: %i\n", num_workers);
	printf("first CPU:          %i\n", odp_cpumask_first(&cpumask));
	printf("cpu mask:           %s\n", cpumaskstr);

	app_init_params.if_count = params.if_count;
	app_init_params.if_names = params.if_names;
	app_init_params.pkt_hook[OFP_HOOK_LOCAL] = fastpath_local_hook;

	/*
	 * Now that ODP has been initalized, we can initialize OFP. This will
	 * open a pktio instance for each interface supplied as argument by the
	 * user.
	 *
	 * General configuration will be to pktio and schedluer queues here in
	 * addition will fast path interface configuration.
	 */
	if (ofp_init_global(instance, &app_init_params) != 0) {
		printf("Error: OFP global init failed.\n");
		ofp_term_global();
		odp_term_local();
		odp_term_global(instance);
		return EXIT_FAILURE;
	}

	if (ofp_init_local() != 0) {
		printf("Error: OFP local init failed.\n");
		ofp_term_local();
		ofp_term_global();
		odp_term_local();
		odp_term_global(instance);
		return EXIT_FAILURE;
	}

	/*
	 * Create and launch dataplane dispatcher worker threads to be placed
	 * according to the cpumask, thread_tbl will be populated with the
	 * created pthread IDs.
	 *
	 * In this case, all threads will run the default_event_dispatcher
	 * function with ofp_eth_vlan_processing as argument.
	 *
	 * If different dispatchers should run, or the same be run with differnt
	 * input arguments, the cpumask is used to control this.
	 */
	memset(thread_tbl, 0, sizeof(thread_tbl));
	thr_params.start = default_event_dispatcher;
	thr_params.arg = ofp_eth_vlan_processing;
	thr_params.thr_type = ODP_THREAD_WORKER;
	thr_params.instance = instance;
	ret_val = odph_linux_pthread_create(thread_tbl,
					    &cpumask,
					    &thr_params);
	if (ret_val != num_workers) {
		OFP_ERR("Error: Failed to create worker threads, "
			"expected %d, got %d",
			num_workers, ret_val);
		ofp_stop_processing();
		odph_linux_pthread_join(thread_tbl, num_workers);
		ofp_term_local();
		ofp_term_global();
		odp_term_local();
		odp_term_global(instance);
		return EXIT_FAILURE;
	}

	/*
	 * Now when the ODP dispatcher threads are running, further applications
	 * can be launched, in this case, we will start the OFP CLI thread on
	 * the management core, i.e. not competing for cpu cycles with the
	 * worker threads
	 */
	if (ofp_start_cli_thread(instance, app_init_params.linux_core_id,
		params.conf_file) < 0) {
		OFP_ERR("Error: Failed to init CLI thread");
		ofp_stop_processing();
		odph_linux_pthread_join(thread_tbl, num_workers);
		ofp_term_local();
		ofp_term_global();
		odp_term_local();
		odp_term_global(instance);
		return EXIT_FAILURE;
	}

	/*
	 * If we choose to check performance, a performance monitoring client
	 * will be started on the management core. Once every second it will
	 * read the statistics from the workers from a shared memory region.
	 * Using this has negligible performance impact (<<0.01%).
	 */
	if (params.perf_stat) {
		if (start_performance(instance,
			app_init_params.linux_core_id) <= 0) {
			OFP_ERR("Error: Failed to init performance monitor");
			ofp_stop_processing();
			odph_linux_pthread_join(thread_tbl, num_workers);
			ofp_term_local();
			ofp_term_global();
			odp_term_local();
			odp_term_global(instance);
			return EXIT_FAILURE;
		}
	}

	/*
	 * Wait here until all worker threads have terminated, then free up all
	 * resources allocated by odp_init_global().
	 */
	odph_linux_pthread_join(thread_tbl, num_workers);

	if (ofp_term_local() < 0)
		printf("Error: ofp_term_local failed\n");

	if (ofp_term_global() < 0)
		printf("Error: ofp_term_global failed\n");

	if (odp_term_local() < 0)
		printf("Error: odp_term_local failed\n");

	if (odp_term_global(instance) < 0)
		printf("Error: odp_term_global failed\n");

	printf("FPM End Main()\n");

	return EXIT_SUCCESS;
}
Beispiel #2
0
static int ofp_lib_start(void)
{
	ofp_init_global_t app_init_params;

	odph_linux_pthread_t thread_tbl[32];
	int ret_val, num_workers = 1;
	odp_cpumask_t cpumask;
	char cpumaskstr[64];

	if (ofp_init_global_called)
		return EXIT_FAILURE;

	/*
	 * Before any ODP API functions can be called, we must first init the ODP
	 * globals, e.g. availale accelerators or software implementations for
	 * shared memory, threads, pool, qeueus, sheduler, pktio, timer, crypto
	 * and classification.
	 */
	if (odp_init_global(NULL, NULL)) {
		OFP_ERR("ODP global init failed.");
		return EXIT_FAILURE;
	}

	/*
	 * When the gloabel ODP level init has been done, we can now issue a
	 * local init per thread. This must also be done before any other ODP API
	 * calls may be made. Local inits are made here for shared memory,
	 * threads, pktio and scheduler.
	 */
	if (odp_init_local(ODP_THREAD_CONTROL) != 0) {
		OFP_ERR("ODP local init failed.");
		odp_term_global();
		return EXIT_FAILURE;
	}

	/*
	 * Initializes cpumask with CPUs available for worker threads.
	 * Sets up to 'num' CPUs and returns the count actually set.
	 * Use zero for all available CPUs.
	 */
	num_workers = odp_cpumask_default_worker(&cpumask, num_workers);
	if (odp_cpumask_to_str(&cpumask, cpumaskstr, sizeof(cpumaskstr)) < 0) {
		OFP_ERR("Error: Too small buffer provided to "
			"odp_cpumask_to_str");
		odp_term_local();
		odp_term_global();
		return EXIT_FAILURE;
	}

	printf("Num worker threads: %i\n", num_workers);
	printf("first CPU: %i\n", odp_cpumask_first(&cpumask));
	printf("cpu mask:  %s\n", cpumaskstr);

	/*
	 * Now that ODP has been initalized, we can initialize OFP. This will
	 * open a pktio instance for each interface supplied as argument by the
	 * user.
	 *
	 * General configuration will be to pktio and schedluer queues here in
	 * addition will fast path interface configuration.
	 */
	memset(&app_init_params, 0, sizeof(app_init_params));
	if (ofp_init_global(&app_init_params) != 0) {
		OFP_ERR("OFP global init failed.");
		ofp_term_global();
		odp_term_local();
		odp_term_global();
		return EXIT_FAILURE;
	}

	if (ofp_init_local() != 0) {
		OFP_ERR("Error: OFP local init failed.");
		ofp_term_local();
		ofp_term_global();
		odp_term_local();
		odp_term_global();
		return EXIT_FAILURE;
	}


	/*
	 * Create and launch dataplane dispatcher worker threads to be placed
	 * according to the cpumask, thread_tbl will be populated with the
	 * created pthread IDs.
	 *
	 * In this case, all threads will run the default_event_dispatcher
	 * function with ofp_eth_vlan_processing as argument.
	 *
	 * If different dispatchers should run, or the same be run with differnt
	 * input arguments, the cpumask is used to control this.
	 */
	memset(thread_tbl, 0, sizeof(thread_tbl));
	ret_val = ofp_linux_pthread_create(thread_tbl,
			&cpumask,
			default_event_dispatcher,
			ofp_eth_vlan_processing,
			ODP_THREAD_CONTROL);

	if (ret_val != num_workers) {
		OFP_ERR("Error: Failed to create worker threads, "
			"expected %d, got %d",
			num_workers, ret_val);
		ofp_stop_processing();
		odph_linux_pthread_join(thread_tbl, num_workers);
		ofp_term_local();
		ofp_term_global();
		odp_term_local();
		odp_term_global();
		return EXIT_FAILURE;
	}

	ofp_ifconfig();

	return EXIT_SUCCESS;
}
Beispiel #3
0
/**
 * Signal handler function
 *
 * @param signum int
 * @return void
 *
 */
static void ofp_sig_func_stop(int signum)
{
	printf("Signal handler (signum = %d) ... exiting.\n", signum);

	ofp_stop_processing();
}
Beispiel #4
0
int ofp_term_global(void)
{
	int rc = 0;
	uint16_t i;
	struct ofp_ifnet *ifnet;

	ofp_stop_processing();

	/* Terminate CLI thread*/
	CHECK_ERROR(ofp_stop_cli_thread(), rc);

#ifdef SP
	/* Terminate Netlink thread*/
	if (shm->nl_thread_is_running) {
		odph_linux_pthread_join(&shm->nl_thread, 1);
		shm->nl_thread_is_running = 0;
	}
#endif /* SP */

	/* Cleanup interfaces: queues and pktios*/
	for (i = 0; i < VXLAN_PORTS; i++) {
		ifnet = ofp_get_ifnet((uint16_t)i, 0);
		if (!ifnet) {
			OFP_ERR("Failed to locate interface for port %d", i);
			rc = -1;
			continue;
		}
		if (ifnet->if_state == OFP_IFT_STATE_FREE)
			continue;

		if (ifnet->pktio == ODP_PKTIO_INVALID)
			continue;

		OFP_INFO("Cleaning device '%s' addr %s", ifnet->if_name,
			ofp_print_mac((uint8_t *)ifnet->mac));

		CHECK_ERROR(odp_pktio_stop(ifnet->pktio), rc);
#ifdef SP
		close(ifnet->fd);
		odph_linux_pthread_join(ifnet->rx_tbl, 1);
		odph_linux_pthread_join(ifnet->tx_tbl, 1);
		ifnet->fd = -1;
#endif /*SP*/

		/* Multicasting. */
		ofp_igmp_domifdetach(ifnet);
		ifnet->ii_inet.ii_igmp = NULL;

		if (ifnet->loopq_def != ODP_QUEUE_INVALID) {
			if (odp_queue_destroy(ifnet->loopq_def) < 0) {
				OFP_ERR("Failed to destroy loop queue for %s",
					ifnet->if_name);
				rc = -1;
			}
			ifnet->loopq_def = ODP_QUEUE_INVALID;
		}
#ifdef SP
		if (ifnet->spq_def != ODP_QUEUE_INVALID) {
			cleanup_pkt_queue(ifnet->spq_def);
			if (odp_queue_destroy(ifnet->spq_def) < 0) {
				OFP_ERR("Failed to destroy slow path "
					"queue for %s", ifnet->if_name);
				rc = -1;
			}
			ifnet->spq_def = ODP_QUEUE_INVALID;
		}
#endif /*SP*/
		ifnet->outq_def = ODP_QUEUE_INVALID;

		if (ifnet->pktio != ODP_PKTIO_INVALID) {
			if (odp_pktio_close(ifnet->pktio) < 0) {
				OFP_ERR("Failed to destroy pktio for %s",
					ifnet->if_name);
				rc = -1;
			}
			ifnet->pktio = ODP_PKTIO_INVALID;
		}

		if (ifnet->inq_def != ODP_QUEUE_INVALID) {
			cleanup_pkt_queue(ifnet->inq_def);
			if (odp_queue_destroy(ifnet->inq_def) < 0) {
				OFP_ERR("Failed to destroy default input "
					"queue for %s", ifnet->if_name);
				rc = -1;
			}
			ifnet->inq_def = ODP_QUEUE_INVALID;
		}
	}

	CHECK_ERROR(ofp_clean_vxlan_interface_queue(), rc);

	if (ofp_term_post_global(SHM_PACKET_POOL_NAME)) {
		OFP_ERR("Failed to cleanup resources\n");
		rc = -1;
	}

	return rc;
}