From 6a07d2d622eaa06953f3353e39c080984076e8de Mon Sep 17 00:00:00 2001 From: Ashlee Young Date: Fri, 9 Oct 2015 18:32:44 -0700 Subject: Updated master to commit id 6ee8aa3e67ce89908a8c93aa9445c6f71a18f986 Change-Id: I94b055ee2f298daf71e2ec794fd0f2495bd8081f --- .../openflow/controller/impl/Controller.java | 117 ++++++++++++++++++--- .../openflow/controller/impl/OFChannelHandler.java | 3 +- .../controller/impl/OpenFlowControllerImpl.java | 67 ++++++------ .../controller/impl/OpenflowPipelineFactory.java | 18 +++- 4 files changed, 154 insertions(+), 51 deletions(-) (limited to 'framework/src/onos/openflow/ctl') diff --git a/framework/src/onos/openflow/ctl/src/main/java/org/onosproject/openflow/controller/impl/Controller.java b/framework/src/onos/openflow/ctl/src/main/java/org/onosproject/openflow/controller/impl/Controller.java index 0c28a6fa..9d355156 100644 --- a/framework/src/onos/openflow/ctl/src/main/java/org/onosproject/openflow/controller/impl/Controller.java +++ b/framework/src/onos/openflow/ctl/src/main/java/org/onosproject/openflow/controller/impl/Controller.java @@ -16,6 +16,8 @@ package org.onosproject.openflow.controller.impl; +import com.google.common.base.Strings; +import com.google.common.collect.ImmutableList; import org.jboss.netty.bootstrap.ServerBootstrap; import org.jboss.netty.channel.ChannelPipelineFactory; import org.jboss.netty.channel.group.ChannelGroup; @@ -37,13 +39,24 @@ import org.projectfloodlight.openflow.protocol.OFVersion; import org.slf4j.Logger; import org.slf4j.LoggerFactory; +import javax.net.ssl.KeyManagerFactory; +import javax.net.ssl.SSLContext; +import javax.net.ssl.SSLEngine; +import javax.net.ssl.TrustManagerFactory; +import java.io.FileInputStream; import java.lang.management.ManagementFactory; import java.lang.management.RuntimeMXBean; import java.net.InetSocketAddress; +import java.security.KeyStore; +import java.util.Dictionary; import java.util.HashMap; +import java.util.List; import java.util.Map; import java.util.concurrent.Executors; +import java.util.stream.Collectors; +import java.util.stream.Stream; +import static org.onlab.util.Tools.get; import static org.onlab.util.Tools.groupedThreads; import static org.onosproject.net.DeviceId.deviceId; import static org.onosproject.openflow.controller.Dpid.uri; @@ -59,14 +72,16 @@ public class Controller { protected static final OFFactory FACTORY13 = OFFactories.getFactory(OFVersion.OF_13); protected static final OFFactory FACTORY10 = OFFactories.getFactory(OFVersion.OF_10); + private static final boolean TLS_DISABLED = false; + private static final short MIN_KS_LENGTH = 6; protected HashMap controllerNodeIPsCache; private ChannelGroup cg; // Configuration options - protected int openFlowPort = 6633; - protected int workerThreads = 0; + protected List openFlowPorts = ImmutableList.of(6633, 6653); + protected int workerThreads = 16; // Start time of the controller protected long systemStartTime; @@ -75,9 +90,16 @@ public class Controller { private NioServerSocketChannelFactory execFactory; + protected String ksLocation; + protected String tsLocation; + protected char[] ksPwd; + protected char[] tsPwd; + private SSLEngine serverSSLEngine; + // Perf. related configuration protected static final int SEND_BUFFER_SIZE = 4 * 1024 * 1024; private DriverService driverService; + private boolean enableOFTLS = TLS_DISABLED; // *************** // Getters/Setters @@ -127,13 +149,15 @@ public class Controller { bootstrap.setOption("child.sendBufferSize", Controller.SEND_BUFFER_SIZE); ChannelPipelineFactory pfact = - new OpenflowPipelineFactory(this, null); + new OpenflowPipelineFactory(this, null, serverSSLEngine); bootstrap.setPipelineFactory(pfact); - InetSocketAddress sa = new InetSocketAddress(openFlowPort); cg = new DefaultChannelGroup(); - cg.add(bootstrap.bind(sa)); + openFlowPorts.forEach(port -> { + InetSocketAddress sa = new InetSocketAddress(port); + cg.add(bootstrap.bind(sa)); + log.info("Listening for switch connections on {}", sa); + }); - log.info("Listening for switch connections on {}", sa); } catch (Exception e) { throw new RuntimeException(e); } @@ -155,19 +179,22 @@ public class Controller { } } - public void setConfigParams(Map configParams) { - String ofPort = configParams.get("openflowport"); - if (ofPort != null) { - this.openFlowPort = Integer.parseInt(ofPort); + public void setConfigParams(Dictionary properties) { + String ports = get(properties, "openflowPorts"); + if (!Strings.isNullOrEmpty(ports)) { + this.openFlowPorts = Stream.of(ports.split(",")) + .map(s -> Integer.parseInt(s)) + .collect(Collectors.toList()); } + log.debug("OpenFlow ports set to {}", this.openFlowPorts); - log.debug("OpenFlow port set to {}", this.openFlowPort); - String threads = configParams.get("workerthreads"); - this.workerThreads = threads != null ? Integer.parseInt(threads) : 16; + String threads = get(properties, "workerThreads"); + if (!Strings.isNullOrEmpty(threads)) { + this.workerThreads = Integer.parseInt(threads); + } log.debug("Number of worker threads set to {}", this.workerThreads); } - /** * Initialize internal data structures. */ @@ -177,6 +204,68 @@ public class Controller { this.controllerNodeIPsCache = new HashMap<>(); this.systemStartTime = System.currentTimeMillis(); + + try { + getTLSParameters(); + if (enableOFTLS) { + initSSL(); + } + } catch (Exception ex) { + log.error("SSL init failed: {}", ex.getMessage()); + } + + } + + private void getTLSParameters() { + String tempString = System.getProperty("enableOFTLS"); + enableOFTLS = Strings.isNullOrEmpty(tempString) ? TLS_DISABLED : Boolean.parseBoolean(tempString); + log.info("OpenFlow Security is {}", enableOFTLS ? "enabled" : "disabled"); + if (enableOFTLS) { + ksLocation = System.getProperty("javax.net.ssl.keyStore"); + if (Strings.isNullOrEmpty(ksLocation)) { + enableOFTLS = TLS_DISABLED; + return; + } + tsLocation = System.getProperty("javax.net.ssl.trustStore"); + if (Strings.isNullOrEmpty(tsLocation)) { + enableOFTLS = TLS_DISABLED; + return; + } + ksPwd = System.getProperty("javax.net.ssl.keyStorePassword").toCharArray(); + if (MIN_KS_LENGTH > ksPwd.length) { + enableOFTLS = TLS_DISABLED; + return; + } + tsPwd = System.getProperty("javax.net.ssl.trustStorePassword").toCharArray(); + if (MIN_KS_LENGTH > tsPwd.length) { + enableOFTLS = TLS_DISABLED; + return; + } + } + } + + private void initSSL() throws Exception { + + TrustManagerFactory tmFactory = TrustManagerFactory.getInstance(TrustManagerFactory.getDefaultAlgorithm()); + KeyStore ts = KeyStore.getInstance("JKS"); + ts.load(new FileInputStream(tsLocation), tsPwd); + tmFactory.init(ts); + + KeyManagerFactory kmf = KeyManagerFactory.getInstance(KeyManagerFactory.getDefaultAlgorithm()); + KeyStore ks = KeyStore.getInstance("JKS"); + ks.load(new FileInputStream(ksLocation), ksPwd); + kmf.init(ks, ksPwd); + + SSLContext serverContext = SSLContext.getInstance("TLS"); + serverContext.init(kmf.getKeyManagers(), tmFactory.getTrustManagers(), null); + + serverSSLEngine = serverContext.createSSLEngine(); + + serverSSLEngine.setNeedClientAuth(true); + serverSSLEngine.setUseClientMode(false); + serverSSLEngine.setEnabledProtocols(serverSSLEngine.getSupportedProtocols()); + serverSSLEngine.setEnabledCipherSuites(serverSSLEngine.getSupportedCipherSuites()); + serverSSLEngine.setEnableSessionCreation(true); } // ************** diff --git a/framework/src/onos/openflow/ctl/src/main/java/org/onosproject/openflow/controller/impl/OFChannelHandler.java b/framework/src/onos/openflow/ctl/src/main/java/org/onosproject/openflow/controller/impl/OFChannelHandler.java index 450aa827..1a088ff7 100644 --- a/framework/src/onos/openflow/ctl/src/main/java/org/onosproject/openflow/controller/impl/OFChannelHandler.java +++ b/framework/src/onos/openflow/ctl/src/main/java/org/onosproject/openflow/controller/impl/OFChannelHandler.java @@ -941,7 +941,8 @@ class OFChannelHandler extends IdleStateAwareChannelHandler { void processOFHello(OFChannelHandler h, OFHello m) throws IOException, SwitchStateException { // we only expect hello in the WAIT_HELLO state - illegalMessageReceived(h, m); + log.warn("Received Hello outside WAIT_HELLO state; switch {} is not complaint.", + h.channel.getRemoteAddress()); } void processOFBarrierReply(OFChannelHandler h, OFBarrierReply m) diff --git a/framework/src/onos/openflow/ctl/src/main/java/org/onosproject/openflow/controller/impl/OpenFlowControllerImpl.java b/framework/src/onos/openflow/ctl/src/main/java/org/onosproject/openflow/controller/impl/OpenFlowControllerImpl.java index c82078a1..d0429947 100644 --- a/framework/src/onos/openflow/ctl/src/main/java/org/onosproject/openflow/controller/impl/OpenFlowControllerImpl.java +++ b/framework/src/onos/openflow/ctl/src/main/java/org/onosproject/openflow/controller/impl/OpenFlowControllerImpl.java @@ -15,7 +15,6 @@ */ package org.onosproject.openflow.controller.impl; -import com.google.common.base.Strings; import com.google.common.collect.ArrayListMultimap; import com.google.common.collect.Lists; import com.google.common.collect.Multimap; @@ -48,6 +47,8 @@ import org.projectfloodlight.openflow.protocol.OFExperimenter; import org.projectfloodlight.openflow.protocol.OFFactories; import org.projectfloodlight.openflow.protocol.OFFlowStatsEntry; import org.projectfloodlight.openflow.protocol.OFFlowStatsReply; +import org.projectfloodlight.openflow.protocol.OFTableStatsEntry; +import org.projectfloodlight.openflow.protocol.OFTableStatsReply; import org.projectfloodlight.openflow.protocol.OFGroupDescStatsEntry; import org.projectfloodlight.openflow.protocol.OFGroupDescStatsReply; import org.projectfloodlight.openflow.protocol.OFGroupStatsEntry; @@ -67,11 +68,8 @@ import org.slf4j.LoggerFactory; import java.util.Collection; import java.util.Collections; -import java.util.Dictionary; -import java.util.HashMap; import java.util.LinkedList; import java.util.List; -import java.util.Map; import java.util.Set; import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.CopyOnWriteArraySet; @@ -80,13 +78,12 @@ import java.util.concurrent.Executors; import java.util.concurrent.locks.Lock; import java.util.concurrent.locks.ReentrantLock; -import static org.onlab.util.Tools.get; import static org.onlab.util.Tools.groupedThreads; @Component(immediate = true) @Service public class OpenFlowControllerImpl implements OpenFlowController { - private static final int DEFAULT_OFPORT = 6633; + private static final String DEFAULT_OFPORT = "6633,6653"; private static final int DEFAULT_WORKER_THREADS = 16; private static final Logger log = @@ -102,9 +99,9 @@ public class OpenFlowControllerImpl implements OpenFlowController { @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY) protected ComponentConfigService cfgService; - @Property(name = "openflowPort", intValue = DEFAULT_OFPORT, - label = "Port number used by OpenFlow protocol; default is 6633") - private int openflowPort = DEFAULT_OFPORT; + @Property(name = "openflowPorts", value = DEFAULT_OFPORT, + label = "Port numbers (comma separated) used by OpenFlow protocol; default is 6633,6653") + private String openflowPorts = DEFAULT_OFPORT; @Property(name = "workerThreads", intValue = DEFAULT_WORKER_THREADS, label = "Number of controller worker threads; default is 16") @@ -134,6 +131,9 @@ public class OpenFlowControllerImpl implements OpenFlowController { protected Multimap fullFlowStats = ArrayListMultimap.create(); + protected Multimap fullTableStats = + ArrayListMultimap.create(); + protected Multimap fullGroupStats = ArrayListMultimap.create(); @@ -148,8 +148,7 @@ public class OpenFlowControllerImpl implements OpenFlowController { @Activate public void activate(ComponentContext context) { cfgService.registerProperties(getClass()); - Map properties = readComponentConfiguration(context); - ctrl.setConfigParams(properties); + ctrl.setConfigParams(context.getProperties()); ctrl.start(agent, driverService); } @@ -159,33 +158,10 @@ public class OpenFlowControllerImpl implements OpenFlowController { ctrl.stop(); } - /** - * Extracts properties from the component configuration context. - * - * @param context the component context - */ - private Map readComponentConfiguration(ComponentContext context) { - Dictionary properties = context.getProperties(); - Map outProperties = new HashMap<>(); - - String port = get(properties, "openflowPort"); - if (!Strings.isNullOrEmpty(port)) { - outProperties.put("openflowport", port); - } - - String thread = get(properties, "workerThreads"); - if (!Strings.isNullOrEmpty(thread)) { - outProperties.put("workerthreads", thread); - } - - return outProperties; - } - @Modified public void modified(ComponentContext context) { - Map properties = readComponentConfiguration(context); ctrl.stop(); - ctrl.setConfigParams(properties); + ctrl.setConfigParams(context.getProperties()); ctrl.start(agent, driverService); } @@ -259,6 +235,7 @@ public class OpenFlowControllerImpl implements OpenFlowController { @Override public void processPacket(Dpid dpid, OFMessage msg) { Collection flowStats; + Collection tableStats; Collection groupStats; Collection groupDescStats; Collection portStats; @@ -302,6 +279,16 @@ public class OpenFlowControllerImpl implements OpenFlowController { OFFlowStatsReply.Builder rep = OFFactories.getFactory(msg.getVersion()).buildFlowStatsReply(); rep.setEntries(Lists.newLinkedList(flowStats)); + rep.setXid(reply.getXid()); + executorMsgs.submit(new OFMessageHandler(dpid, rep.build())); + } + break; + case TABLE: + tableStats = publishTableStats(dpid, (OFTableStatsReply) reply); + if (tableStats != null) { + OFTableStatsReply.Builder rep = + OFFactories.getFactory(msg.getVersion()).buildTableStatsReply(); + rep.setEntries(Lists.newLinkedList(tableStats)); executorMsgs.submit(new OFMessageHandler(dpid, rep.build())); } break; @@ -423,6 +410,16 @@ public class OpenFlowControllerImpl implements OpenFlowController { return null; } + private synchronized Collection publishTableStats(Dpid dpid, + OFTableStatsReply reply) { + //TODO: Get rid of synchronized + fullTableStats.putAll(dpid, reply.getEntries()); + if (!reply.getFlags().contains(OFStatsReplyFlags.REPLY_MORE)) { + return fullTableStats.removeAll(dpid); + } + return null; + } + private synchronized Collection publishGroupStats(Dpid dpid, OFGroupStatsReply reply) { //TODO: Get rid of synchronized diff --git a/framework/src/onos/openflow/ctl/src/main/java/org/onosproject/openflow/controller/impl/OpenflowPipelineFactory.java b/framework/src/onos/openflow/ctl/src/main/java/org/onosproject/openflow/controller/impl/OpenflowPipelineFactory.java index c7ba105c..1467520d 100644 --- a/framework/src/onos/openflow/ctl/src/main/java/org/onosproject/openflow/controller/impl/OpenflowPipelineFactory.java +++ b/framework/src/onos/openflow/ctl/src/main/java/org/onosproject/openflow/controller/impl/OpenflowPipelineFactory.java @@ -27,6 +27,10 @@ import org.jboss.netty.handler.timeout.ReadTimeoutHandler; import org.jboss.netty.util.ExternalResourceReleasable; import org.jboss.netty.util.HashedWheelTimer; import org.jboss.netty.util.Timer; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import javax.net.ssl.SSLEngine; /** * Creates a ChannelPipeline for a server-side openflow channel. @@ -34,6 +38,9 @@ import org.jboss.netty.util.Timer; public class OpenflowPipelineFactory implements ChannelPipelineFactory, ExternalResourceReleasable { + private final Logger log = LoggerFactory.getLogger(getClass()); + + private final SSLEngine sslEngine; protected Controller controller; protected ThreadPoolExecutor pipelineExecutor; protected Timer timer; @@ -41,13 +48,15 @@ public class OpenflowPipelineFactory protected ReadTimeoutHandler readTimeoutHandler; public OpenflowPipelineFactory(Controller controller, - ThreadPoolExecutor pipelineExecutor) { + ThreadPoolExecutor pipelineExecutor, + SSLEngine sslEngine) { super(); this.controller = controller; this.pipelineExecutor = pipelineExecutor; this.timer = new HashedWheelTimer(); this.idleHandler = new IdleStateHandler(timer, 20, 25, 0); this.readTimeoutHandler = new ReadTimeoutHandler(timer, 30); + this.sslEngine = sslEngine; } @Override @@ -55,6 +64,13 @@ public class OpenflowPipelineFactory OFChannelHandler handler = new OFChannelHandler(controller); ChannelPipeline pipeline = Channels.pipeline(); + if (sslEngine != null) { + log.info("OpenFlow SSL enabled."); + pipeline.addLast("ssl", + new org.jboss.netty.handler.ssl.SslHandler(sslEngine)); + } else { + log.info("OpenFlow SSL disabled"); + } pipeline.addLast("ofmessagedecoder", new OFMessageDecoder()); pipeline.addLast("ofmessageencoder", new OFMessageEncoder()); pipeline.addLast("idle", idleHandler); -- cgit 1.2.3-korg