2 * Copyright 2014-2015 Open Networking Laboratory
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
8 * http://www.apache.org/licenses/LICENSE-2.0
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
17 package org.onosproject.openflow.controller.impl;
19 import com.google.common.base.Strings;
20 import com.google.common.collect.ImmutableList;
21 import org.jboss.netty.bootstrap.ServerBootstrap;
22 import org.jboss.netty.channel.ChannelPipelineFactory;
23 import org.jboss.netty.channel.group.ChannelGroup;
24 import org.jboss.netty.channel.group.DefaultChannelGroup;
25 import org.jboss.netty.channel.socket.nio.NioServerSocketChannelFactory;
26 import org.onlab.util.ItemNotFoundException;
27 import org.onosproject.net.DeviceId;
28 import org.onosproject.net.driver.DefaultDriverData;
29 import org.onosproject.net.driver.DefaultDriverHandler;
30 import org.onosproject.net.driver.Driver;
31 import org.onosproject.net.driver.DriverService;
32 import org.onosproject.openflow.controller.Dpid;
33 import org.onosproject.openflow.controller.driver.OpenFlowAgent;
34 import org.onosproject.openflow.controller.driver.OpenFlowSwitchDriver;
35 import org.projectfloodlight.openflow.protocol.OFDescStatsReply;
36 import org.projectfloodlight.openflow.protocol.OFFactories;
37 import org.projectfloodlight.openflow.protocol.OFFactory;
38 import org.projectfloodlight.openflow.protocol.OFVersion;
39 import org.slf4j.Logger;
40 import org.slf4j.LoggerFactory;
42 import javax.net.ssl.KeyManagerFactory;
43 import javax.net.ssl.SSLContext;
44 import javax.net.ssl.SSLEngine;
45 import javax.net.ssl.TrustManagerFactory;
46 import java.io.FileInputStream;
47 import java.lang.management.ManagementFactory;
48 import java.lang.management.RuntimeMXBean;
49 import java.net.InetSocketAddress;
50 import java.security.KeyStore;
51 import java.util.Dictionary;
52 import java.util.HashMap;
53 import java.util.List;
55 import java.util.concurrent.Executors;
56 import java.util.stream.Collectors;
57 import java.util.stream.Stream;
59 import static org.onlab.util.Tools.get;
60 import static org.onlab.util.Tools.groupedThreads;
61 import static org.onosproject.net.DeviceId.deviceId;
62 import static org.onosproject.openflow.controller.Dpid.uri;
66 * The main controller class. Handles all setup and network listeners
67 * - Distributed ownership control of switch through IControllerRegistryService
69 public class Controller {
71 protected static final Logger log = LoggerFactory.getLogger(Controller.class);
73 protected static final OFFactory FACTORY13 = OFFactories.getFactory(OFVersion.OF_13);
74 protected static final OFFactory FACTORY10 = OFFactories.getFactory(OFVersion.OF_10);
75 private static final boolean TLS_DISABLED = false;
76 private static final short MIN_KS_LENGTH = 6;
78 protected HashMap<String, String> controllerNodeIPsCache;
80 private ChannelGroup cg;
82 // Configuration options
83 protected List<Integer> openFlowPorts = ImmutableList.of(6633, 6653);
84 protected int workerThreads = 16;
86 // Start time of the controller
87 protected long systemStartTime;
89 private OpenFlowAgent agent;
91 private NioServerSocketChannelFactory execFactory;
93 protected String ksLocation;
94 protected String tsLocation;
95 protected char[] ksPwd;
96 protected char[] tsPwd;
97 private SSLEngine serverSSLEngine;
99 // Perf. related configuration
100 protected static final int SEND_BUFFER_SIZE = 4 * 1024 * 1024;
101 private DriverService driverService;
102 private boolean enableOFTLS = TLS_DISABLED;
108 public OFFactory getOFMessageFactory10() {
113 public OFFactory getOFMessageFactory13() {
122 * Tell controller that we're ready to accept switches loop.
127 final ServerBootstrap bootstrap = createServerBootStrap();
129 bootstrap.setOption("reuseAddr", true);
130 bootstrap.setOption("child.keepAlive", true);
131 bootstrap.setOption("child.tcpNoDelay", true);
132 bootstrap.setOption("child.sendBufferSize", Controller.SEND_BUFFER_SIZE);
134 ChannelPipelineFactory pfact =
135 new OpenflowPipelineFactory(this, null, serverSSLEngine);
136 bootstrap.setPipelineFactory(pfact);
137 cg = new DefaultChannelGroup();
138 openFlowPorts.forEach(port -> {
139 InetSocketAddress sa = new InetSocketAddress(port);
140 cg.add(bootstrap.bind(sa));
141 log.info("Listening for switch connections on {}", sa);
144 } catch (Exception e) {
145 throw new RuntimeException(e);
150 private ServerBootstrap createServerBootStrap() {
152 if (workerThreads == 0) {
153 execFactory = new NioServerSocketChannelFactory(
154 Executors.newCachedThreadPool(groupedThreads("onos/of", "boss-%d")),
155 Executors.newCachedThreadPool(groupedThreads("onos/of", "worker-%d")));
156 return new ServerBootstrap(execFactory);
158 execFactory = new NioServerSocketChannelFactory(
159 Executors.newCachedThreadPool(groupedThreads("onos/of", "boss-%d")),
160 Executors.newCachedThreadPool(groupedThreads("onos/of", "worker-%d")), workerThreads);
161 return new ServerBootstrap(execFactory);
165 public void setConfigParams(Dictionary<?, ?> properties) {
166 String ports = get(properties, "openflowPorts");
167 if (!Strings.isNullOrEmpty(ports)) {
168 this.openFlowPorts = Stream.of(ports.split(","))
169 .map(s -> Integer.parseInt(s))
170 .collect(Collectors.toList());
172 log.debug("OpenFlow ports set to {}", this.openFlowPorts);
174 String threads = get(properties, "workerThreads");
175 if (!Strings.isNullOrEmpty(threads)) {
176 this.workerThreads = Integer.parseInt(threads);
178 log.debug("Number of worker threads set to {}", this.workerThreads);
182 * Initialize internal data structures.
185 // These data structures are initialized here because other
186 // module's startUp() might be called before ours
187 this.controllerNodeIPsCache = new HashMap<>();
189 this.systemStartTime = System.currentTimeMillis();
196 } catch (Exception ex) {
197 log.error("SSL init failed: {}", ex.getMessage());
202 private void getTLSParameters() {
203 String tempString = System.getProperty("enableOFTLS");
204 enableOFTLS = Strings.isNullOrEmpty(tempString) ? TLS_DISABLED : Boolean.parseBoolean(tempString);
205 log.info("OpenFlow Security is {}", enableOFTLS ? "enabled" : "disabled");
207 ksLocation = System.getProperty("javax.net.ssl.keyStore");
208 if (Strings.isNullOrEmpty(ksLocation)) {
209 enableOFTLS = TLS_DISABLED;
212 tsLocation = System.getProperty("javax.net.ssl.trustStore");
213 if (Strings.isNullOrEmpty(tsLocation)) {
214 enableOFTLS = TLS_DISABLED;
217 ksPwd = System.getProperty("javax.net.ssl.keyStorePassword").toCharArray();
218 if (MIN_KS_LENGTH > ksPwd.length) {
219 enableOFTLS = TLS_DISABLED;
222 tsPwd = System.getProperty("javax.net.ssl.trustStorePassword").toCharArray();
223 if (MIN_KS_LENGTH > tsPwd.length) {
224 enableOFTLS = TLS_DISABLED;
230 private void initSSL() throws Exception {
232 TrustManagerFactory tmFactory = TrustManagerFactory.getInstance(TrustManagerFactory.getDefaultAlgorithm());
233 KeyStore ts = KeyStore.getInstance("JKS");
234 ts.load(new FileInputStream(tsLocation), tsPwd);
237 KeyManagerFactory kmf = KeyManagerFactory.getInstance(KeyManagerFactory.getDefaultAlgorithm());
238 KeyStore ks = KeyStore.getInstance("JKS");
239 ks.load(new FileInputStream(ksLocation), ksPwd);
242 SSLContext serverContext = SSLContext.getInstance("TLS");
243 serverContext.init(kmf.getKeyManagers(), tmFactory.getTrustManagers(), null);
245 serverSSLEngine = serverContext.createSSLEngine();
247 serverSSLEngine.setNeedClientAuth(true);
248 serverSSLEngine.setUseClientMode(false);
249 serverSSLEngine.setEnabledProtocols(serverSSLEngine.getSupportedProtocols());
250 serverSSLEngine.setEnabledCipherSuites(serverSSLEngine.getSupportedCipherSuites());
251 serverSSLEngine.setEnableSessionCreation(true);
258 public Map<String, Long> getMemory() {
259 Map<String, Long> m = new HashMap<>();
260 Runtime runtime = Runtime.getRuntime();
261 m.put("total", runtime.totalMemory());
262 m.put("free", runtime.freeMemory());
267 public Long getSystemUptime() {
268 RuntimeMXBean rb = ManagementFactory.getRuntimeMXBean();
269 return rb.getUptime();
272 public long getSystemStartTime() {
273 return (this.systemStartTime);
277 * Forward to the driver-manager to get an IOFSwitch instance.
279 * @param dpid data path id
280 * @param desc switch description
281 * @param ofv OpenFlow version
282 * @return switch instance
284 protected OpenFlowSwitchDriver getOFSwitchInstance(long dpid,
285 OFDescStatsReply desc,
287 Dpid dpidObj = new Dpid(dpid);
291 driver = driverService.getDriver(DeviceId.deviceId(Dpid.uri(dpidObj)));
292 } catch (ItemNotFoundException e) {
293 driver = driverService.getDriver(desc.getMfrDesc(), desc.getHwDesc(), desc.getSwDesc());
296 if (driver != null && driver.hasBehaviour(OpenFlowSwitchDriver.class)) {
297 Dpid did = new Dpid(dpid);
298 DefaultDriverHandler handler =
299 new DefaultDriverHandler(new DefaultDriverData(driver, deviceId(uri(did))));
300 OpenFlowSwitchDriver ofSwitchDriver =
301 driver.createBehaviour(handler, OpenFlowSwitchDriver.class);
302 ofSwitchDriver.init(did, desc, ofv);
303 ofSwitchDriver.setAgent(agent);
304 ofSwitchDriver.setRoleHandler(new RoleManager(ofSwitchDriver));
305 log.info("OpenFlow handshaker found for device {}: {}", dpid, ofSwitchDriver);
306 return ofSwitchDriver;
308 log.error("No OpenFlow driver for {} : {}", dpid, desc);
313 public void start(OpenFlowAgent ag, DriverService driverService) {
314 log.info("Starting OpenFlow IO");
316 this.driverService = driverService;
323 log.info("Stopping OpenFlow IO");
325 execFactory.shutdown();