diff --git a/example/l3fwd/odp_l3fwd.c b/example/l3fwd/odp_l3fwd.c
index 29da045..5598a5a 100644
--- a/example/l3fwd/odp_l3fwd.c
+++ b/example/l3fwd/odp_l3fwd.c
@@ -7,6 +7,7 @@
 #include <stdlib.h>
 #include <stdio.h>
 
+#include <example_debug.h>
 #include <odp_api.h>
 #include <odp/helper/linux.h>
 #include <odp/helper/eth.h>
@@ -14,19 +15,27 @@
 #include <odp/helper/udp.h>
 #include <odp/helper/tcp.h>
 
+#include <getopt.h>
+
 #include "odp_l3fwd_db.h"
 
 #define POOL_NUM_PKT 8192
 #define POOL_SEG_LEN 1856
 #define MAX_PKT_BURST 32
 
-static const char * const route_str[] = {
-	"1.1.1.0/24:fm1-mac1:00.e0.0c.00.85.00",
-	"2.1.1.0/24:fm1-mac2:00.e0.0c.00.85.01",
-};
-
 #define MAX_NB_WORKER	8
 #define MAX_NB_PKTIO	4
+#define MAX_NB_ROUTE    32
+
+/** Get rid of path in filename - only for unix-type paths using '/' */
+#define NO_PATH(file_name) (strrchr((file_name), '/') ? \
+			    strrchr((file_name), '/') + 1 : (file_name))
+
+typedef struct {
+	char *if_names[MAX_NB_PKTIO];
+	uint32_t if_count;
+	char *route_str[MAX_NB_ROUTE];
+} app_args_t;
 
 struct l3fwd_pktio_s {
 	odp_pktio_t pktio;
@@ -39,6 +48,7 @@ struct thread_arg_s {
 };
 
 struct {
+	app_args_t		cmd_args;
 	struct l3fwd_pktio_s	l3fwd_pktios[MAX_NB_PKTIO];
 	odph_linux_pthread_t	l3fwd_workers[MAX_NB_WORKER];
 	struct thread_arg_s	worker_args[MAX_NB_WORKER];
@@ -46,6 +56,10 @@ struct {
 	uint32_t		nb_worker; /* effective workers */
 } global;
 
+static void print_usage(char *progname);
+static void print_info(char *progname, app_args_t *args);
+static void parse_cmdline_args(int argc, char *argv[], app_args_t *args);
+
 static odp_pktio_t create_pktio(const char *name, odp_pool_t pool,
 				odp_pktin_queue_t *pktin,
 				odp_pktout_queue_t *pktout)
@@ -97,16 +111,17 @@ static void *run_worker(void *arg)
 	odp_packet_t pkt_tbl_drop[MAX_PKT_BURST];
 	uint32_t pkts, i;
 	struct l3fwd_pktio_s *port;
+	char *if_name;
 
 	i = ((struct thread_arg_s *)arg)->if_idx;
 	port = &global.l3fwd_pktios[i];
-
+	if_name = global.cmd_args.if_names[i];
 	if (odp_pktio_start(port->pktio)) {
-		printf("unable to start interface: %d\n", i);
+		printf("unable to start pktio: %s\n", if_name);
 		exit(1);
 	}
 
-	printf("start interface: %d\n", i);
+	printf("start pktio: %s\n", if_name);
 	for (;;) {
 		int need_to_drop = 0;
 
@@ -180,13 +195,7 @@ int main(int argc, char **argv)
 	odph_linux_thr_params_t thr_params;
 	uint32_t cpu, i;
 	uint8_t mac[ODPH_ETHADDR_LEN];
-
-	if (argc != 3) {
-		printf("Usage: odp_l3fwd eth0 eth1\n");
-		printf("Where eth0 and eth1 are the used interfaces"
-		       " (must have 2 of them)\n");
-		exit(1);
-	}
+	app_args_t *args;
 
 	if (odp_init_global(&instance, NULL, NULL)) {
 		printf("Error: ODP global init failed.\n");
@@ -201,17 +210,21 @@ int main(int argc, char **argv)
 	/* Clear global argument */
 	memset(&global, 0, sizeof(global));
 
+	/* Parse cmdline arguments */
+	args = &global.cmd_args;
+	parse_cmdline_args(argc, argv, args);
+
 	/* Init l3fwd tale */
 	init_fwd_db();
 
 	/* Add route into table */
-	for (i = 0; i < sizeof(route_str) / sizeof(char *); i++) {
-		char buf[128];
-
-		snprintf(buf, 128, "%s", route_str[i]);
-		create_fwd_db_entry(buf);
+	for (i = 0; i < MAX_NB_ROUTE; i++) {
+		if (args->route_str[i])
+			create_fwd_db_entry(args->route_str[i]);
 	}
 
+	print_info(NO_PATH(argv[0]), args);
+
 	/* Create packet pool */
 	odp_pool_param_init(&params);
 	params.pkt.seg_len = POOL_SEG_LEN;
@@ -226,20 +239,25 @@ int main(int argc, char **argv)
 		exit(1);
 	}
 
-	/* TODO: parse cmdline to get pktio number, name */
-	global.nb_pktio = 2;
+	global.nb_pktio = args->if_count;
 	for (i = 0; i < global.nb_pktio; i++) {
 		struct l3fwd_pktio_s *port;
-		char *ifname = argv[i + 1];
+		char buf[16];
 
 		port = &global.l3fwd_pktios[i];
-		port->pktio = create_pktio(ifname, pool, &port->ifin,
+		port->pktio = create_pktio(args->if_names[i], pool, &port->ifin,
 					   &port->ifout);
 		odp_pktio_mac_addr(port->pktio, mac, ODPH_ETHADDR_LEN);
-		resolve_fwd_db(ifname, port->pktio, mac);
+		resolve_fwd_db(args->if_names[i], port->pktio, mac);
+
+		/* print mac string, could be used to config pktgen */
+		sprintf(buf, "%02X:%02X:%02X:%02X:%02X:%02X",
+			mac[0], mac[1], mac[2], mac[3], mac[4], mac[5]);
+		printf("create pktio %s, mac %s\n", args->if_names[i], buf);
 	}
 
-	global.nb_worker = 2;
+	/* one thread for each port */
+	global.nb_worker = args->if_count;
 	memset(&thr_params, 0, sizeof(thr_params));
 	thr_params.start    = run_worker;
 	thr_params.thr_type = ODP_THREAD_WORKER;
@@ -264,3 +282,149 @@ int main(int argc, char **argv)
 
 	return 0;
 }
+
+static void print_usage(char *progname)
+{
+	printf("\n"
+	       "ODP L3 forwarding application.\n"
+	       "\n"
+	       "Usage: %s OPTIONS\n"
+	       "  E.g. %s -i eth0,eth1\n"
+	       " In the above example,\n"
+	       " eth0 will send pkts to eth1 and vice versa\n"
+	       "\n"
+	       "Mandatory OPTIONS:\n"
+	       "  -i, --interface eth interfaces (comma-separated, no spaces)\n"
+	       "  -r, --route SubNet:Intf[:NextHopMAC]\n"
+	       "	NextHopMAC can be optional, in this case, zeroed mac\n"
+	       "\n"
+	       "Optional OPTIONS\n"
+	       "  -h, --help           Display help and exit.\n\n"
+	       "\n", NO_PATH(progname), NO_PATH(progname)
+	    );
+}
+
+static void parse_cmdline_args(int argc, char *argv[], app_args_t *args)
+{
+	int opt;
+	int long_index;
+	char *token, *local;
+	size_t len, route_index = 0;
+	int i, mem_failure = 0;
+
+	static struct option longopts[] = {
+		{"interface", required_argument, NULL, 'i'},	/* return 'i' */
+		{"route", required_argument, NULL, 'r'},	/* return 'r' */
+		{"help", no_argument, NULL, 'h'},		/* return 'h' */
+		{NULL, 0, NULL, 0}
+	};
+
+	while (1) {
+		opt = getopt_long(argc, argv, "+i:r:h",
+				  longopts, &long_index);
+
+		if (opt == -1)
+			break;	/* No more options */
+
+		switch (opt) {
+		/* parse packet-io interface names */
+		case 'i':
+			len = strlen(optarg);
+			if (len == 0) {
+				print_usage(argv[0]);
+				exit(EXIT_FAILURE);
+			}
+			len += 1;	/* add room for '\0' */
+
+			local = malloc(len);
+			if (!local) {
+				print_usage(argv[0]);
+				exit(EXIT_FAILURE);
+			}
+
+			/* count the number of tokens separated by ',' */
+			strcpy(local, optarg);
+			for (token = strtok(local, ","), i = 0;
+			     token != NULL;
+			     token = strtok(NULL, ","), i++)
+				;
+
+			if (i == 0) {
+				print_usage(argv[0]);
+				exit(EXIT_FAILURE);
+			}
+
+			args->if_count = i;
+
+			/* store the if names (reset names string) */
+			strcpy(local, optarg);
+			for (token = strtok(local, ","), i = 0;
+			     token != NULL; token = strtok(NULL, ","), i++) {
+				args->if_names[i] = token;
+			}
+			break;
+
+		/*Configure Route in forwarding database*/
+		case 'r':
+			if (route_index >= MAX_NB_ROUTE) {
+				printf("No more routes can be added\n");
+				break;
+			}
+			local = calloc(1, strlen(optarg) + 1);
+			if (!local) {
+				mem_failure = 1;
+				break;
+			}
+			memcpy(local, optarg, strlen(optarg));
+			local[strlen(optarg)] = '\0';
+			args->route_str[route_index++] = local;
+			break;
+
+		case 'h':
+			print_usage(argv[0]);
+			exit(EXIT_SUCCESS);
+			break;
+
+		default:
+			break;
+		}
+	}
+
+	if (args->if_count == 0 || mem_failure == 1) {
+		print_usage(argv[0]);
+		exit(EXIT_FAILURE);
+	}
+
+	optind = 1;		/* reset 'extern optind' from the getopt lib */
+}
+
+static void print_info(char *progname, app_args_t *args)
+{
+	uint32_t i;
+
+	printf("\n"
+	       "ODP system info\n"
+	       "---------------\n"
+	       "ODP API version: %s\n"
+	       "ODP impl name:	 %s\n"
+	       "CPU model:       %s\n"
+	       "CPU freq (hz):   %" PRIu64 "\n"
+	       "Cache line size: %i\n"
+	       "CPU count:       %i\n"
+	       "\n",
+	       odp_version_api_str(), odp_version_impl_name(),
+	       odp_cpu_model_str(), odp_cpu_hz_max(),
+	       odp_sys_cache_line_size(), odp_cpu_count());
+
+	printf("Running ODP appl: \"%s\"\n"
+	       "-----------------\n"
+	       "IF-count:        %i\n"
+	       "Using IFs:      ",
+	       progname, args->if_count);
+
+	for (i = 0; i < args->if_count; ++i)
+		printf(" %s", args->if_names[i]);
+
+	printf("\n\n");
+	fflush(NULL);
+}
diff --git a/example/l3fwd/odp_l3fwd_db.c b/example/l3fwd/odp_l3fwd_db.c
index 7fde4ae..c1e1b5b 100644
--- a/example/l3fwd/odp_l3fwd_db.c
+++ b/example/l3fwd/odp_l3fwd_db.c
@@ -342,15 +342,6 @@ int create_fwd_db_entry(char *input)
 		pos++;
 	}
 
-	/* Verify we parsed exactly the number of tokens we expected */
-	if (3 != pos) {
-		printf("ERROR: \"%s\" contains %d tokens, expected 3\n",
-		       input,
-		       pos);
-		free(local);
-		return -1;
-	}
-
 	/* Reset pktio to invalid */
 	entry->pktio = ODP_PKTIO_INVALID;
 
