[ONOS-5606] Try to use Epoll event group if OS natively support it

Change-Id: I449df3a0a9115c24aa29e15931877626879dae20
diff --git a/protocols/lisp/ctl/BUCK b/protocols/lisp/ctl/BUCK
index c6b463a..622dae5 100644
--- a/protocols/lisp/ctl/BUCK
+++ b/protocols/lisp/ctl/BUCK
@@ -5,6 +5,7 @@
     '//lib:netty-buffer',
     '//lib:netty-codec',
     '//lib:netty-transport',
+    '//lib:netty-transport-native-epoll',
     '//lib:netty-handler'
 ]
 
diff --git a/protocols/lisp/ctl/src/main/java/org/onosproject/lisp/ctl/LispControllerBootstrap.java b/protocols/lisp/ctl/src/main/java/org/onosproject/lisp/ctl/LispControllerBootstrap.java
index b7415c0..922320e 100644
--- a/protocols/lisp/ctl/src/main/java/org/onosproject/lisp/ctl/LispControllerBootstrap.java
+++ b/protocols/lisp/ctl/src/main/java/org/onosproject/lisp/ctl/LispControllerBootstrap.java
@@ -19,9 +19,12 @@
 import com.google.common.collect.Lists;
 import io.netty.bootstrap.Bootstrap;
 import io.netty.buffer.PooledByteBufAllocator;
+import io.netty.channel.AbstractChannel;
 import io.netty.channel.ChannelFuture;
 import io.netty.channel.ChannelOption;
 import io.netty.channel.EventLoopGroup;
+import io.netty.channel.epoll.EpollDatagramChannel;
+import io.netty.channel.epoll.EpollEventLoopGroup;
 import io.netty.channel.nio.NioEventLoopGroup;
 import io.netty.channel.socket.nio.NioDatagramChannel;
 import org.slf4j.Logger;
@@ -44,11 +47,12 @@
     protected List<Integer> lispPorts = ImmutableList.of(LISP_DATA_PORT, LISP_CONTROL_PORT);
 
     private EventLoopGroup eventLoopGroup;
+    private Class<? extends AbstractChannel> channelClass;
 
     /**
      * Stitches all channel handlers into server bootstrap.
      */
-    public void run() {
+    private void run() {
 
         try {
             final Bootstrap bootstrap = createServerBootstrap();
@@ -79,9 +83,10 @@
      */
     private Bootstrap createServerBootstrap() {
         Bootstrap bootstrap = new Bootstrap();
-        eventLoopGroup = new NioEventLoopGroup();
+
+        initEventLoopGroup();
         bootstrap.group(eventLoopGroup)
-                .channel(NioDatagramChannel.class)
+                .channel(channelClass)
                 .handler(new LispChannelInitializer());
 
         return bootstrap;
@@ -107,11 +112,29 @@
                 f.channel().closeFuture().sync();
             }
         } catch (InterruptedException e) {
-            e.printStackTrace();
+            log.warn("Failed to close channels. Reasons: {}.", e.getMessage());
         }
     }
 
     /**
+     * Initializes event loop group.
+     */
+    private void initEventLoopGroup() {
+
+        // try to use EpollEventLoopGroup if possible,
+        // if OS does not support native Epoll, fallback to use netty NIO
+        try {
+            eventLoopGroup = new EpollEventLoopGroup();
+            channelClass = EpollDatagramChannel.class;
+        } catch (Throwable e) {
+            log.debug("Failed to initialize native (epoll) transport. "
+                        + "Reason: {}. Proceeding with NIO event group.", e.getMessage());
+        }
+        eventLoopGroup = new NioEventLoopGroup();
+        channelClass = NioDatagramChannel.class;
+    }
+
+    /**
      * Launches LISP controller to listen control channel.
      */
     public void start() {
@@ -130,7 +153,7 @@
             // try to shutdown all open event groups
             eventLoopGroup.shutdownGracefully().sync();
         } catch (InterruptedException e) {
-            e.printStackTrace();
+            log.warn("Failed to stop LISP controller. Reasons: {}.", e.getMessage());
         }
     }
 }