Controller network interface enhancements: 82/1082/1
authorChi-Vien Ly <chivly@cisco.com>
Tue, 3 Sep 2013 17:07:13 +0000 (10:07 -0700)
committerChi-Vien Ly <chivly@cisco.com>
Tue, 3 Sep 2013 17:07:13 +0000 (10:07 -0700)
- Provide a configuration parameter "of.address = " in config.ini which allows a specific IP address to be specified.
  If a valid IP address is specified, the controller will ONLY accept connections from switches with destination address
  matching the specified configured address. If an address it NOT specified (which is the default case) or is syntactically
  incorrect, the controller will use "any" (wildcard) address. The default case is what currently been implemented.
- If the IP address is specified, the controller will determine the networking interface (eg, eth0) on which the
  IP address is configured. If the interface is NOT up and is changed status between up and down, a log will be generated
  to alert the network operation to take corrective actions. If the address is not specified (or is specified with an invalid
  address syntax), the controller will use any interfaces and will NOT monitor the status of these interfaces.

Change-Id: Ie2a92ad99d35367a1d89dca390e7af54321bfe7c
Signed-off-by: Chi-Vien Ly <chivly@cisco.com>
opendaylight/distribution/opendaylight/src/main/resources/configuration/config.ini
opendaylight/protocol_plugins/openflow/src/main/java/org/opendaylight/controller/protocol_plugin/openflow/core/internal/ControllerIO.java

index f9899d7d8b3c5ca5821a2971c336d8d07f43bdac..5501be46b2e59afb2743d70aad90c549ad5a4ae7 100644 (file)
@@ -46,6 +46,8 @@ org.eclipse.gemini.web.tomcat.config.path=configuration/tomcat-server.xml
 # Open Flow related system parameters
 # TCP port on which the controller is listening (default 6633)
 # of.listenPort=6633
+# IP address of the controller (default: wild card)
+# of.address = 127.0.0.1
 # The time (in milliseconds) the controller will wait for a response after sending a Barrier Request or a Statistic Request message (default 2000 msec)
 # of.messageResponseTimer=2000
 # The switch liveness timeout value (default 60500 msec)
index 868e2086511b5cd7926ccb08275cbda6bb270c9d..70c507207632af84e2db3f9182cfd76be2223318 100644 (file)
@@ -9,6 +9,9 @@
 package org.opendaylight.controller.protocol_plugin.openflow.core.internal;
 
 import java.io.IOException;
+import java.net.InetAddress;
+import java.net.NetworkInterface;
+import java.net.SocketException;
 import java.nio.channels.SelectionKey;
 import java.nio.channels.Selector;
 import java.nio.channels.ServerSocketChannel;
@@ -24,6 +27,8 @@ public class ControllerIO {
             .getLogger(ControllerIO.class);
     private static Short defaultOpenFlowPort = 6633;
     private Short openFlowPort;
+    private InetAddress controllerIP;
+    private NetworkInterface netInt;
     private SelectionKey serverSelectionKey;
     private IController listener;
     private ServerSocketChannel serverSocket;
@@ -43,30 +48,41 @@ public class ControllerIO {
                         openFlowPort);
             }
         }
+        String addressString = System.getProperty("of.address");
+        if (addressString != null) {
+            try {
+                controllerIP = InetAddress.getByName(addressString);
+            } catch (Exception e) {
+                controllerIP = null;
+                logger.warn("Invalid IP: {}, use wildcard *", addressString);
+            }
+        } else {
+            controllerIP = null;
+        }
     }
 
     public void start() throws IOException {
         this.running = true;
-        // obtain a selector
-        this.selector = SelectorProvider.provider().openSelector();
-        // create the listening socket
-        this.serverSocket = ServerSocketChannel.open();
-        this.serverSocket.configureBlocking(false);
-        this.serverSocket.socket().bind(
-                new java.net.InetSocketAddress(openFlowPort));
-        this.serverSocket.socket().setReuseAddress(true);
-        // register this socket for accepting incoming connections
-        this.serverSelectionKey = this.serverSocket.register(selector,
-                SelectionKey.OP_ACCEPT);
+        this.netInt = null;
         controllerIOThread = new Thread(new Runnable() {
             @Override
             public void run() {
+                waitUntilInterfaceUp();
+                if (!startAcceptConnections()) {
+                    return;
+                }
+                logger.info("Controller is now listening on {}:{}",
+                        (controllerIP == null) ? "any" : controllerIP.getHostAddress(),
+                        openFlowPort);
+                boolean netInterfaceUp = true;
                 while (running) {
                     try {
                         // wait for an incoming connection
-                        selector.select(0);
+                        // check interface state every 5sec
+                        selector.select(5000);
                         Iterator<SelectionKey> selectedKeys = selector
                                 .selectedKeys().iterator();
+                        netInterfaceUp = isNetInterfaceUp(netInterfaceUp);
                         while (selectedKeys.hasNext()) {
                             SelectionKey skey = selectedKeys.next();
                             selectedKeys.remove();
@@ -82,9 +98,91 @@ public class ControllerIO {
             }
         }, "ControllerI/O Thread");
         controllerIOThread.start();
-        logger.info("Controller is now listening on port {}", openFlowPort);
     }
 
+    private boolean startAcceptConnections() {
+        if (running) {
+            try {
+                // obtain a selector
+                selector = SelectorProvider.provider().openSelector();
+                // create the listening socket
+                serverSocket = ServerSocketChannel.open();
+                serverSocket.configureBlocking(false);
+                serverSocket.socket().bind(
+                        new java.net.InetSocketAddress(controllerIP,
+                                openFlowPort));
+                serverSocket.socket().setReuseAddress(true);
+                // register this socket for accepting incoming
+                // connections
+                serverSelectionKey = serverSocket.register(selector,
+                        SelectionKey.OP_ACCEPT);
+            } catch (IOException e) {
+                logger.error(
+                        "Failed to listen on {}:{}, exit",
+                        (controllerIP == null) ? "" : controllerIP
+                                .getHostAddress(), openFlowPort);
+                return false;
+            }
+            return true;
+        }
+        return false;
+    }
+
+    private boolean isNetInterfaceUp(boolean currentlyUp) {
+        if (controllerIP == null) {
+            // for wildcard address, return since there is always an "up"
+            // interface (such as loopback)
+            return true;
+        }
+        boolean up;
+        try {
+            if (netInt == null) {
+                logger.warn("Can't find any operational interface for address {}",
+                        controllerIP.getHostAddress());
+                return false;
+            }
+            up = netInt.isUp();
+            if (!up) {
+                // always generate log if the interface is down
+                logger.warn("Interface {} with address {} is DOWN!",
+                        netInt.getDisplayName(),
+                        controllerIP.getHostAddress());
+            } else {
+                if (!currentlyUp) {
+                    // only generate log if the interface changes from down to up
+                    logger.info("Interface {} with address {} is UP!",
+                            netInt.getDisplayName(),
+                            controllerIP.getHostAddress());
+                }
+            }
+        } catch (SocketException e) {
+            logger.warn("Interface {} with address {} is DOWN!",
+                    netInt.getDisplayName(),
+                    controllerIP.getHostAddress());
+           up = false;
+        }
+        return up;
+    }
+
+    private void waitUntilInterfaceUp() {
+        if (controllerIP == null) {
+            // for wildcard address, return since there is always an "up"
+            // interface (such as loopback)
+            return;
+        }
+        boolean isUp = false;
+        do {
+            try {
+                // get the network interface from the address
+                netInt = NetworkInterface.getByInetAddress(controllerIP);
+                isUp = isNetInterfaceUp(isUp);
+                if (!isUp) {
+                    Thread.sleep(5000);
+                }
+            } catch (Exception e) {
+            }
+        } while ((!isUp) && (running));
+    }
     public void shutDown() throws IOException {
         this.running = false;
         this.selector.wakeup();