blob: b8548984d3b81f81a0d8ca26c93efa6e684e23b2 [file] [log] [blame]
Thomas Vachuska781d18b2014-10-27 10:31:25 -07001/*
Brian O'Connor5ab426f2016-04-09 01:19:45 -07002 * Copyright 2015-present Open Networking Laboratory
tom7ef8ff92014-09-17 13:08:06 -07003 *
Thomas Vachuska4f1a60c2014-10-28 13:39:07 -07004 * 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
tom7ef8ff92014-09-17 13:08:06 -07007 *
Thomas Vachuska4f1a60c2014-10-28 13:39:07 -07008 * http://www.apache.org/licenses/LICENSE-2.0
9 *
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.
Thomas Vachuska781d18b2014-10-27 10:31:25 -070015 */
tom7ef8ff92014-09-17 13:08:06 -070016
Brian O'Connorabafb502014-12-02 22:26:20 -080017package org.onosproject.openflow.controller.impl;
tom7ef8ff92014-09-17 13:08:06 -070018
Brian O'Connorff278502015-09-22 14:49:52 -070019import com.google.common.base.Strings;
20import com.google.common.collect.ImmutableList;
tom7ef8ff92014-09-17 13:08:06 -070021import org.jboss.netty.bootstrap.ServerBootstrap;
22import org.jboss.netty.channel.ChannelPipelineFactory;
23import org.jboss.netty.channel.group.ChannelGroup;
24import org.jboss.netty.channel.group.DefaultChannelGroup;
25import org.jboss.netty.channel.socket.nio.NioServerSocketChannelFactory;
alshabib5162a9d2015-12-07 17:49:37 -080026
Jonathan Harta0d12492015-07-16 12:03:41 -070027import org.onlab.util.ItemNotFoundException;
28import org.onosproject.net.DeviceId;
alshabibb452fd72015-04-22 20:46:20 -070029import org.onosproject.net.driver.DefaultDriverData;
30import org.onosproject.net.driver.DefaultDriverHandler;
31import org.onosproject.net.driver.Driver;
32import org.onosproject.net.driver.DriverService;
Brian O'Connorabafb502014-12-02 22:26:20 -080033import org.onosproject.openflow.controller.Dpid;
34import org.onosproject.openflow.controller.driver.OpenFlowAgent;
35import org.onosproject.openflow.controller.driver.OpenFlowSwitchDriver;
tom7ef8ff92014-09-17 13:08:06 -070036import org.projectfloodlight.openflow.protocol.OFDescStatsReply;
37import org.projectfloodlight.openflow.protocol.OFFactories;
38import org.projectfloodlight.openflow.protocol.OFFactory;
39import org.projectfloodlight.openflow.protocol.OFVersion;
40import org.slf4j.Logger;
41import org.slf4j.LoggerFactory;
42
alshabib9b6c19c2015-09-26 12:19:27 -070043import javax.net.ssl.KeyManagerFactory;
44import javax.net.ssl.SSLContext;
alshabib9b6c19c2015-09-26 12:19:27 -070045import javax.net.ssl.TrustManagerFactory;
46import java.io.FileInputStream;
Thomas Vachuska6f94ded2015-02-21 14:02:38 -080047import java.lang.management.ManagementFactory;
48import java.lang.management.RuntimeMXBean;
49import java.net.InetSocketAddress;
alshabib9b6c19c2015-09-26 12:19:27 -070050import java.security.KeyStore;
Brian O'Connorff278502015-09-22 14:49:52 -070051import java.util.Dictionary;
Thomas Vachuska6f94ded2015-02-21 14:02:38 -080052import java.util.HashMap;
Brian O'Connorff278502015-09-22 14:49:52 -070053import java.util.List;
Thomas Vachuska6f94ded2015-02-21 14:02:38 -080054import java.util.Map;
55import java.util.concurrent.Executors;
Brian O'Connorff278502015-09-22 14:49:52 -070056import java.util.stream.Collectors;
57import java.util.stream.Stream;
Thomas Vachuska6f94ded2015-02-21 14:02:38 -080058
Brian O'Connorff278502015-09-22 14:49:52 -070059import static org.onlab.util.Tools.get;
Thomas Vachuska6f94ded2015-02-21 14:02:38 -080060import static org.onlab.util.Tools.groupedThreads;
Thomas Vachuska80b0a802015-07-17 08:43:30 -070061import static org.onosproject.net.DeviceId.deviceId;
62import static org.onosproject.openflow.controller.Dpid.uri;
Thomas Vachuska6f94ded2015-02-21 14:02:38 -080063
tom7ef8ff92014-09-17 13:08:06 -070064
65/**
66 * The main controller class. Handles all setup and network listeners
tom7ef8ff92014-09-17 13:08:06 -070067 */
68public class Controller {
69
70 protected static final Logger log = LoggerFactory.getLogger(Controller.class);
alshabib9eab22f2014-10-20 17:17:31 -070071
Yuta HIGUCHI2341e602017-03-08 20:10:08 -080072 /**
73 * @deprecated in 1.10.0
74 */
75 @Deprecated
tom7ef8ff92014-09-17 13:08:06 -070076 protected static final OFFactory FACTORY13 = OFFactories.getFactory(OFVersion.OF_13);
Yuta HIGUCHI2341e602017-03-08 20:10:08 -080077 /**
78 * @deprecated in 1.10.0
79 */
80 @Deprecated
tom7ef8ff92014-09-17 13:08:06 -070081 protected static final OFFactory FACTORY10 = OFFactories.getFactory(OFVersion.OF_10);
Yuta HIGUCHI2341e602017-03-08 20:10:08 -080082
alshabib9b6c19c2015-09-26 12:19:27 -070083 private static final boolean TLS_DISABLED = false;
84 private static final short MIN_KS_LENGTH = 6;
tom7ef8ff92014-09-17 13:08:06 -070085
tom7ef8ff92014-09-17 13:08:06 -070086 protected HashMap<String, String> controllerNodeIPsCache;
87
88 private ChannelGroup cg;
89
90 // Configuration options
Brian O'Connorff278502015-09-22 14:49:52 -070091 protected List<Integer> openFlowPorts = ImmutableList.of(6633, 6653);
Yuta HIGUCHI8552b172016-07-25 12:10:08 -070092 protected int workerThreads = 0;
tom7ef8ff92014-09-17 13:08:06 -070093
94 // Start time of the controller
95 protected long systemStartTime;
96
97 private OpenFlowAgent agent;
98
99 private NioServerSocketChannelFactory execFactory;
100
alshabib9b6c19c2015-09-26 12:19:27 -0700101 protected String ksLocation;
102 protected String tsLocation;
103 protected char[] ksPwd;
104 protected char[] tsPwd;
alshabib5162a9d2015-12-07 17:49:37 -0800105 protected SSLContext sslContext;
alshabib9b6c19c2015-09-26 12:19:27 -0700106
tom7ef8ff92014-09-17 13:08:06 -0700107 // Perf. related configuration
108 protected static final int SEND_BUFFER_SIZE = 4 * 1024 * 1024;
Yuta HIGUCHI2341e602017-03-08 20:10:08 -0800109
alshabibb452fd72015-04-22 20:46:20 -0700110 private DriverService driverService;
Jonathan Hartb35540a2015-11-17 09:30:56 -0800111 private boolean enableOfTls = TLS_DISABLED;
tom7ef8ff92014-09-17 13:08:06 -0700112
113 // ***************
114 // Getters/Setters
115 // ***************
116
Yuta HIGUCHI2341e602017-03-08 20:10:08 -0800117 /**
118 * @return OF1.0 factory
119 * @deprecated in 1.10.0
120 */
121 @Deprecated
tom7ef8ff92014-09-17 13:08:06 -0700122 public OFFactory getOFMessageFactory10() {
123 return FACTORY10;
124 }
125
126
Yuta HIGUCHI2341e602017-03-08 20:10:08 -0800127 /**
128 * @return OF1.3 factory
129 * @deprecated in 1.10.0
130 */
131 @Deprecated
tom7ef8ff92014-09-17 13:08:06 -0700132 public OFFactory getOFMessageFactory13() {
133 return FACTORY13;
134 }
135
tom7ef8ff92014-09-17 13:08:06 -0700136 // **************
137 // Initialization
138 // **************
139
140 /**
141 * Tell controller that we're ready to accept switches loop.
142 */
143 public void run() {
144
145 try {
146 final ServerBootstrap bootstrap = createServerBootStrap();
147
148 bootstrap.setOption("reuseAddr", true);
149 bootstrap.setOption("child.keepAlive", true);
150 bootstrap.setOption("child.tcpNoDelay", true);
151 bootstrap.setOption("child.sendBufferSize", Controller.SEND_BUFFER_SIZE);
152
153 ChannelPipelineFactory pfact =
alshabib5162a9d2015-12-07 17:49:37 -0800154 new OpenflowPipelineFactory(this, null, sslContext);
tom7ef8ff92014-09-17 13:08:06 -0700155 bootstrap.setPipelineFactory(pfact);
tom7ef8ff92014-09-17 13:08:06 -0700156 cg = new DefaultChannelGroup();
Brian O'Connorff278502015-09-22 14:49:52 -0700157 openFlowPorts.forEach(port -> {
158 InetSocketAddress sa = new InetSocketAddress(port);
159 cg.add(bootstrap.bind(sa));
160 log.info("Listening for switch connections on {}", sa);
161 });
tom7ef8ff92014-09-17 13:08:06 -0700162
tom7ef8ff92014-09-17 13:08:06 -0700163 } catch (Exception e) {
164 throw new RuntimeException(e);
165 }
166
167 }
168
169 private ServerBootstrap createServerBootStrap() {
170
171 if (workerThreads == 0) {
Thomas Vachuska6f94ded2015-02-21 14:02:38 -0800172 execFactory = new NioServerSocketChannelFactory(
HIGUCHI Yutad9e01052016-04-14 09:31:42 -0700173 Executors.newCachedThreadPool(groupedThreads("onos/of", "boss-%d", log)),
174 Executors.newCachedThreadPool(groupedThreads("onos/of", "worker-%d", log)));
tom7ef8ff92014-09-17 13:08:06 -0700175 return new ServerBootstrap(execFactory);
176 } else {
177 execFactory = new NioServerSocketChannelFactory(
HIGUCHI Yutad9e01052016-04-14 09:31:42 -0700178 Executors.newCachedThreadPool(groupedThreads("onos/of", "boss-%d", log)),
179 Executors.newCachedThreadPool(groupedThreads("onos/of", "worker-%d", log)), workerThreads);
tom7ef8ff92014-09-17 13:08:06 -0700180 return new ServerBootstrap(execFactory);
181 }
182 }
183
Brian O'Connorff278502015-09-22 14:49:52 -0700184 public void setConfigParams(Dictionary<?, ?> properties) {
185 String ports = get(properties, "openflowPorts");
186 if (!Strings.isNullOrEmpty(ports)) {
187 this.openFlowPorts = Stream.of(ports.split(","))
188 .map(s -> Integer.parseInt(s))
189 .collect(Collectors.toList());
tom7ef8ff92014-09-17 13:08:06 -0700190 }
Brian O'Connorff278502015-09-22 14:49:52 -0700191 log.debug("OpenFlow ports set to {}", this.openFlowPorts);
Charles Chan45624b82015-08-24 00:29:20 +0800192
Brian O'Connorff278502015-09-22 14:49:52 -0700193 String threads = get(properties, "workerThreads");
194 if (!Strings.isNullOrEmpty(threads)) {
195 this.workerThreads = Integer.parseInt(threads);
196 }
tom7ef8ff92014-09-17 13:08:06 -0700197 log.debug("Number of worker threads set to {}", this.workerThreads);
198 }
199
tom7ef8ff92014-09-17 13:08:06 -0700200 /**
201 * Initialize internal data structures.
202 */
Jonathan Hartbbd91d42015-02-27 11:18:04 -0800203 public void init() {
tom7ef8ff92014-09-17 13:08:06 -0700204 // These data structures are initialized here because other
205 // module's startUp() might be called before ours
Jonathan Hartbbd91d42015-02-27 11:18:04 -0800206 this.controllerNodeIPsCache = new HashMap<>();
tom7ef8ff92014-09-17 13:08:06 -0700207
tom7ef8ff92014-09-17 13:08:06 -0700208 this.systemStartTime = System.currentTimeMillis();
alshabib9b6c19c2015-09-26 12:19:27 -0700209
210 try {
Jonathan Hartb35540a2015-11-17 09:30:56 -0800211 getTlsParameters();
212 if (enableOfTls) {
213 initSsl();
alshabib9b6c19c2015-09-26 12:19:27 -0700214 }
215 } catch (Exception ex) {
216 log.error("SSL init failed: {}", ex.getMessage());
217 }
alshabib9b6c19c2015-09-26 12:19:27 -0700218 }
219
Jonathan Hartb35540a2015-11-17 09:30:56 -0800220 private void getTlsParameters() {
alshabib9b6c19c2015-09-26 12:19:27 -0700221 String tempString = System.getProperty("enableOFTLS");
Jonathan Hartb35540a2015-11-17 09:30:56 -0800222 enableOfTls = Strings.isNullOrEmpty(tempString) ? TLS_DISABLED : Boolean.parseBoolean(tempString);
223 log.info("OpenFlow Security is {}", enableOfTls ? "enabled" : "disabled");
224 if (enableOfTls) {
alshabib9b6c19c2015-09-26 12:19:27 -0700225 ksLocation = System.getProperty("javax.net.ssl.keyStore");
226 if (Strings.isNullOrEmpty(ksLocation)) {
Jonathan Hartb35540a2015-11-17 09:30:56 -0800227 enableOfTls = TLS_DISABLED;
alshabib9b6c19c2015-09-26 12:19:27 -0700228 return;
229 }
230 tsLocation = System.getProperty("javax.net.ssl.trustStore");
231 if (Strings.isNullOrEmpty(tsLocation)) {
Jonathan Hartb35540a2015-11-17 09:30:56 -0800232 enableOfTls = TLS_DISABLED;
alshabib9b6c19c2015-09-26 12:19:27 -0700233 return;
234 }
235 ksPwd = System.getProperty("javax.net.ssl.keyStorePassword").toCharArray();
236 if (MIN_KS_LENGTH > ksPwd.length) {
Jonathan Hartb35540a2015-11-17 09:30:56 -0800237 enableOfTls = TLS_DISABLED;
alshabib9b6c19c2015-09-26 12:19:27 -0700238 return;
239 }
240 tsPwd = System.getProperty("javax.net.ssl.trustStorePassword").toCharArray();
241 if (MIN_KS_LENGTH > tsPwd.length) {
Jonathan Hartb35540a2015-11-17 09:30:56 -0800242 enableOfTls = TLS_DISABLED;
alshabib9b6c19c2015-09-26 12:19:27 -0700243 return;
244 }
245 }
246 }
247
Jonathan Hartb35540a2015-11-17 09:30:56 -0800248 private void initSsl() throws Exception {
alshabib9b6c19c2015-09-26 12:19:27 -0700249 TrustManagerFactory tmFactory = TrustManagerFactory.getInstance(TrustManagerFactory.getDefaultAlgorithm());
250 KeyStore ts = KeyStore.getInstance("JKS");
251 ts.load(new FileInputStream(tsLocation), tsPwd);
252 tmFactory.init(ts);
253
254 KeyManagerFactory kmf = KeyManagerFactory.getInstance(KeyManagerFactory.getDefaultAlgorithm());
255 KeyStore ks = KeyStore.getInstance("JKS");
256 ks.load(new FileInputStream(ksLocation), ksPwd);
257 kmf.init(ks, ksPwd);
258
alshabib5162a9d2015-12-07 17:49:37 -0800259 sslContext = SSLContext.getInstance("TLS");
260 sslContext.init(kmf.getKeyManagers(), tmFactory.getTrustManagers(), null);
tom7ef8ff92014-09-17 13:08:06 -0700261 }
262
263 // **************
264 // Utility methods
265 // **************
266
267 public Map<String, Long> getMemory() {
Jonathan Hartbbd91d42015-02-27 11:18:04 -0800268 Map<String, Long> m = new HashMap<>();
tom7ef8ff92014-09-17 13:08:06 -0700269 Runtime runtime = Runtime.getRuntime();
270 m.put("total", runtime.totalMemory());
271 m.put("free", runtime.freeMemory());
272 return m;
273 }
274
275
Ray Milkeydc0ff192015-11-04 13:49:52 -0800276 public Long getSystemUptime() {
tom7ef8ff92014-09-17 13:08:06 -0700277 RuntimeMXBean rb = ManagementFactory.getRuntimeMXBean();
278 return rb.getUptime();
279 }
280
Ray Milkeydc0ff192015-11-04 13:49:52 -0800281 public long getSystemStartTime() {
282 return (this.systemStartTime);
283 }
284
tom7ef8ff92014-09-17 13:08:06 -0700285 /**
286 * Forward to the driver-manager to get an IOFSwitch instance.
Thomas Vachuska6f94ded2015-02-21 14:02:38 -0800287 *
Yuta HIGUCHI5c947272014-11-03 21:39:21 -0800288 * @param dpid data path id
289 * @param desc switch description
Thomas Vachuska6f94ded2015-02-21 14:02:38 -0800290 * @param ofv OpenFlow version
tom7ef8ff92014-09-17 13:08:06 -0700291 * @return switch instance
292 */
293 protected OpenFlowSwitchDriver getOFSwitchInstance(long dpid,
alshabibb452fd72015-04-22 20:46:20 -0700294 OFDescStatsReply desc,
295 OFVersion ofv) {
Jonathan Harta0d12492015-07-16 12:03:41 -0700296 Dpid dpidObj = new Dpid(dpid);
297
298 Driver driver;
299 try {
Sho SHIMIZUbc82ebb2015-08-25 10:15:21 -0700300 driver = driverService.getDriver(DeviceId.deviceId(Dpid.uri(dpidObj)));
Jonathan Harta0d12492015-07-16 12:03:41 -0700301 } catch (ItemNotFoundException e) {
302 driver = driverService.getDriver(desc.getMfrDesc(), desc.getHwDesc(), desc.getSwDesc());
303 }
alshabibb452fd72015-04-22 20:46:20 -0700304
Jonathan Harta33134e2016-07-27 17:33:35 -0700305 if (driver == null) {
306 log.error("No OpenFlow driver for {} : {}", dpid, desc);
307 return null;
alshabibb452fd72015-04-22 20:46:20 -0700308 }
alshabibb452fd72015-04-22 20:46:20 -0700309
Jonathan Harta33134e2016-07-27 17:33:35 -0700310 log.info("Driver {} assigned to device {}", driver.name(), dpidObj);
311
312 if (!driver.hasBehaviour(OpenFlowSwitchDriver.class)) {
313 log.error("Driver {} does not support OpenFlowSwitchDriver behaviour", driver.name());
314 return null;
315 }
316
317 DefaultDriverHandler handler =
318 new DefaultDriverHandler(new DefaultDriverData(driver, deviceId(uri(dpidObj))));
319 OpenFlowSwitchDriver ofSwitchDriver =
320 driver.createBehaviour(handler, OpenFlowSwitchDriver.class);
321 ofSwitchDriver.init(dpidObj, desc, ofv);
322 ofSwitchDriver.setAgent(agent);
323 ofSwitchDriver.setRoleHandler(new RoleManager(ofSwitchDriver));
324 log.info("OpenFlow handshaker found for device {}: {}", dpid, ofSwitchDriver);
325 return ofSwitchDriver;
tom7ef8ff92014-09-17 13:08:06 -0700326 }
327
alshabibb452fd72015-04-22 20:46:20 -0700328 public void start(OpenFlowAgent ag, DriverService driverService) {
tom7ef8ff92014-09-17 13:08:06 -0700329 log.info("Starting OpenFlow IO");
330 this.agent = ag;
alshabibb452fd72015-04-22 20:46:20 -0700331 this.driverService = driverService;
Jonathan Hartbbd91d42015-02-27 11:18:04 -0800332 this.init();
tom7ef8ff92014-09-17 13:08:06 -0700333 this.run();
334 }
335
336
337 public void stop() {
338 log.info("Stopping OpenFlow IO");
tom7ef8ff92014-09-17 13:08:06 -0700339 cg.close();
Thomas Vachuska1c681d72015-05-18 14:58:53 -0700340 execFactory.shutdown();
tom7ef8ff92014-09-17 13:08:06 -0700341 }
342
343}