diff --git a/examples/kni/main.c b/examples/kni/main.c
index e99ef5c38a..d4d7a3daa9 100644
--- a/examples/kni/main.c
+++ b/examples/kni/main.c
@@ -73,6 +73,7 @@
 
 #define KNI_US_PER_SECOND       1000000
 #define KNI_SECOND_PER_DAY      86400
+#define MIN_ZERO_POLL_COUNT     100
 
 #define KNI_MAX_KTHREAD 32
 /*
@@ -107,6 +108,8 @@ static uint32_t ports_mask = 0;
 static int promiscuous_on = 0;
 /* Monitor link status continually. off by default. */
 static int monitor_links;
+/* rx set in interrupt mode off by default. */
+static int intr_rx_en;
 
 /* Structure type for recording kni interface specific stats */
 struct kni_interface_stats {
@@ -206,7 +209,7 @@ kni_burst_free_mbufs(struct rte_mbuf **pkts, unsigned num)
 /**
  * Interface to burst rx and enqueue mbufs into rx_q
  */
-static void
+static int
 kni_ingress(struct kni_port_params *p)
 {
 	uint8_t i;
@@ -214,9 +217,9 @@ kni_ingress(struct kni_port_params *p)
 	unsigned nb_rx, num;
 	uint32_t nb_kni;
 	struct rte_mbuf *pkts_burst[PKT_BURST_SZ];
-
+	int ret = 0;
 	if (p == NULL)
-		return;
+		return -1;
 
 	nb_kni = p->nb_kni;
 	port_id = p->port_id;
@@ -225,8 +228,10 @@ kni_ingress(struct kni_port_params *p)
 		nb_rx = rte_eth_rx_burst(port_id, 0, pkts_burst, PKT_BURST_SZ);
 		if (unlikely(nb_rx > PKT_BURST_SZ)) {
 			RTE_LOG(ERR, APP, "Error receiving from eth\n");
-			return;
+			return -1;
 		}
+		if (nb_rx == 0)
+			ret = 1;
 		/* Burst tx to kni */
 		num = rte_kni_tx_burst(p->kni[i], pkts_burst, nb_rx);
 		if (num)
@@ -239,6 +244,7 @@ kni_ingress(struct kni_port_params *p)
 			kni_stats[port_id].rx_dropped += nb_rx - num;
 		}
 	}
+	return ret;
 }
 
 /**
@@ -277,12 +283,56 @@ kni_egress(struct kni_port_params *p)
 	}
 }
 
+static int
+sleep_until_rx_interrupt(int num, int lcore)
+{
+	static struct {
+		bool wakeup;
+	} __rte_cache_aligned status[RTE_MAX_LCORE];
+	struct rte_epoll_event event[num];
+	int n;
+
+	if (status[lcore].wakeup) {
+		RTE_LOG(DEBUG, APP,
+				"lcore %u sleeps until interrupt triggers\n",
+				rte_lcore_id());
+	}
+	n = rte_epoll_wait(RTE_EPOLL_PER_THREAD, event, num, 10);
+	status[lcore].wakeup = n != 0;
+
+	return 0;
+}
+
+static void
+turn_on_off_intr(uint16_t port_id, uint16_t queue_id, bool on)
+{
+	if (on)
+		rte_eth_dev_rx_intr_enable(port_id, queue_id);
+	else
+		rte_eth_dev_rx_intr_disable(port_id, queue_id);
+}
+
+static int event_register(void)
+{
+	int ret;
+
+	ret = rte_eth_dev_rx_intr_ctl_q(0, 0,
+					RTE_EPOLL_PER_THREAD,
+					RTE_INTR_EVENT_ADD, NULL);
+	if (ret)
+		return ret;
+
+	return 0;
+}
+
 static int
 main_loop(__rte_unused void *arg)
 {
 	uint16_t i;
 	int32_t f_stop;
 	int32_t f_pause;
+	int ret = 0;
+	uint32_t zero_rx_packet_count = 0;
 	const unsigned lcore_id = rte_lcore_id();
 	enum lcore_rxtx {
 		LCORE_NONE,
@@ -291,12 +341,17 @@ main_loop(__rte_unused void *arg)
 		LCORE_MAX
 	};
 	enum lcore_rxtx flag = LCORE_NONE;
+	int intr_en = 0;
 
 	RTE_ETH_FOREACH_DEV(i) {
 		if (!kni_port_params_array[i])
 			continue;
 		if (kni_port_params_array[i]->lcore_rx == (uint8_t)lcore_id) {
 			flag = LCORE_RX;
+			if (intr_rx_en && !event_register())
+				intr_en = 1;
+			else
+				RTE_LOG(DEBUG, APP, "RX interrupt won't enable.\n");
 			break;
 		} else if (kni_port_params_array[i]->lcore_tx ==
 						(uint8_t)lcore_id) {
@@ -316,7 +371,23 @@ main_loop(__rte_unused void *arg)
 				break;
 			if (f_pause)
 				continue;
-			kni_ingress(kni_port_params_array[i]);
+			ret = kni_ingress(kni_port_params_array[i]);
+			if (ret == 1) {
+				zero_rx_packet_count++;
+				if (zero_rx_packet_count <=
+						MIN_ZERO_POLL_COUNT)
+					continue;
+			} else
+				zero_rx_packet_count = 0;
+
+			if (zero_rx_packet_count > 0) {
+				zero_rx_packet_count = 0;
+				if (unlikely(intr_en)) {
+					turn_on_off_intr(i, 0, 1);
+					sleep_until_rx_interrupt(1, lcore_id);
+					turn_on_off_intr(i, 0, 0);
+				}
+			}
 		}
 	} else if (flag == LCORE_TX) {
 		RTE_LOG(INFO, APP, "Lcore %u is writing to port %d\n",
@@ -341,12 +412,13 @@ main_loop(__rte_unused void *arg)
 static void
 print_usage(const char *prgname)
 {
-	RTE_LOG(INFO, APP, "\nUsage: %s [EAL options] -- -p PORTMASK -P -m "
+	RTE_LOG(INFO, APP, "\nUsage: %s [EAL options] -- -p PORTMASK -P -m -I "
 		   "[--config (port,lcore_rx,lcore_tx,lcore_kthread...)"
 		   "[,(port,lcore_rx,lcore_tx,lcore_kthread...)]]\n"
 		   "    -p PORTMASK: hex bitmask of ports to use\n"
 		   "    -P : enable promiscuous mode\n"
 		   "    -m : enable monitoring of port carrier state\n"
+		   "    -I : enable rx interrupt mode\n"
 		   "    --config (port,lcore_rx,lcore_tx,lcore_kthread...): "
 		   "port and lcore configurations\n",
 	           prgname);
@@ -527,7 +599,7 @@ parse_args(int argc, char **argv)
 	opterr = 0;
 
 	/* Parse command line */
-	while ((opt = getopt_long(argc, argv, "p:Pm", longopts,
+	while ((opt = getopt_long(argc, argv, "p:PmI", longopts,
 						&longindex)) != EOF) {
 		switch (opt) {
 		case 'p':
@@ -539,6 +611,9 @@ parse_args(int argc, char **argv)
 		case 'm':
 			monitor_links = 1;
 			break;
+		case 'I':
+			intr_rx_en = 1;
+			break;
 		case 0:
 			if (!strncmp(longopts[longindex].name,
 				     CMDLINE_OPT_CONFIG,
@@ -610,6 +685,8 @@ init_port(uint16_t port)
 	if (dev_info.tx_offload_capa & RTE_ETH_TX_OFFLOAD_MBUF_FAST_FREE)
 		local_port_conf.txmode.offloads |=
 			RTE_ETH_TX_OFFLOAD_MBUF_FAST_FREE;
+	if (intr_rx_en)
+		local_port_conf.intr_conf.rxq = 1;
 	ret = rte_eth_dev_configure(port, 1, 1, &local_port_conf);
 	if (ret < 0)
 		rte_exit(EXIT_FAILURE, "Could not configure port%u (%d)\n",
