blob: 3b473b8a4b1d70f68215d3977227054e582f3aee [file] [log] [blame]
Thomas Vachuska781d18b2014-10-27 10:31:25 -07001/*
Ray Milkey34c95902015-04-15 09:47:53 -07002 * Copyright 2014-2015 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;
Jonathan Harta0d12492015-07-16 12:03:41 -070026import org.onlab.util.ItemNotFoundException;
27import org.onosproject.net.DeviceId;
alshabibb452fd72015-04-22 20:46:20 -070028import org.onosproject.net.driver.DefaultDriverData;
29import org.onosproject.net.driver.DefaultDriverHandler;
30import org.onosproject.net.driver.Driver;
31import org.onosproject.net.driver.DriverService;
Brian O'Connorabafb502014-12-02 22:26:20 -080032import org.onosproject.openflow.controller.Dpid;
33import org.onosproject.openflow.controller.driver.OpenFlowAgent;
34import org.onosproject.openflow.controller.driver.OpenFlowSwitchDriver;
tom7ef8ff92014-09-17 13:08:06 -070035import org.projectfloodlight.openflow.protocol.OFDescStatsReply;
36import org.projectfloodlight.openflow.protocol.OFFactories;
37import org.projectfloodlight.openflow.protocol.OFFactory;
38import org.projectfloodlight.openflow.protocol.OFVersion;
39import org.slf4j.Logger;
40import org.slf4j.LoggerFactory;
41
Thomas Vachuska6f94ded2015-02-21 14:02:38 -080042import java.lang.management.ManagementFactory;
43import java.lang.management.RuntimeMXBean;
44import java.net.InetSocketAddress;
Brian O'Connorff278502015-09-22 14:49:52 -070045import java.util.Dictionary;
Thomas Vachuska6f94ded2015-02-21 14:02:38 -080046import java.util.HashMap;
Brian O'Connorff278502015-09-22 14:49:52 -070047import java.util.List;
Thomas Vachuska6f94ded2015-02-21 14:02:38 -080048import java.util.Map;
49import java.util.concurrent.Executors;
Brian O'Connorff278502015-09-22 14:49:52 -070050import java.util.stream.Collectors;
51import java.util.stream.Stream;
Thomas Vachuska6f94ded2015-02-21 14:02:38 -080052
Brian O'Connorff278502015-09-22 14:49:52 -070053import static org.onlab.util.Tools.get;
Thomas Vachuska6f94ded2015-02-21 14:02:38 -080054import static org.onlab.util.Tools.groupedThreads;
Thomas Vachuska80b0a802015-07-17 08:43:30 -070055import static org.onosproject.net.DeviceId.deviceId;
56import static org.onosproject.openflow.controller.Dpid.uri;
Thomas Vachuska6f94ded2015-02-21 14:02:38 -080057
tom7ef8ff92014-09-17 13:08:06 -070058
59/**
60 * The main controller class. Handles all setup and network listeners
61 * - Distributed ownership control of switch through IControllerRegistryService
62 */
63public class Controller {
64
65 protected static final Logger log = LoggerFactory.getLogger(Controller.class);
alshabib9eab22f2014-10-20 17:17:31 -070066
tom7ef8ff92014-09-17 13:08:06 -070067 protected static final OFFactory FACTORY13 = OFFactories.getFactory(OFVersion.OF_13);
68 protected static final OFFactory FACTORY10 = OFFactories.getFactory(OFVersion.OF_10);
69
tom7ef8ff92014-09-17 13:08:06 -070070 protected HashMap<String, String> controllerNodeIPsCache;
71
72 private ChannelGroup cg;
73
74 // Configuration options
Brian O'Connorff278502015-09-22 14:49:52 -070075 protected List<Integer> openFlowPorts = ImmutableList.of(6633, 6653);
76 protected int workerThreads = 16;
tom7ef8ff92014-09-17 13:08:06 -070077
78 // Start time of the controller
79 protected long systemStartTime;
80
81 private OpenFlowAgent agent;
82
83 private NioServerSocketChannelFactory execFactory;
84
85 // Perf. related configuration
86 protected static final int SEND_BUFFER_SIZE = 4 * 1024 * 1024;
alshabibb452fd72015-04-22 20:46:20 -070087 private DriverService driverService;
tom7ef8ff92014-09-17 13:08:06 -070088
89 // ***************
90 // Getters/Setters
91 // ***************
92
93 public OFFactory getOFMessageFactory10() {
94 return FACTORY10;
95 }
96
97
98 public OFFactory getOFMessageFactory13() {
99 return FACTORY13;
100 }
101
102
tom7ef8ff92014-09-17 13:08:06 -0700103 public Map<String, String> getControllerNodeIPs() {
104 // We return a copy of the mapping so we can guarantee that
105 // the mapping return is the same as one that will be (or was)
106 // dispatched to IHAListeners
Jonathan Hartbbd91d42015-02-27 11:18:04 -0800107 HashMap<String, String> retval = new HashMap<>();
tom7ef8ff92014-09-17 13:08:06 -0700108 synchronized (controllerNodeIPsCache) {
109 retval.putAll(controllerNodeIPsCache);
110 }
111 return retval;
112 }
113
114
115 public long getSystemStartTime() {
116 return (this.systemStartTime);
117 }
118
119 // **************
120 // Initialization
121 // **************
122
123 /**
124 * Tell controller that we're ready to accept switches loop.
125 */
126 public void run() {
127
128 try {
129 final ServerBootstrap bootstrap = createServerBootStrap();
130
131 bootstrap.setOption("reuseAddr", true);
132 bootstrap.setOption("child.keepAlive", true);
133 bootstrap.setOption("child.tcpNoDelay", true);
134 bootstrap.setOption("child.sendBufferSize", Controller.SEND_BUFFER_SIZE);
135
136 ChannelPipelineFactory pfact =
137 new OpenflowPipelineFactory(this, null);
138 bootstrap.setPipelineFactory(pfact);
tom7ef8ff92014-09-17 13:08:06 -0700139 cg = new DefaultChannelGroup();
Brian O'Connorff278502015-09-22 14:49:52 -0700140 openFlowPorts.forEach(port -> {
141 InetSocketAddress sa = new InetSocketAddress(port);
142 cg.add(bootstrap.bind(sa));
143 log.info("Listening for switch connections on {}", sa);
144 });
tom7ef8ff92014-09-17 13:08:06 -0700145
tom7ef8ff92014-09-17 13:08:06 -0700146 } catch (Exception e) {
147 throw new RuntimeException(e);
148 }
149
150 }
151
152 private ServerBootstrap createServerBootStrap() {
153
154 if (workerThreads == 0) {
Thomas Vachuska6f94ded2015-02-21 14:02:38 -0800155 execFactory = new NioServerSocketChannelFactory(
156 Executors.newCachedThreadPool(groupedThreads("onos/of", "boss-%d")),
157 Executors.newCachedThreadPool(groupedThreads("onos/of", "worker-%d")));
tom7ef8ff92014-09-17 13:08:06 -0700158 return new ServerBootstrap(execFactory);
159 } else {
160 execFactory = new NioServerSocketChannelFactory(
Thomas Vachuska6f94ded2015-02-21 14:02:38 -0800161 Executors.newCachedThreadPool(groupedThreads("onos/of", "boss-%d")),
162 Executors.newCachedThreadPool(groupedThreads("onos/of", "worker-%d")), workerThreads);
tom7ef8ff92014-09-17 13:08:06 -0700163 return new ServerBootstrap(execFactory);
164 }
165 }
166
Brian O'Connorff278502015-09-22 14:49:52 -0700167 public void setConfigParams(Dictionary<?, ?> properties) {
168 String ports = get(properties, "openflowPorts");
169 if (!Strings.isNullOrEmpty(ports)) {
170 this.openFlowPorts = Stream.of(ports.split(","))
171 .map(s -> Integer.parseInt(s))
172 .collect(Collectors.toList());
tom7ef8ff92014-09-17 13:08:06 -0700173 }
Brian O'Connorff278502015-09-22 14:49:52 -0700174 log.debug("OpenFlow ports set to {}", this.openFlowPorts);
Charles Chan45624b82015-08-24 00:29:20 +0800175
Brian O'Connorff278502015-09-22 14:49:52 -0700176 String threads = get(properties, "workerThreads");
177 if (!Strings.isNullOrEmpty(threads)) {
178 this.workerThreads = Integer.parseInt(threads);
179 }
tom7ef8ff92014-09-17 13:08:06 -0700180 log.debug("Number of worker threads set to {}", this.workerThreads);
181 }
182
tom7ef8ff92014-09-17 13:08:06 -0700183 /**
184 * Initialize internal data structures.
185 */
Jonathan Hartbbd91d42015-02-27 11:18:04 -0800186 public void init() {
tom7ef8ff92014-09-17 13:08:06 -0700187 // These data structures are initialized here because other
188 // module's startUp() might be called before ours
Jonathan Hartbbd91d42015-02-27 11:18:04 -0800189 this.controllerNodeIPsCache = new HashMap<>();
tom7ef8ff92014-09-17 13:08:06 -0700190
tom7ef8ff92014-09-17 13:08:06 -0700191 this.systemStartTime = System.currentTimeMillis();
tom7ef8ff92014-09-17 13:08:06 -0700192 }
193
194 // **************
195 // Utility methods
196 // **************
197
198 public Map<String, Long> getMemory() {
Jonathan Hartbbd91d42015-02-27 11:18:04 -0800199 Map<String, Long> m = new HashMap<>();
tom7ef8ff92014-09-17 13:08:06 -0700200 Runtime runtime = Runtime.getRuntime();
201 m.put("total", runtime.totalMemory());
202 m.put("free", runtime.freeMemory());
203 return m;
204 }
205
206
207 public Long getUptime() {
208 RuntimeMXBean rb = ManagementFactory.getRuntimeMXBean();
209 return rb.getUptime();
210 }
211
212 /**
213 * Forward to the driver-manager to get an IOFSwitch instance.
Thomas Vachuska6f94ded2015-02-21 14:02:38 -0800214 *
Yuta HIGUCHI5c947272014-11-03 21:39:21 -0800215 * @param dpid data path id
216 * @param desc switch description
Thomas Vachuska6f94ded2015-02-21 14:02:38 -0800217 * @param ofv OpenFlow version
tom7ef8ff92014-09-17 13:08:06 -0700218 * @return switch instance
219 */
220 protected OpenFlowSwitchDriver getOFSwitchInstance(long dpid,
alshabibb452fd72015-04-22 20:46:20 -0700221 OFDescStatsReply desc,
222 OFVersion ofv) {
Jonathan Harta0d12492015-07-16 12:03:41 -0700223 Dpid dpidObj = new Dpid(dpid);
224
225 Driver driver;
226 try {
Sho SHIMIZUbc82ebb2015-08-25 10:15:21 -0700227 driver = driverService.getDriver(DeviceId.deviceId(Dpid.uri(dpidObj)));
Jonathan Harta0d12492015-07-16 12:03:41 -0700228 } catch (ItemNotFoundException e) {
229 driver = driverService.getDriver(desc.getMfrDesc(), desc.getHwDesc(), desc.getSwDesc());
230 }
alshabibb452fd72015-04-22 20:46:20 -0700231
Thomas Vachuska3358af22015-05-19 18:40:34 -0700232 if (driver != null && driver.hasBehaviour(OpenFlowSwitchDriver.class)) {
Thomas Vachuska80b0a802015-07-17 08:43:30 -0700233 Dpid did = new Dpid(dpid);
234 DefaultDriverHandler handler =
235 new DefaultDriverHandler(new DefaultDriverData(driver, deviceId(uri(did))));
236 OpenFlowSwitchDriver ofSwitchDriver =
237 driver.createBehaviour(handler, OpenFlowSwitchDriver.class);
238 ofSwitchDriver.init(did, desc, ofv);
alshabibb452fd72015-04-22 20:46:20 -0700239 ofSwitchDriver.setAgent(agent);
240 ofSwitchDriver.setRoleHandler(new RoleManager(ofSwitchDriver));
Saurav Das100e3b82015-04-30 11:12:10 -0700241 log.info("OpenFlow handshaker found for device {}: {}", dpid, ofSwitchDriver);
alshabibb452fd72015-04-22 20:46:20 -0700242 return ofSwitchDriver;
243 }
244 log.error("No OpenFlow driver for {} : {}", dpid, desc);
245 return null;
246
tom7ef8ff92014-09-17 13:08:06 -0700247 }
248
alshabibb452fd72015-04-22 20:46:20 -0700249 public void start(OpenFlowAgent ag, DriverService driverService) {
tom7ef8ff92014-09-17 13:08:06 -0700250 log.info("Starting OpenFlow IO");
251 this.agent = ag;
alshabibb452fd72015-04-22 20:46:20 -0700252 this.driverService = driverService;
Jonathan Hartbbd91d42015-02-27 11:18:04 -0800253 this.init();
tom7ef8ff92014-09-17 13:08:06 -0700254 this.run();
255 }
256
257
258 public void stop() {
259 log.info("Stopping OpenFlow IO");
tom7ef8ff92014-09-17 13:08:06 -0700260 cg.close();
Thomas Vachuska1c681d72015-05-18 14:58:53 -0700261 execFactory.shutdown();
tom7ef8ff92014-09-17 13:08:06 -0700262 }
263
264}