blob: 55908db45a418792dc5f24c7635d8335fbcce01d [file] [log] [blame]
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -08001/**
Ray Milkey269ffb92014-04-03 14:43:30 -07002 * Copyright 2011, Big Switch Networks, Inc.
3 * Originally created by David Erickson, Stanford University
4 *
5 * Licensed under the Apache License, Version 2.0 (the "License"); you may
6 * not use this file except in compliance with the License. You may obtain
7 * a copy of the License at
8 *
9 * http://www.apache.org/licenses/LICENSE-2.0
10 *
11 * Unless required by applicable law or agreed to in writing, software
12 * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
13 * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
14 * License for the specific language governing permissions and limitations
15 * under the License.
16 **/
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -080017
18package net.floodlightcontroller.core.internal;
19
20import java.io.FileInputStream;
21import java.io.IOException;
Brian O'Connorc67f9fa2014-08-07 18:17:46 -070022import java.lang.management.ManagementFactory;
23import java.lang.management.RuntimeMXBean;
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -080024import java.net.InetSocketAddress;
Jonathan Hartd10008d2013-02-23 17:04:08 -080025import java.net.UnknownHostException;
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -080026import java.util.Collections;
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -080027import java.util.HashMap;
28import java.util.HashSet;
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -080029import java.util.List;
30import java.util.Map;
31import java.util.Map.Entry;
32import java.util.Properties;
33import java.util.Set;
34import java.util.Stack;
35import java.util.concurrent.BlockingQueue;
36import java.util.concurrent.ConcurrentHashMap;
37import java.util.concurrent.ConcurrentMap;
38import java.util.concurrent.CopyOnWriteArraySet;
39import java.util.concurrent.Executors;
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -080040import java.util.concurrent.LinkedBlockingQueue;
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -080041
42import net.floodlightcontroller.core.FloodlightContext;
43import net.floodlightcontroller.core.IFloodlightProviderService;
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -080044import net.floodlightcontroller.core.IListener.Command;
Jonathan Hartd10008d2013-02-23 17:04:08 -080045import net.floodlightcontroller.core.IOFMessageListener;
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -080046import net.floodlightcontroller.core.IOFSwitch;
Brian O'Connorc67f9fa2014-08-07 18:17:46 -070047import net.floodlightcontroller.core.IOFSwitch.PortChangeType;
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -080048import net.floodlightcontroller.core.IOFSwitchFilter;
49import net.floodlightcontroller.core.IOFSwitchListener;
Pankaj Berdedc73bb12013-08-14 13:46:38 -070050import net.floodlightcontroller.core.IUpdate;
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -080051import net.floodlightcontroller.core.annotations.LogMessageDoc;
52import net.floodlightcontroller.core.annotations.LogMessageDocs;
Brian O'Connorc67f9fa2014-08-07 18:17:46 -070053import net.floodlightcontroller.core.internal.OFChannelHandler.RoleRecvStatus;
54import net.floodlightcontroller.core.module.FloodlightModuleException;
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -080055import net.floodlightcontroller.core.util.ListenerDispatcher;
56import net.floodlightcontroller.core.web.CoreWebRoutable;
Brian O'Connorc67f9fa2014-08-07 18:17:46 -070057import net.floodlightcontroller.debugcounter.IDebugCounter;
58import net.floodlightcontroller.debugcounter.IDebugCounterService;
59import net.floodlightcontroller.debugcounter.IDebugCounterService.CounterException;
60import net.floodlightcontroller.debugcounter.IDebugCounterService.CounterType;
61import net.floodlightcontroller.debugevent.IDebugEventService;
62import net.floodlightcontroller.debugevent.IDebugEventService.EventColumn;
63import net.floodlightcontroller.debugevent.IDebugEventService.EventFieldType;
64import net.floodlightcontroller.debugevent.IDebugEventService.EventType;
65import net.floodlightcontroller.debugevent.IDebugEventService.MaxEventsRegistered;
66import net.floodlightcontroller.debugevent.IEventUpdater;
67import net.floodlightcontroller.debugevent.NullDebugEvent;
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -080068import net.floodlightcontroller.restserver.IRestApiService;
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -080069import net.floodlightcontroller.threadpool.IThreadPoolService;
Brian O'Connorc67f9fa2014-08-07 18:17:46 -070070import net.floodlightcontroller.util.LoadMonitor;
Saurav Dasfc5e3eb2014-09-25 19:05:21 -070071import net.onrc.onos.core.configmanager.INetworkConfigService;
Brian O'Connorc67f9fa2014-08-07 18:17:46 -070072import net.onrc.onos.core.drivermanager.DriverManager;
Jonathan Hart23701d12014-04-03 10:45:48 -070073import net.onrc.onos.core.linkdiscovery.ILinkDiscoveryService;
Jonathan Hartdeda0ba2014-04-03 11:14:12 -070074import net.onrc.onos.core.packet.Ethernet;
75import net.onrc.onos.core.registry.IControllerRegistryService;
Jonathan Hartdeda0ba2014-04-03 11:14:12 -070076import net.onrc.onos.core.registry.IControllerRegistryService.ControlChangeCallback;
Jonathan Harta99ec672014-04-03 11:30:34 -070077import net.onrc.onos.core.registry.RegistryException;
Pavlin Radoslavov695f8952014-07-23 16:57:01 -070078import net.onrc.onos.core.util.Dpid;
Pavlin Radoslavov53b208a2014-07-28 13:16:11 -070079import net.onrc.onos.core.util.OnosInstanceId;
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -080080
81import org.jboss.netty.bootstrap.ServerBootstrap;
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -080082import org.jboss.netty.channel.ChannelPipelineFactory;
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -080083import org.jboss.netty.channel.group.ChannelGroup;
84import org.jboss.netty.channel.group.DefaultChannelGroup;
85import org.jboss.netty.channel.socket.nio.NioServerSocketChannelFactory;
Brian O'Connorc67f9fa2014-08-07 18:17:46 -070086import org.projectfloodlight.openflow.protocol.OFDescStatsReply;
87import org.projectfloodlight.openflow.protocol.OFFactories;
88import org.projectfloodlight.openflow.protocol.OFFactory;
89import org.projectfloodlight.openflow.protocol.OFMessage;
90import org.projectfloodlight.openflow.protocol.OFPacketIn;
91import org.projectfloodlight.openflow.protocol.OFPortDesc;
92import org.projectfloodlight.openflow.protocol.OFType;
93import org.projectfloodlight.openflow.protocol.OFVersion;
94import org.projectfloodlight.openflow.protocol.match.MatchField;
95import org.projectfloodlight.openflow.protocol.match.MatchFields;
96import org.projectfloodlight.openflow.types.EthType;
97import org.projectfloodlight.openflow.types.OFPort;
98import org.projectfloodlight.openflow.util.HexString;
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -080099import org.slf4j.Logger;
100import org.slf4j.LoggerFactory;
101
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -0800102/**
Saurav Dasfcdad072014-08-13 14:15:21 -0700103 * The main controller class. Handles all setup and network listeners -
104 * Distributed ownership control of switch through IControllerRegistryService
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -0800105 */
Jonathan Hart2fa28062013-11-25 20:16:28 -0800106public class Controller implements IFloodlightProviderService {
Ray Milkey269ffb92014-04-03 14:43:30 -0700107
Yuta HIGUCHI6ac8d182013-10-22 15:24:56 -0700108 protected final static Logger log = LoggerFactory.getLogger(Controller.class);
Brian O'Connorc67f9fa2014-08-07 18:17:46 -0700109 static final String ERROR_DATABASE =
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -0800110 "The controller could not communicate with the system database.";
Brian O'Connorc67f9fa2014-08-07 18:17:46 -0700111 protected static OFFactory factory13 = OFFactories.getFactory(OFVersion.OF_13);
112 protected static OFFactory factory10 = OFFactories.getFactory(OFVersion.OF_10);
Ray Milkey269ffb92014-04-03 14:43:30 -0700113
Brian O'Connorc67f9fa2014-08-07 18:17:46 -0700114 // connectedSwitches cache contains all connected switch's channelHandlers
115 // including ones where this controller is a master/equal/slave controller
116 // as well as ones that have not been activated yet
117 protected ConcurrentHashMap<Long, OFChannelHandler> connectedSwitches;
118 // These caches contains only those switches that are active
119 protected ConcurrentHashMap<Long, IOFSwitch> activeMasterSwitches;
120 protected ConcurrentHashMap<Long, IOFSwitch> activeEqualSwitches;
121 // lock to synchronize on, when manipulating multiple caches above
122 private Object multiCacheLock;
Ray Milkey269ffb92014-04-03 14:43:30 -0700123
Brian O'Connorc67f9fa2014-08-07 18:17:46 -0700124 // The controllerNodeIPsCache maps Controller IDs to their IP address.
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -0800125 // It's only used by handleControllerNodeIPsChanged
126 protected HashMap<String, String> controllerNodeIPsCache;
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -0800127 protected BlockingQueue<IUpdate> updates;
Ray Milkey269ffb92014-04-03 14:43:30 -0700128
Saurav Dasfcdad072014-08-13 14:15:21 -0700129 protected ConcurrentMap<OFType, ListenerDispatcher<OFType, IOFMessageListener>> messageListeners;
Brian O'Connorc67f9fa2014-08-07 18:17:46 -0700130 protected Set<IOFSwitchListener> switchListeners;
Pavlin Radoslavov695f8952014-07-23 16:57:01 -0700131
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -0800132 // Module dependencies
133 protected IRestApiService restApi;
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -0800134 protected IThreadPoolService threadPool;
Jonathan Hartd10008d2013-02-23 17:04:08 -0800135 protected IControllerRegistryService registryService;
Brian O'Connorc67f9fa2014-08-07 18:17:46 -0700136 protected IDebugCounterService debugCounters;
137 protected IDebugEventService debugEvents;
Ray Milkey269ffb92014-04-03 14:43:30 -0700138
Jonathan Hart8a5d0972013-12-04 10:02:44 -0800139 protected ILinkDiscoveryService linkDiscovery;
Saurav Dasfc5e3eb2014-09-25 19:05:21 -0700140 protected INetworkConfigService networkConfig;
Ray Milkey269ffb92014-04-03 14:43:30 -0700141
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -0800142 // Configuration options
143 protected int openFlowPort = 6633;
144 protected int workerThreads = 0;
Brian O'Connorc67f9fa2014-08-07 18:17:46 -0700145
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -0800146 // The id for this controller node. Should be unique for each controller
147 // node in a controller cluster.
Pavlin Radoslavov53b208a2014-07-28 13:16:11 -0700148 private OnosInstanceId onosInstanceId = new OnosInstanceId("localhost");
Ray Milkey269ffb92014-04-03 14:43:30 -0700149
Brian O'Connorc67f9fa2014-08-07 18:17:46 -0700150 // defined counters
151 private Counters counters;
152 // Event IDs for debug events
153 protected IEventUpdater<SwitchEvent> evSwitch;
154
155 // Load monitor for overload protection
156 protected final boolean overload_drop =
Saurav Dasfcdad072014-08-13 14:15:21 -0700157 Boolean.parseBoolean(System.getProperty("overload_drop", "false"));
Brian O'Connorc67f9fa2014-08-07 18:17:46 -0700158 protected final LoadMonitor loadmonitor = new LoadMonitor(log);
Ray Milkey269ffb92014-04-03 14:43:30 -0700159
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -0800160 // Start time of the controller
161 protected long systemStartTime;
Ray Milkey269ffb92014-04-03 14:43:30 -0700162
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -0800163 // Flag to always flush flow table on switch reconnect (HA or otherwise)
164 protected boolean alwaysClearFlowsOnSwAdd = false;
Ray Milkey269ffb92014-04-03 14:43:30 -0700165
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -0800166 // Perf. related configuration
167 protected static final int SEND_BUFFER_SIZE = 4 * 1024 * 1024;
168 protected static final int BATCH_MAX_SIZE = 100;
Ray Milkey269ffb92014-04-03 14:43:30 -0700169 protected static final boolean ALWAYS_DECODE_ETH = true;
170
Brian O'Connorc67f9fa2014-08-07 18:17:46 -0700171 // ******************************
172 // Switch Management and Updates
173 // ******************************
174
175 /**
Saurav Dasfcdad072014-08-13 14:15:21 -0700176 * Switch updates are sent to all IOFSwitchListeners. A switch that is
177 * connected to this controller instance, but not activated, is not
178 * available for updates.
Jonathan Hartcb34f382014-08-12 21:11:03 -0700179 *
Saurav Dasfcdad072014-08-13 14:15:21 -0700180 * In ONOS, each controller instance can simultaneously serve in a MASTER
181 * role for some connected switches, and in a EQUAL role for other connected
182 * switches. The EQUAL role can be treated as a SLAVE role, by ensuring that
183 * the controller instance never sends packets or commands out to the
184 * switch. Activated switches, either with Controller Role MASTER or EQUAL
185 * are announced as updates. We also support announcements of controller
186 * role transitions from MASTER --> EQUAL, and EQUAL --> MASTER, for an
187 * individual switch.
Jonathan Hartcb34f382014-08-12 21:11:03 -0700188 *
Brian O'Connorc67f9fa2014-08-07 18:17:46 -0700189 * Disconnection of only activated switches are announced. Finally, changes
190 * to switch ports are announced with a portChangeType (see @IOFSwitch)
Jonathan Hartcb34f382014-08-12 21:11:03 -0700191 *
Brian O'Connorc67f9fa2014-08-07 18:17:46 -0700192 * @author saurav
193 */
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -0800194 public enum SwitchUpdateType {
Brian O'Connorc67f9fa2014-08-07 18:17:46 -0700195 /** switch activated with this controller's role as MASTER */
196 ACTIVATED_MASTER,
Saurav Dasfcdad072014-08-13 14:15:21 -0700197 /**
198 * switch activated with this controller's role as EQUAL. listener can
199 * treat this controller's role as SLAVE by not sending packets or
200 * commands to the switch
201 */
Brian O'Connorc67f9fa2014-08-07 18:17:46 -0700202 ACTIVATED_EQUAL,
203 /** this controller's role for this switch changed from Master to Equal */
204 MASTER_TO_EQUAL,
205 /** this controller's role for this switch changed form Equal to Master */
206 EQUAL_TO_MASTER,
207 /** A previously activated switch disconnected */
208 DISCONNECTED,
209 /** Port changed on a previously activated switch */
Pankaj Berde465ac7c2013-05-23 13:47:49 -0700210 PORTCHANGED,
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -0800211 }
Ray Milkey269ffb92014-04-03 14:43:30 -0700212
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -0800213 /**
Saurav Dasfcdad072014-08-13 14:15:21 -0700214 * Update message indicating a switch was added or removed ONOS: This
215 * message extended to indicate Port add or removed event.
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -0800216 */
217 protected class SwitchUpdate implements IUpdate {
Brian O'Connorc67f9fa2014-08-07 18:17:46 -0700218 public long getSwId() {
219 return swId;
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -0800220 }
Ray Milkey269ffb92014-04-03 14:43:30 -0700221
Brian O'Connorc67f9fa2014-08-07 18:17:46 -0700222 public SwitchUpdateType getSwitchUpdateType() {
223 return switchUpdateType;
224 }
225
226 public PortChangeType getPortChangeType() {
227 return changeType;
228 }
229
230 private final long swId;
231 private final SwitchUpdateType switchUpdateType;
232 private final OFPortDesc port;
233 private final PortChangeType changeType;
234
235 public SwitchUpdate(long swId, SwitchUpdateType switchUpdateType) {
236 this(swId, switchUpdateType, null, null);
237 }
Saurav Dasfcdad072014-08-13 14:15:21 -0700238
Brian O'Connorc67f9fa2014-08-07 18:17:46 -0700239 public SwitchUpdate(long swId,
Saurav Dasfcdad072014-08-13 14:15:21 -0700240 SwitchUpdateType switchUpdateType,
241 OFPortDesc port,
242 PortChangeType changeType) {
Brian O'Connorc67f9fa2014-08-07 18:17:46 -0700243 if (switchUpdateType == SwitchUpdateType.PORTCHANGED) {
244 if (port == null) {
245 throw new NullPointerException("Port must not be null " +
246 "for PORTCHANGED updates");
247 }
248 if (changeType == null) {
249 throw new NullPointerException("ChangeType must not be " +
250 "null for PORTCHANGED updates");
251 }
252 } else {
253 if (port != null || changeType != null) {
254 throw new IllegalArgumentException("port and changeType " +
255 "must be null for " + switchUpdateType +
256 " updates");
257 }
258 }
259 this.swId = swId;
260 this.switchUpdateType = switchUpdateType;
Pankaj Berde465ac7c2013-05-23 13:47:49 -0700261 this.port = port;
Brian O'Connorc67f9fa2014-08-07 18:17:46 -0700262 this.changeType = changeType;
Pankaj Berde465ac7c2013-05-23 13:47:49 -0700263 }
Ray Milkey269ffb92014-04-03 14:43:30 -0700264
Brian O'Connorc67f9fa2014-08-07 18:17:46 -0700265 @Override
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -0800266 public void dispatch() {
267 if (log.isTraceEnabled()) {
268 log.trace("Dispatching switch update {} {}",
Brian O'Connorc67f9fa2014-08-07 18:17:46 -0700269 HexString.toHexString(swId), switchUpdateType);
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -0800270 }
271 if (switchListeners != null) {
272 for (IOFSwitchListener listener : switchListeners) {
Saurav Dasfcdad072014-08-13 14:15:21 -0700273 switch (switchUpdateType) {
274 case ACTIVATED_MASTER:
275 // don't count here. We have more specific
276 // counters before the update is created
277 listener.switchActivatedMaster(swId);
278 break;
279 case ACTIVATED_EQUAL:
280 // don't count here. We have more specific
281 // counters before the update is created
282 listener.switchActivatedEqual(swId);
283 break;
284 case MASTER_TO_EQUAL:
285 listener.switchMasterToEqual(swId);
286 break;
287 case EQUAL_TO_MASTER:
288 listener.switchEqualToMaster(swId);
289 break;
290 case DISCONNECTED:
291 // don't count here. We have more specific
292 // counters before the update is created
293 listener.switchDisconnected(swId);
294 break;
295 case PORTCHANGED:
296 counters.switchPortChanged.updateCounterWithFlush();
297 listener.switchPortChanged(swId, port, changeType);
298 break;
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -0800299 }
300 }
301 }
302 }
Brian O'Connorc67f9fa2014-08-07 18:17:46 -0700303
Brian O'Connorc67f9fa2014-08-07 18:17:46 -0700304 }
305
306 protected boolean addConnectedSwitch(long dpid, OFChannelHandler h) {
307 if (connectedSwitches.get(dpid) != null) {
308 log.error("Trying to add connectedSwitch but found a previous "
309 + "value for dpid: {}", dpid);
310 return false;
311 } else {
312 connectedSwitches.put(dpid, h);
313 return true;
314 }
315 }
316
317 /**
Saurav Dasfcdad072014-08-13 14:15:21 -0700318 * Switch Events
Brian O'Connorc67f9fa2014-08-07 18:17:46 -0700319 */
320 @Override
321 public void addSwitchEvent(long dpid, String reason, boolean flushNow) {
322 if (flushNow)
323 evSwitch.updateEventWithFlush(new SwitchEvent(dpid, reason));
324 else
325 evSwitch.updateEventNoFlush(new SwitchEvent(dpid, reason));
326 }
327
328 private boolean validActivation(long dpid) {
329 if (connectedSwitches.get(dpid) == null) {
330 log.error("Trying to activate switch but is not in "
331 + "connected switches: dpid {}. Aborting ..",
332 HexString.toHexString(dpid));
333 return false;
334 }
335 if (activeMasterSwitches.get(dpid) != null ||
336 activeEqualSwitches.get(dpid) != null) {
337 log.error("Trying to activate switch but it is already "
338 + "activated: dpid {}. Found in activeMaster: {} "
339 + "Found in activeEqual: {}. Aborting ..", new Object[] {
Saurav Dasfcdad072014-08-13 14:15:21 -0700340 HexString.toHexString(dpid),
341 (activeMasterSwitches.get(dpid) == null) ? 'Y' : 'N',
342 (activeEqualSwitches.get(dpid) == null) ? 'Y' : 'N'});
Brian O'Connorc67f9fa2014-08-07 18:17:46 -0700343 counters.switchWithSameDpidActivated.updateCounterWithFlush();
344 return false;
345 }
346 return true;
347 }
348
349 /**
350 * Called when a switch is activated, with this controller's role as MASTER
351 */
352 protected boolean addActivatedMasterSwitch(long dpid, IOFSwitch sw) {
Saurav Dasfcdad072014-08-13 14:15:21 -0700353 synchronized (multiCacheLock) {
354 if (!validActivation(dpid))
355 return false;
Brian O'Connorc67f9fa2014-08-07 18:17:46 -0700356 activeMasterSwitches.put(dpid, sw);
357 }
Pavlin Radoslavov000fbae2014-08-19 19:42:58 -0700358
Saurav Dasfcdad072014-08-13 14:15:21 -0700359 // update counters and events
Brian O'Connorc67f9fa2014-08-07 18:17:46 -0700360 counters.switchActivated.updateCounterWithFlush();
361 evSwitch.updateEventWithFlush(new SwitchEvent(dpid, "activeMaster"));
362 addUpdateToQueue(new SwitchUpdate(dpid,
363 SwitchUpdateType.ACTIVATED_MASTER));
364 return true;
365 }
366
367 /**
368 * Called when a switch is activated, with this controller's role as EQUAL
369 */
370 protected boolean addActivatedEqualSwitch(long dpid, IOFSwitch sw) {
Saurav Dasfcdad072014-08-13 14:15:21 -0700371 synchronized (multiCacheLock) {
372 if (!validActivation(dpid))
373 return false;
Brian O'Connorc67f9fa2014-08-07 18:17:46 -0700374 activeEqualSwitches.put(dpid, sw);
375 }
Saurav Dasfcdad072014-08-13 14:15:21 -0700376 // update counters and events
Brian O'Connorc67f9fa2014-08-07 18:17:46 -0700377 counters.switchActivated.updateCounterWithFlush();
378 evSwitch.updateEventWithFlush(new SwitchEvent(dpid, "activeEqual"));
379 addUpdateToQueue(new SwitchUpdate(dpid,
380 SwitchUpdateType.ACTIVATED_EQUAL));
381 return true;
382 }
383
384 /**
Saurav Dasfcdad072014-08-13 14:15:21 -0700385 * Called when this controller's role for a switch transitions from equal to
386 * master. For 1.0 switches, we internally refer to the role 'slave' as
Brian O'Connorc67f9fa2014-08-07 18:17:46 -0700387 * 'equal' - so this transition is equivalent to 'addActivatedMasterSwitch'.
388 */
389 protected void transitionToMasterSwitch(long dpid) {
Saurav Dasfcdad072014-08-13 14:15:21 -0700390 synchronized (multiCacheLock) {
391 IOFSwitch sw = activeEqualSwitches.remove(dpid);
392 if (sw == null) {
393 log.error("Transition to master called on sw {}, but switch "
394 + "was not found in controller-cache", dpid);
395 return;
396 }
397 activeMasterSwitches.put(dpid, sw);
398 }
399 addUpdateToQueue(new SwitchUpdate(dpid,
Brian O'Connorc67f9fa2014-08-07 18:17:46 -0700400 SwitchUpdateType.EQUAL_TO_MASTER));
401 }
402
Brian O'Connorc67f9fa2014-08-07 18:17:46 -0700403 /**
Saurav Dasfcdad072014-08-13 14:15:21 -0700404 * Called when this controller's role for a switch transitions to equal. For
405 * 1.0 switches, we internally refer to the role 'slave' as 'equal'.
Brian O'Connorc67f9fa2014-08-07 18:17:46 -0700406 */
407 protected void transitionToEqualSwitch(long dpid) {
Saurav Dasfcdad072014-08-13 14:15:21 -0700408 synchronized (multiCacheLock) {
409 IOFSwitch sw = activeMasterSwitches.remove(dpid);
410 if (sw == null) {
411 log.error("Transition to equal called on sw {}, but switch "
412 + "was not found in controller-cache", dpid);
413 return;
414 }
415 activeEqualSwitches.put(dpid, sw);
416 }
417 addUpdateToQueue(new SwitchUpdate(dpid,
Brian O'Connorc67f9fa2014-08-07 18:17:46 -0700418 SwitchUpdateType.MASTER_TO_EQUAL));
419 }
420
421 /**
422 * Clear all state in controller switch maps for a switch that has
Saurav Dasfcdad072014-08-13 14:15:21 -0700423 * disconnected from the local controller. Also release control for that
424 * switch from the global repository. Notify switch listeners.
Brian O'Connorc67f9fa2014-08-07 18:17:46 -0700425 */
426 protected void removeConnectedSwitch(long dpid) {
427 releaseRegistryControl(dpid);
Jonathan Hart282fd4e2014-08-12 14:42:14 -0700428 OFChannelHandler ch = connectedSwitches.remove(dpid);
Brian O'Connorc67f9fa2014-08-07 18:17:46 -0700429 IOFSwitch sw = activeMasterSwitches.remove(dpid);
Saurav Dasfcdad072014-08-13 14:15:21 -0700430 if (sw == null) {
431 sw = activeEqualSwitches.remove(dpid);
432 }
Brian O'Connorc67f9fa2014-08-07 18:17:46 -0700433 if (sw != null) {
434 sw.cancelAllStatisticsReplies();
435 sw.setConnected(false); // do we need this?
436 }
437 evSwitch.updateEventWithFlush(new SwitchEvent(dpid, "disconnected"));
438 counters.switchDisconnected.updateCounterWithFlush();
Jonathan Hart282fd4e2014-08-12 14:42:14 -0700439 if (ch != null) {
440 addUpdateToQueue(new SwitchUpdate(dpid, SwitchUpdateType.DISCONNECTED));
441 }
Brian O'Connorc67f9fa2014-08-07 18:17:46 -0700442 }
443
444 /**
Saurav Dasfcdad072014-08-13 14:15:21 -0700445 * Indicates that ports on the given switch have changed. Enqueue a switch
446 * update.
Jonathan Hartcb34f382014-08-12 21:11:03 -0700447 *
Brian O'Connorc67f9fa2014-08-07 18:17:46 -0700448 * @param sw
449 */
450 protected void notifyPortChanged(long dpid, OFPortDesc port,
451 PortChangeType changeType) {
452 if (port == null || changeType == null) {
Jonathan Hart282fd4e2014-08-12 14:42:14 -0700453 String msg = String.format("Switch port or changeType must not "
Brian O'Connorc67f9fa2014-08-07 18:17:46 -0700454 + "be null in port change notification");
455 throw new NullPointerException(msg);
456 }
457 if (connectedSwitches.get(dpid) == null || getSwitch(dpid) == null) {
458 log.warn("Port change update on switch {} not connected or activated "
459 + "... Aborting.", HexString.toHexString(dpid));
460 return;
461 }
462
Brian O'Connorc67f9fa2014-08-07 18:17:46 -0700463 SwitchUpdate update = new SwitchUpdate(dpid, SwitchUpdateType.PORTCHANGED,
464 port, changeType);
465 addUpdateToQueue(update);
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -0800466 }
Ray Milkey269ffb92014-04-03 14:43:30 -0700467
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -0800468 // ***************
469 // Getters/Setters
Brian O'Connorc67f9fa2014-08-07 18:17:46 -0700470 // ***************
Ray Milkey269ffb92014-04-03 14:43:30 -0700471
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -0800472 public void setRestApiService(IRestApiService restApi) {
473 this.restApi = restApi;
474 }
Ray Milkey269ffb92014-04-03 14:43:30 -0700475
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -0800476 public void setThreadPoolService(IThreadPoolService tp) {
477 this.threadPool = tp;
478 }
479
Ray Milkey269ffb92014-04-03 14:43:30 -0700480 public void setMastershipService(IControllerRegistryService serviceImpl) {
481 this.registryService = serviceImpl;
Pankaj Berdedc73bb12013-08-14 13:46:38 -0700482 }
Ray Milkey269ffb92014-04-03 14:43:30 -0700483
484 public void setLinkDiscoveryService(ILinkDiscoveryService linkDiscovery) {
485 this.linkDiscovery = linkDiscovery;
486 }
487
Saurav Dasfc5e3eb2014-09-25 19:05:21 -0700488 public void setNetworkConfigService(INetworkConfigService networkConfigService) {
489 this.networkConfig = networkConfigService;
490 }
491
Brian O'Connorc67f9fa2014-08-07 18:17:46 -0700492 public void setDebugCounter(IDebugCounterService debugCounters) {
493 this.debugCounters = debugCounters;
494 }
495
496 public void setDebugEvent(IDebugEventService debugEvents) {
497 this.debugEvents = debugEvents;
498 }
499
500 IDebugCounterService getDebugCounter() {
501 return this.debugCounters;
Ray Milkey269ffb92014-04-03 14:43:30 -0700502 }
503
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -0800504 // **********************
Brian O'Connorc67f9fa2014-08-07 18:17:46 -0700505 // Role Handling
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -0800506 // **********************
Ray Milkey269ffb92014-04-03 14:43:30 -0700507
Saurav Dasfcdad072014-08-13 14:15:21 -0700508 /**
509 * created by ONOS - works with registry service
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -0800510 */
Jonathan Hartcc957a02013-02-26 10:39:04 -0800511 protected class RoleChangeCallback implements ControlChangeCallback {
Ray Milkey269ffb92014-04-03 14:43:30 -0700512 @Override
Pavlin Radoslavov695f8952014-07-23 16:57:01 -0700513 public void controlChanged(long dpidLong, boolean hasControl) {
514 Dpid dpid = new Dpid(dpidLong);
Ray Milkey269ffb92014-04-03 14:43:30 -0700515 log.info("Role change callback for switch {}, hasControl {}",
Brian O'Connorc67f9fa2014-08-07 18:17:46 -0700516 dpid, hasControl);
Pankaj Berde01939e92013-03-08 14:38:27 -0800517
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -0800518 Role role = null;
Ray Milkey269ffb92014-04-03 14:43:30 -0700519
Brian O'Connorc67f9fa2014-08-07 18:17:46 -0700520 /*
521 * issue #229
522 * Cannot rely on sw.getRole() as it can be behind due to pending
523 * role changes in the queue. Just submit it and late the
524 * RoleChanger handle duplicates.
525 */
Ray Milkey269ffb92014-04-03 14:43:30 -0700526
Brian O'Connorc67f9fa2014-08-07 18:17:46 -0700527 if (hasControl) {
528 role = Role.MASTER;
Ray Milkey269ffb92014-04-03 14:43:30 -0700529 } else {
Brian O'Connorc67f9fa2014-08-07 18:17:46 -0700530 role = Role.EQUAL; // treat the same as Role.SLAVE
Ray Milkey269ffb92014-04-03 14:43:30 -0700531 }
Ray Milkey269ffb92014-04-03 14:43:30 -0700532
Brian O'Connorc67f9fa2014-08-07 18:17:46 -0700533 OFChannelHandler swCh = connectedSwitches.get(dpid.value());
534 if (swCh == null) {
535 log.warn("Switch {} not found in connected switches", dpid);
536 return;
Pankaj Berde465ac7c2013-05-23 13:47:49 -0700537 }
Brian O'Connorc67f9fa2014-08-07 18:17:46 -0700538
539 log.debug("Sending role request {} msg to {}", role, dpid);
540 swCh.sendRoleRequest(role, RoleRecvStatus.MATCHED_SET_ROLE);
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -0800541 }
Brian O'Connorc67f9fa2014-08-07 18:17:46 -0700542 }
543
544 public synchronized void submitRegistryRequest(long dpid) {
545 OFChannelHandler h = connectedSwitches.get(dpid);
546 if (h == null) {
547 log.error("Trying to request registry control for switch {} "
548 + "not in connected switches. Aborting.. ",
549 HexString.toHexString(dpid));
550 // FIXME shouldn't we immediately return here?
551 }
Saurav Dasfcdad072014-08-13 14:15:21 -0700552 // Request control of the switch from the global registry
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -0800553 try {
Brian O'Connorc67f9fa2014-08-07 18:17:46 -0700554 h.controlRequested = Boolean.TRUE;
555 registryService.requestControl(dpid, new RoleChangeCallback());
556 } catch (RegistryException e) {
557 log.debug("Registry error: {}", e.getMessage());
558 h.controlRequested = Boolean.FALSE;
559 }
560 if (!h.controlRequested) { // XXX what is being attempted here?
561 // yield to allow other thread(s) to release control
562 try {
563 Thread.sleep(10);
564 } catch (InterruptedException e) {
565 // Ignore interruptions
566 }
Saurav Dasfcdad072014-08-13 14:15:21 -0700567 // safer to bounce the switch to reconnect here than proceeding
568 // further
Brian O'Connorc67f9fa2014-08-07 18:17:46 -0700569 // XXX S why? can't we just try again a little later?
570 log.debug("Closing sw:{} because we weren't able to request control " +
571 "successfully" + dpid);
572 connectedSwitches.get(dpid).disconnectSwitch();
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -0800573 }
574 }
Ray Milkey269ffb92014-04-03 14:43:30 -0700575
Brian O'Connorc67f9fa2014-08-07 18:17:46 -0700576 public synchronized void releaseRegistryControl(long dpidLong) {
577 OFChannelHandler h = connectedSwitches.get(dpidLong);
578 if (h == null) {
579 log.error("Trying to release registry control for switch {} "
580 + "not in connected switches. Aborting.. ",
581 HexString.toHexString(dpidLong));
582 return;
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -0800583 }
Brian O'Connorc67f9fa2014-08-07 18:17:46 -0700584 if (h.controlRequested) {
585 registryService.releaseControl(dpidLong);
586 }
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -0800587 }
588
Brian O'Connorc67f9fa2014-08-07 18:17:46 -0700589 // *******************
590 // OF Message Handling
591 // *******************
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -0800592
593 /**
Brian O'Connorc67f9fa2014-08-07 18:17:46 -0700594 * Handle and dispatch a message to IOFMessageListeners.
Jonathan Hartcb34f382014-08-12 21:11:03 -0700595 *
Saurav Dasfcdad072014-08-13 14:15:21 -0700596 * We only dispatch messages to listeners if the controller's role is
597 * MASTER.
Jonathan Hartcb34f382014-08-12 21:11:03 -0700598 *
Brian O'Connorc67f9fa2014-08-07 18:17:46 -0700599 * @param sw The switch sending the message
600 * @param m The message the switch sent
Saurav Dasfcdad072014-08-13 14:15:21 -0700601 * @param flContext The floodlight context to use for this message. If null,
602 * a new context will be allocated.
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -0800603 * @throws IOException
Jonathan Hartcb34f382014-08-12 21:11:03 -0700604 *
Saurav Dasfcdad072014-08-13 14:15:21 -0700605 * FIXME: this method and the ChannelHandler disagree on which
606 * messages should be dispatched and which shouldn't
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -0800607 */
608 @LogMessageDocs({
Ray Milkey269ffb92014-04-03 14:43:30 -0700609 @LogMessageDoc(level = "ERROR",
610 message = "Ignoring PacketIn (Xid = {xid}) because the data" +
611 " field is empty.",
612 explanation = "The switch sent an improperly-formatted PacketIn" +
613 " message",
614 recommendation = LogMessageDoc.CHECK_SWITCH),
615 @LogMessageDoc(level = "WARN",
616 message = "Unhandled OF Message: {} from {}",
617 explanation = "The switch sent a message not handled by " +
618 "the controller")
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -0800619 })
Saurav Dasfcdad072014-08-13 14:15:21 -0700620 @SuppressWarnings({"fallthrough", "unchecked"})
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -0800621 protected void handleMessage(IOFSwitch sw, OFMessage m,
Saurav Dasfcdad072014-08-13 14:15:21 -0700622 FloodlightContext bContext)
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -0800623 throws IOException {
624 Ethernet eth = null;
Yuta HIGUCHIa507baf2014-08-22 13:42:40 -0700625 // FIXME losing port number precision here
Brian O'Connorc67f9fa2014-08-07 18:17:46 -0700626 short inport = -1;
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -0800627
628 switch (m.getType()) {
Saurav Dasfcdad072014-08-13 14:15:21 -0700629 case PACKET_IN:
630 OFPacketIn pi = (OFPacketIn) m;
631 // log.info("saw packet in from sw {}", sw.getStringId());
632 if (pi.getData().length <= 0) {
633 log.error("Ignoring PacketIn (Xid = " + pi.getXid() +
634 ") because/* the data field is empty.");
635 return;
636 }
637
638 // get incoming port to store in floodlight context
639 if (sw.getOFVersion() == OFVersion.OF_10) {
640 inport = pi.getInPort().getShortPortNumber();
641 } else if (sw.getOFVersion() == OFVersion.OF_13) {
642 for (MatchField<?> mf : pi.getMatch().getMatchFields()) {
643 if (mf.id == MatchFields.IN_PORT) {
644 inport = pi.getMatch().get((MatchField<OFPort>) mf)
645 .getShortPortNumber();
646 break;
647 }
648 }
649 if (inport == -1) {
650 log.error("Match field for incoming port missing in "
651 + "packet-in from sw {}. Ignoring msg",
652 sw.getStringId());
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -0800653 return;
654 }
Saurav Dasfcdad072014-08-13 14:15:21 -0700655 } else {
656 // should have been taken care of earlier in handshake
657 log.error("OFVersion {} not supported for "
658 + "packet-in from sw {}. Ignoring msg",
659 sw.getOFVersion(), sw.getStringId());
660 return;
661 }
Ray Milkey269ffb92014-04-03 14:43:30 -0700662
Saurav Dasfcdad072014-08-13 14:15:21 -0700663 // decode enclosed ethernet packet to store in floodlight context
664 if (Controller.ALWAYS_DECODE_ETH) {
665 eth = new Ethernet();
666 eth.deserialize(pi.getData(), 0,
667 pi.getData().length);
668 }
669 // fall through to default case...
670
671 /*log.debug("Sw:{} packet-in: {}", sw.getStringId(),
672 String.format("0x%x", eth.getEtherType()));*/
673 if (eth.getEtherType() != (short) EthType.LLDP.getValue())
Saurav Das87cf5ae2014-10-01 15:43:48 -0700674 log.debug("Sw:{} packet-in: {}", sw.getStringId(), pi);
Saurav Dasfcdad072014-08-13 14:15:21 -0700675
676 default:
677
678 List<IOFMessageListener> listeners = null;
679
680 if (messageListeners.containsKey(m.getType())) {
681 listeners = messageListeners.get(m.getType()).
682 getOrderedListeners();
683 }
684 FloodlightContext bc = null;
685 if (listeners != null) {
686 // Check if floodlight context is passed from the calling
687 // function, if so use that floodlight context, otherwise
688 // allocate one
689 if (bContext == null) {
690 bc = flcontext_alloc();
Brian O'Connorc67f9fa2014-08-07 18:17:46 -0700691 } else {
Saurav Dasfcdad072014-08-13 14:15:21 -0700692 bc = bContext;
693 }
694 if (eth != null) {
695 IFloodlightProviderService.bcStore.put(bc,
696 IFloodlightProviderService.CONTEXT_PI_PAYLOAD,
697 eth);
698 }
699 if (inport != -1) {
700 bc.getStorage().put(
701 IFloodlightProviderService.CONTEXT_PI_INPORT,
702 inport);
Brian O'Connorc67f9fa2014-08-07 18:17:46 -0700703 }
704
Saurav Dasfcdad072014-08-13 14:15:21 -0700705 // Get the starting time (overall and per-component) of
706 // the processing chain for this packet if performance
707 // monitoring is turned on
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -0800708
Saurav Dasfcdad072014-08-13 14:15:21 -0700709 Command cmd = null;
710 for (IOFMessageListener listener : listeners) {
711 if (listener instanceof IOFSwitchFilter) {
712 if (!((IOFSwitchFilter) listener).isInterested(sw)) {
713 continue;
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -0800714 }
715 }
mininet73e7fb72013-12-03 14:25:53 -0800716
Saurav Dasfcdad072014-08-13 14:15:21 -0700717 cmd = listener.receive(sw, m, bc);
718
719 if (Command.STOP.equals(cmd)) {
720 break;
721 }
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -0800722 }
Ray Milkey269ffb92014-04-03 14:43:30 -0700723
Saurav Dasfcdad072014-08-13 14:15:21 -0700724 } else {
725 log.warn("Unhandled OF Message: {} from {}", m, sw);
726 }
727
728 if ((bContext == null) && (bc != null))
729 flcontext_free(bc);
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -0800730 }
731 }
Ray Milkey269ffb92014-04-03 14:43:30 -0700732
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -0800733 // ***************
Brian O'Connorc67f9fa2014-08-07 18:17:46 -0700734 // IFloodlightProviderService
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -0800735 // ***************
Ray Milkey269ffb92014-04-03 14:43:30 -0700736
Brian O'Connorc67f9fa2014-08-07 18:17:46 -0700737 // FIXME: remove this method
738 @Override
Saurav Dasfcdad072014-08-13 14:15:21 -0700739 public Map<Long, IOFSwitch> getSwitches() {
Brian O'Connorc67f9fa2014-08-07 18:17:46 -0700740 return getMasterSwitches();
741 }
742
743 // FIXME: remove this method
744 public Map<Long, IOFSwitch> getMasterSwitches() {
745 return Collections.unmodifiableMap(activeMasterSwitches);
746 }
747
Brian O'Connorc67f9fa2014-08-07 18:17:46 -0700748 @Override
749 public Set<Long> getAllSwitchDpids() {
750 Set<Long> dpids = new HashSet<Long>();
751 dpids.addAll(activeMasterSwitches.keySet());
752 dpids.addAll(activeEqualSwitches.keySet());
753 return dpids;
754 }
755
756 @Override
757 public Set<Long> getAllMasterSwitchDpids() {
758 Set<Long> dpids = new HashSet<Long>();
759 dpids.addAll(activeMasterSwitches.keySet());
760 return dpids;
761 }
762
763 @Override
764 public Set<Long> getAllEqualSwitchDpids() {
765 Set<Long> dpids = new HashSet<Long>();
766 dpids.addAll(activeEqualSwitches.keySet());
767 return dpids;
768 }
769
770 @Override
771 public IOFSwitch getSwitch(long dpid) {
772 IOFSwitch sw = null;
Saurav Dasfcdad072014-08-13 14:15:21 -0700773 if ((sw = activeMasterSwitches.get(dpid)) != null)
774 return sw;
775 if ((sw = activeEqualSwitches.get(dpid)) != null)
776 return sw;
Brian O'Connorc67f9fa2014-08-07 18:17:46 -0700777 return sw;
778 }
779
780 @Override
781 public IOFSwitch getMasterSwitch(long dpid) {
Saurav Dasfcdad072014-08-13 14:15:21 -0700782 return activeMasterSwitches.get(dpid);
Brian O'Connorc67f9fa2014-08-07 18:17:46 -0700783 }
784
785 @Override
786 public IOFSwitch getEqualSwitch(long dpid) {
Saurav Dasfcdad072014-08-13 14:15:21 -0700787 return activeEqualSwitches.get(dpid);
Brian O'Connorc67f9fa2014-08-07 18:17:46 -0700788 }
789
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -0800790 @Override
Ray Milkey269ffb92014-04-03 14:43:30 -0700791 public synchronized void addOFMessageListener(OFType type,
Saurav Dasfcdad072014-08-13 14:15:21 -0700792 IOFMessageListener listener) {
Ray Milkey269ffb92014-04-03 14:43:30 -0700793 ListenerDispatcher<OFType, IOFMessageListener> ldd =
794 messageListeners.get(type);
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -0800795 if (ldd == null) {
796 ldd = new ListenerDispatcher<OFType, IOFMessageListener>();
797 messageListeners.put(type, ldd);
798 }
799 ldd.addListener(type, listener);
800 }
801
802 @Override
803 public synchronized void removeOFMessageListener(OFType type,
Saurav Dasfcdad072014-08-13 14:15:21 -0700804 IOFMessageListener listener) {
Ray Milkey269ffb92014-04-03 14:43:30 -0700805 ListenerDispatcher<OFType, IOFMessageListener> ldd =
806 messageListeners.get(type);
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -0800807 if (ldd != null) {
808 ldd.removeListener(listener);
809 }
810 }
Ray Milkey269ffb92014-04-03 14:43:30 -0700811
Brian O'Connorc67f9fa2014-08-07 18:17:46 -0700812 public void removeOFMessageListeners(OFType type) {
813 messageListeners.remove(type);
814 }
815
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -0800816 private void logListeners() {
Saurav Dasfcdad072014-08-13 14:15:21 -0700817 for (Map.Entry<OFType, ListenerDispatcher<OFType, IOFMessageListener>> entry : messageListeners
818 .entrySet()) {
Ray Milkey269ffb92014-04-03 14:43:30 -0700819
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -0800820 OFType type = entry.getKey();
Ray Milkey269ffb92014-04-03 14:43:30 -0700821 ListenerDispatcher<OFType, IOFMessageListener> ldd =
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -0800822 entry.getValue();
Ray Milkey269ffb92014-04-03 14:43:30 -0700823
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -0800824 StringBuffer sb = new StringBuffer();
Brian O'Connorc67f9fa2014-08-07 18:17:46 -0700825 sb.append("OFMessageListeners for ");
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -0800826 sb.append(type);
827 sb.append(": ");
828 for (IOFMessageListener l : ldd.getOrderedListeners()) {
829 sb.append(l.getName());
830 sb.append(",");
831 }
Ray Milkey269ffb92014-04-03 14:43:30 -0700832 log.debug(sb.toString());
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -0800833 }
Brian O'Connorc67f9fa2014-08-07 18:17:46 -0700834 StringBuffer sl = new StringBuffer();
835 sl.append("SwitchUpdate Listeners: ");
836 for (IOFSwitchListener swlistener : switchListeners) {
837 sl.append(swlistener.getName());
838 sl.append(",");
839 }
840 log.debug(sl.toString());
Ray Milkey269ffb92014-04-03 14:43:30 -0700841
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -0800842 }
843
844 @Override
845 public void addOFSwitchListener(IOFSwitchListener listener) {
846 this.switchListeners.add(listener);
847 }
848
849 @Override
850 public void removeOFSwitchListener(IOFSwitchListener listener) {
851 this.switchListeners.remove(listener);
852 }
853
854 @Override
855 public Map<OFType, List<IOFMessageListener>> getListeners() {
Ray Milkey269ffb92014-04-03 14:43:30 -0700856 Map<OFType, List<IOFMessageListener>> lers =
857 new HashMap<OFType, List<IOFMessageListener>>();
Saurav Dasfcdad072014-08-13 14:15:21 -0700858 for (Entry<OFType, ListenerDispatcher<OFType, IOFMessageListener>> e : messageListeners
859 .entrySet()) {
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -0800860 lers.put(e.getKey(), e.getValue().getOrderedListeners());
861 }
862 return Collections.unmodifiableMap(lers);
863 }
Ray Milkey269ffb92014-04-03 14:43:30 -0700864
Brian O'Connorc67f9fa2014-08-07 18:17:46 -0700865 /*@Override
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -0800866 @LogMessageDocs({
Ray Milkey269ffb92014-04-03 14:43:30 -0700867 @LogMessageDoc(message = "Failed to inject OFMessage {message} onto " +
868 "a null switch",
869 explanation = "Failed to process a message because the switch " +
870 " is no longer connected."),
871 @LogMessageDoc(level = "ERROR",
872 message = "Error reinjecting OFMessage on switch {switch}",
873 explanation = "An I/O error occured while attempting to " +
874 "process an OpenFlow message",
875 recommendation = LogMessageDoc.CHECK_SWITCH)
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -0800876 })
877 public boolean injectOfMessage(IOFSwitch sw, OFMessage msg,
878 FloodlightContext bc) {
879 if (sw == null) {
880 log.info("Failed to inject OFMessage {} onto a null switch", msg);
881 return false;
882 }
Ray Milkey269ffb92014-04-03 14:43:30 -0700883
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -0800884 // FIXME: Do we need to be able to inject messages to switches
885 // where we're the slave controller (i.e. they're connected but
886 // not active)?
887 // FIXME: Don't we need synchronization logic here so we're holding
888 // the listener read lock when we call handleMessage? After some
889 // discussions it sounds like the right thing to do here would be to
890 // inject the message as a netty upstream channel event so it goes
891 // through the normal netty event processing, including being
Brian O'Connorc67f9fa2014-08-07 18:17:46 -0700892 // handled
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -0800893 if (!activeSwitches.containsKey(sw.getId())) return false;
Ray Milkey269ffb92014-04-03 14:43:30 -0700894
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -0800895 try {
896 // Pass Floodlight context to the handleMessages()
897 handleMessage(sw, msg, bc);
898 } catch (IOException e) {
Ray Milkey269ffb92014-04-03 14:43:30 -0700899 log.error("Error reinjecting OFMessage on switch {}",
900 HexString.toHexString(sw.getId()));
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -0800901 return false;
902 }
903 return true;
Brian O'Connorc67f9fa2014-08-07 18:17:46 -0700904 }*/
905
Saurav Dasfcdad072014-08-13 14:15:21 -0700906 // @Override
907 // public boolean injectOfMessage(IOFSwitch sw, OFMessage msg) {
908 // // call the overloaded version with floodlight context set to null
909 // return injectOfMessage(sw, msg, null);
910 // }
Brian O'Connorc67f9fa2014-08-07 18:17:46 -0700911
Saurav Dasfcdad072014-08-13 14:15:21 -0700912 // @Override
913 // public void handleOutgoingMessage(IOFSwitch sw, OFMessage m,
914 // FloodlightContext bc) {
915 //
916 // List<IOFMessageListener> listeners = null;
917 // if (messageListeners.containsKey(m.getType())) {
918 // listeners =
919 // messageListeners.get(m.getType()).getOrderedListeners();
920 // }
921 //
922 // if (listeners != null) {
923 // for (IOFMessageListener listener : listeners) {
924 // if (listener instanceof IOFSwitchFilter) {
925 // if (!((IOFSwitchFilter) listener).isInterested(sw)) {
926 // continue;
927 // }
928 // }
929 // if (Command.STOP.equals(listener.receive(sw, m, bc))) {
930 // break;
931 // }
932 // }
933 // }
934 // }
Jonathan Harta213bce2014-08-11 15:44:07 -0700935
936 /**
937 * Gets an OpenFlow message factory for version 1.0.
Jonathan Hartcb34f382014-08-12 21:11:03 -0700938 *
Jonathan Harta213bce2014-08-11 15:44:07 -0700939 * @return an OpenFlow 1.0 message factory
940 */
Brian O'Connorc67f9fa2014-08-07 18:17:46 -0700941 public OFFactory getOFMessageFactory_10() {
942 return factory10;
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -0800943 }
944
Jonathan Harta213bce2014-08-11 15:44:07 -0700945 /**
946 * Gets an OpenFlow message factory for version 1.3.
Jonathan Hartcb34f382014-08-12 21:11:03 -0700947 *
Jonathan Harta213bce2014-08-11 15:44:07 -0700948 * @return an OpenFlow 1.3 message factory
949 */
Brian O'Connorc67f9fa2014-08-07 18:17:46 -0700950 public OFFactory getOFMessageFactory_13() {
951 return factory13;
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -0800952 }
Ray Milkey269ffb92014-04-03 14:43:30 -0700953
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -0800954 @Override
Brian O'Connorc67f9fa2014-08-07 18:17:46 -0700955 public void publishUpdate(IUpdate update) {
956 try {
957 this.updates.put(update);
958 } catch (InterruptedException e) {
959 log.error("Failure adding update to queue", e);
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -0800960 }
961 }
962
963 @Override
Brian O'Connorc67f9fa2014-08-07 18:17:46 -0700964 public Map<String, String> getControllerNodeIPs() {
965 // We return a copy of the mapping so we can guarantee that
966 // the mapping return is the same as one that will be (or was)
967 // dispatched to IHAListeners
968 HashMap<String, String> retval = new HashMap<String, String>();
969 synchronized (controllerNodeIPsCache) {
970 retval.putAll(controllerNodeIPsCache);
971 }
972 return retval;
973 }
974
975 @Override
976 public long getSystemStartTime() {
977 return (this.systemStartTime);
978 }
979
980 @Override
981 public void setAlwaysClearFlowsOnSwAdd(boolean value) {
982 this.alwaysClearFlowsOnSwAdd = value;
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -0800983 }
Ray Milkey269ffb92014-04-03 14:43:30 -0700984
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -0800985 @Override
Pavlin Radoslavov53b208a2014-07-28 13:16:11 -0700986 public OnosInstanceId getOnosInstanceId() {
987 return onosInstanceId;
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -0800988 }
Ray Milkey269ffb92014-04-03 14:43:30 -0700989
Brian O'Connorc67f9fa2014-08-07 18:17:46 -0700990 /**
991 * FOR TESTING ONLY. Dispatch all updates in the update queue until queue is
992 * empty
993 */
994 void processUpdateQueueForTesting() {
995 while (!updates.isEmpty()) {
996 IUpdate update = updates.poll();
997 if (update != null)
998 update.dispatch();
999 }
1000 }
1001
Saurav Dasfc5e3eb2014-09-25 19:05:21 -07001002 public INetworkConfigService getNetworkConfigService() {
1003 return networkConfig;
1004 }
1005
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -08001006 // **************
1007 // Initialization
1008 // **************
1009
Brian O'Connorc67f9fa2014-08-07 18:17:46 -07001010 // XXX S This should probably go away OR it should be edited to handle
1011 // controller roles per switch! Then it could be a way to
1012 // deterministically configure a switch to a MASTER controller instance
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -08001013 /**
Saurav Dasfcdad072014-08-13 14:15:21 -07001014 * Sets the initial role based on properties in the config params. It looks
1015 * for two different properties. If the "role" property is specified then
1016 * the value should be either "EQUAL", "MASTER", or "SLAVE" and the role of
1017 * the controller is set to the specified value. If the "role" property is
1018 * not specified then it looks next for the "role.path" property. In this
1019 * case the value should be the path to a property file in the file system
1020 * that contains a property called "floodlight.role" which can be one of the
1021 * values listed above for the "role" property. The idea behind the
1022 * "role.path" mechanism is that you have some separate heartbeat and master
1023 * controller election algorithm that determines the role of the controller.
1024 * When a role transition happens, it updates the current role in the file
1025 * specified by the "role.path" file. Then if floodlight restarts for some
1026 * reason it can get the correct current role of the controller from the
1027 * file.
Jonathan Hartcb34f382014-08-12 21:11:03 -07001028 *
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -08001029 * @param configParams The config params for the FloodlightProvider service
Saurav Dasfcdad072014-08-13 14:15:21 -07001030 * @return A valid role if role information is specified in the config
1031 * params, otherwise null
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -08001032 */
1033 @LogMessageDocs({
Ray Milkey269ffb92014-04-03 14:43:30 -07001034 @LogMessageDoc(message = "Controller role set to {role}",
1035 explanation = "Setting the initial HA role to "),
1036 @LogMessageDoc(level = "ERROR",
1037 message = "Invalid current role value: {role}",
1038 explanation = "An invalid HA role value was read from the " +
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -08001039 "properties file",
Ray Milkey269ffb92014-04-03 14:43:30 -07001040 recommendation = LogMessageDoc.CHECK_CONTROLLER)
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -08001041 })
1042 protected Role getInitialRole(Map<String, String> configParams) {
1043 Role role = null;
1044 String roleString = configParams.get("role");
Praseed Balakrishnan59469e92014-06-20 11:55:13 -07001045 FileInputStream fs = null;
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -08001046 if (roleString == null) {
1047 String rolePath = configParams.get("rolepath");
1048 if (rolePath != null) {
1049 Properties properties = new Properties();
1050 try {
Praseed Balakrishnan59469e92014-06-20 11:55:13 -07001051 fs = new FileInputStream(rolePath);
1052 properties.load(fs);
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -08001053 roleString = properties.getProperty("floodlight.role");
Ray Milkey269ffb92014-04-03 14:43:30 -07001054 } catch (IOException exc) {
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -08001055 // Don't treat it as an error if the file specified by the
1056 // rolepath property doesn't exist. This lets us enable the
1057 // HA mechanism by just creating/setting the floodlight.role
1058 // property in that file without having to modify the
1059 // floodlight properties.
Praseed Balakrishnan59469e92014-06-20 11:55:13 -07001060 } finally {
1061 if (fs != null) {
1062 try {
1063 fs.close();
1064 } catch (IOException e) {
1065 log.error("Exception while closing resource ", e);
1066 }
1067 }
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -08001068 }
1069 }
1070 }
Ray Milkey269ffb92014-04-03 14:43:30 -07001071
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -08001072 if (roleString != null) {
1073 // Canonicalize the string to the form used for the enum constants
1074 roleString = roleString.trim().toUpperCase();
1075 try {
1076 role = Role.valueOf(roleString);
Ray Milkey269ffb92014-04-03 14:43:30 -07001077 } catch (IllegalArgumentException exc) {
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -08001078 log.error("Invalid current role value: {}", roleString);
1079 }
1080 }
Ray Milkey269ffb92014-04-03 14:43:30 -07001081
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -08001082 log.info("Controller role set to {}", role);
Ray Milkey269ffb92014-04-03 14:43:30 -07001083
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -08001084 return role;
1085 }
Ray Milkey269ffb92014-04-03 14:43:30 -07001086
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -08001087 /**
1088 * Tell controller that we're ready to accept switches loop
Jonathan Hartcb34f382014-08-12 21:11:03 -07001089 *
Ray Milkey269ffb92014-04-03 14:43:30 -07001090 * @throws IOException
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -08001091 */
Brian O'Connorc67f9fa2014-08-07 18:17:46 -07001092 @Override
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -08001093 @LogMessageDocs({
Ray Milkey269ffb92014-04-03 14:43:30 -07001094 @LogMessageDoc(message = "Listening for switch connections on {address}",
1095 explanation = "The controller is ready and listening for new" +
1096 " switch connections"),
1097 @LogMessageDoc(message = "Storage exception in controller " +
1098 "updates loop; terminating process",
1099 explanation = ERROR_DATABASE,
1100 recommendation = LogMessageDoc.CHECK_CONTROLLER),
1101 @LogMessageDoc(level = "ERROR",
1102 message = "Exception in controller updates loop",
1103 explanation = "Failed to dispatch controller event",
1104 recommendation = LogMessageDoc.GENERIC_ACTION)
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -08001105 })
1106 public void run() {
1107 if (log.isDebugEnabled()) {
1108 logListeners();
1109 }
Ray Milkey269ffb92014-04-03 14:43:30 -07001110
1111 try {
1112 final ServerBootstrap bootstrap = createServerBootStrap();
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -08001113
1114 bootstrap.setOption("reuseAddr", true);
1115 bootstrap.setOption("child.keepAlive", true);
1116 bootstrap.setOption("child.tcpNoDelay", true);
1117 bootstrap.setOption("child.sendBufferSize", Controller.SEND_BUFFER_SIZE);
1118
Ray Milkey269ffb92014-04-03 14:43:30 -07001119 ChannelPipelineFactory pfact =
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -08001120 new OpenflowPipelineFactory(this, null);
1121 bootstrap.setPipelineFactory(pfact);
1122 InetSocketAddress sa = new InetSocketAddress(openFlowPort);
1123 final ChannelGroup cg = new DefaultChannelGroup();
1124 cg.add(bootstrap.bind(sa));
Ray Milkey269ffb92014-04-03 14:43:30 -07001125
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -08001126 log.info("Listening for switch connections on {}", sa);
1127 } catch (Exception e) {
1128 throw new RuntimeException(e);
1129 }
1130
1131 // main loop
1132 while (true) {
1133 try {
1134 IUpdate update = updates.take();
1135 update.dispatch();
1136 } catch (InterruptedException e) {
Brian O'Connorc67f9fa2014-08-07 18:17:46 -07001137 log.error("Received interrupted exception in updates loop;" +
Saurav Dasfcdad072014-08-13 14:15:21 -07001138 "terminating process");
Brian O'Connorc67f9fa2014-08-07 18:17:46 -07001139 terminate();
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -08001140 } catch (Exception e) {
1141 log.error("Exception in controller updates loop", e);
1142 }
1143 }
1144 }
1145
1146 private ServerBootstrap createServerBootStrap() {
1147 if (workerThreads == 0) {
1148 return new ServerBootstrap(
1149 new NioServerSocketChannelFactory(
1150 Executors.newCachedThreadPool(),
1151 Executors.newCachedThreadPool()));
1152 } else {
1153 return new ServerBootstrap(
1154 new NioServerSocketChannelFactory(
1155 Executors.newCachedThreadPool(),
1156 Executors.newCachedThreadPool(), workerThreads));
1157 }
1158 }
Ray Milkey269ffb92014-04-03 14:43:30 -07001159
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -08001160 public void setConfigParams(Map<String, String> configParams) {
1161 String ofPort = configParams.get("openflowport");
1162 if (ofPort != null) {
1163 this.openFlowPort = Integer.parseInt(ofPort);
1164 }
1165 log.debug("OpenFlow port set to {}", this.openFlowPort);
1166 String threads = configParams.get("workerthreads");
1167 if (threads != null) {
1168 this.workerThreads = Integer.parseInt(threads);
1169 }
1170 log.debug("Number of worker threads set to {}", this.workerThreads);
1171 String controllerId = configParams.get("controllerid");
1172 if (controllerId != null) {
Pavlin Radoslavov53b208a2014-07-28 13:16:11 -07001173 this.onosInstanceId = new OnosInstanceId(controllerId);
Ray Milkey269ffb92014-04-03 14:43:30 -07001174 } else {
Saurav Dasfcdad072014-08-13 14:15:21 -07001175 // Try to get the hostname of the machine and use that for
1176 // controller ID
Ray Milkey269ffb92014-04-03 14:43:30 -07001177 try {
1178 String hostname = java.net.InetAddress.getLocalHost().getHostName();
Pavlin Radoslavov53b208a2014-07-28 13:16:11 -07001179 this.onosInstanceId = new OnosInstanceId(hostname);
Ray Milkey269ffb92014-04-03 14:43:30 -07001180 } catch (UnknownHostException e) {
1181 // Can't get hostname, we'll just use the default
1182 }
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -08001183 }
Ray Milkey269ffb92014-04-03 14:43:30 -07001184
Jonathan Hart6eda2302014-08-14 14:57:03 -07001185 String useOnly10 = configParams.get("useOnly10");
1186 if (useOnly10 != null && useOnly10.equalsIgnoreCase("true")) {
1187 OFChannelHandler.useOnly10 = true;
1188 log.info("Setting controller to only use OpenFlow 1.0");
1189 }
1190
Pavlin Radoslavov53b208a2014-07-28 13:16:11 -07001191 log.debug("ControllerId set to {}", this.onosInstanceId);
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -08001192 }
1193
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -08001194 /**
1195 * Initialize internal data structures
1196 */
1197 public void init(Map<String, String> configParams) {
1198 // These data structures are initialized here because other
1199 // module's startUp() might be called before ours
1200 this.messageListeners =
Brian O'Connorc67f9fa2014-08-07 18:17:46 -07001201 new ConcurrentHashMap<OFType, ListenerDispatcher<OFType,
Saurav Dasfcdad072014-08-13 14:15:21 -07001202 IOFMessageListener>>();
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -08001203 this.switchListeners = new CopyOnWriteArraySet<IOFSwitchListener>();
Brian O'Connorc67f9fa2014-08-07 18:17:46 -07001204 this.activeMasterSwitches = new ConcurrentHashMap<Long, IOFSwitch>();
1205 this.activeEqualSwitches = new ConcurrentHashMap<Long, IOFSwitch>();
1206 this.connectedSwitches = new ConcurrentHashMap<Long, OFChannelHandler>();
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -08001207 this.controllerNodeIPsCache = new HashMap<String, String>();
1208 this.updates = new LinkedBlockingQueue<IUpdate>();
Brian O'Connorc67f9fa2014-08-07 18:17:46 -07001209
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -08001210 setConfigParams(configParams);
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -08001211 this.systemStartTime = System.currentTimeMillis();
Brian O'Connorc67f9fa2014-08-07 18:17:46 -07001212 this.counters = new Counters();
1213 this.multiCacheLock = new Object();
1214
1215 String option = configParams.get("flushSwitchesOnReconnect");
1216 if (option != null && option.equalsIgnoreCase("true")) {
1217 this.setAlwaysClearFlowsOnSwActivate(true);
1218 log.info("Flush switches on reconnect -- Enabled.");
1219 } else {
1220 this.setAlwaysClearFlowsOnSwActivate(false);
1221 log.info("Flush switches on reconnect -- Disabled");
1222 }
Jonathan Hartcb34f382014-08-12 21:11:03 -07001223
1224 option = configParams.get("cpqdUsePipeline13");
1225 if (option != null && option.equalsIgnoreCase("true")) {
1226 DriverManager.setConfigForCpqd(true);
1227 log.info("Using OF1.3 pipeline for the CPqD software switch");
1228 } else {
1229 log.info("Using OF1.0 pipeline for the CPqD software switch");
1230 }
Jonathan Hart2c44a642014-08-19 03:40:43 -07001231
1232 String disableOvsClassification =
1233 configParams.get("disableOvsClassification");
1234 if (disableOvsClassification != null &&
1235 disableOvsClassification.equalsIgnoreCase("true")) {
1236 DriverManager.setDisableOvsClassification(true);
1237 log.info("OVS switches will be classified as default switches");
1238 }
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -08001239 }
Ray Milkey269ffb92014-04-03 14:43:30 -07001240
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -08001241 /**
1242 * Startup all of the controller's components
Jonathan Hartcb34f382014-08-12 21:11:03 -07001243 *
Brian O'Connorc67f9fa2014-08-07 18:17:46 -07001244 * @throws FloodlightModuleException
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -08001245 */
Ray Milkey269ffb92014-04-03 14:43:30 -07001246 @LogMessageDoc(message = "Waiting for storage source",
1247 explanation = "The system database is not yet ready",
1248 recommendation = "If this message persists, this indicates " +
1249 "that the system database has failed to start. " +
1250 LogMessageDoc.CHECK_CONTROLLER)
Brian O'Connorc67f9fa2014-08-07 18:17:46 -07001251 public void startupComponents() throws FloodlightModuleException {
Ray Milkey269ffb92014-04-03 14:43:30 -07001252 try {
Pavlin Radoslavov53b208a2014-07-28 13:16:11 -07001253 registryService.registerController(onosInstanceId.toString());
Ray Milkey269ffb92014-04-03 14:43:30 -07001254 } catch (RegistryException e) {
1255 log.warn("Registry service error: {}", e.getMessage());
1256 }
1257
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -08001258 // Add our REST API
1259 restApi.addRestletRoutable(new CoreWebRoutable());
Ray Milkey269ffb92014-04-03 14:43:30 -07001260
Brian O'Connorc67f9fa2014-08-07 18:17:46 -07001261 // Startup load monitoring
1262 if (overload_drop) {
1263 this.loadmonitor.startMonitoring(
Saurav Dasfcdad072014-08-13 14:15:21 -07001264 this.threadPool.getScheduledExecutor());
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -08001265 }
Brian O'Connorc67f9fa2014-08-07 18:17:46 -07001266
1267 // register counters and events
1268 try {
1269 this.counters.createCounters(debugCounters);
1270 } catch (CounterException e) {
1271 throw new FloodlightModuleException(e.getMessage());
1272 }
1273 registerControllerDebugEvents();
1274 }
1275
1276 // **************
1277 // debugCounter registrations
1278 // **************
1279
1280 public static class Counters {
1281 public static final String prefix = "controller";
1282 public IDebugCounter setRoleEqual;
1283 public IDebugCounter setSameRole;
1284 public IDebugCounter setRoleMaster;
1285 public IDebugCounter remoteStoreNotification;
1286 public IDebugCounter invalidPortsChanged;
1287 public IDebugCounter invalidSwitchActivatedWhileSlave;
1288 public IDebugCounter invalidStoreEventWhileMaster;
1289 public IDebugCounter switchDisconnectedWhileSlave;
1290 public IDebugCounter switchActivated;
1291 public IDebugCounter errorSameSwitchReactivated; // err
1292 public IDebugCounter switchWithSameDpidActivated; // warn
Saurav Dasfcdad072014-08-13 14:15:21 -07001293 public IDebugCounter newSwitchActivated; // new switch
Brian O'Connorc67f9fa2014-08-07 18:17:46 -07001294 public IDebugCounter syncedSwitchActivated;
1295 public IDebugCounter readyForReconcile;
1296 public IDebugCounter newSwitchFromStore;
1297 public IDebugCounter updatedSwitchFromStore;
1298 public IDebugCounter switchDisconnected;
1299 public IDebugCounter syncedSwitchRemoved;
1300 public IDebugCounter unknownSwitchRemovedFromStore;
1301 public IDebugCounter consolidateStoreRunCount;
1302 public IDebugCounter consolidateStoreInconsistencies;
1303 public IDebugCounter storeSyncError;
1304 public IDebugCounter switchesNotReconnectingToNewMaster;
1305 public IDebugCounter switchPortChanged;
1306 public IDebugCounter switchOtherChange;
1307 public IDebugCounter dispatchMessageWhileSlave;
Saurav Dasfcdad072014-08-13 14:15:21 -07001308 public IDebugCounter dispatchMessage; // does this cnt make sense? more
1309 // specific?? per type? count
1310 // stops?
Brian O'Connorc67f9fa2014-08-07 18:17:46 -07001311 public IDebugCounter controllerNodeIpsChanged;
1312 public IDebugCounter messageReceived;
1313 public IDebugCounter messageInputThrottled;
1314 public IDebugCounter switchDisconnectReadTimeout;
1315 public IDebugCounter switchDisconnectHandshakeTimeout;
1316 public IDebugCounter switchDisconnectIOError;
1317 public IDebugCounter switchDisconnectParseError;
1318 public IDebugCounter switchDisconnectSwitchStateException;
1319 public IDebugCounter rejectedExecutionException;
1320 public IDebugCounter switchDisconnectOtherException;
1321 public IDebugCounter switchConnected;
1322 public IDebugCounter unhandledMessage;
1323 public IDebugCounter packetInWhileSwitchIsSlave;
1324 public IDebugCounter epermErrorWhileSwitchIsMaster;
1325 public IDebugCounter roleNotResentBecauseRolePending;
1326 public IDebugCounter roleRequestSent;
1327 public IDebugCounter roleReplyTimeout;
1328 public IDebugCounter roleReplyReceived; // expected RoleReply received
1329 public IDebugCounter roleReplyErrorUnsupported;
1330 public IDebugCounter switchCounterRegistrationFailed;
1331 public IDebugCounter packetParsingError;
1332
1333 void createCounters(IDebugCounterService debugCounters) throws CounterException {
1334 setRoleEqual =
Saurav Dasfcdad072014-08-13 14:15:21 -07001335 debugCounters.registerCounter(
Brian O'Connorc67f9fa2014-08-07 18:17:46 -07001336 prefix, "set-role-equal",
Saurav Dasfcdad072014-08-13 14:15:21 -07001337 "Controller received a role request with role of " +
1338 "EQUAL which is unusual",
Brian O'Connorc67f9fa2014-08-07 18:17:46 -07001339 CounterType.ALWAYS_COUNT);
1340 setSameRole =
Saurav Dasfcdad072014-08-13 14:15:21 -07001341 debugCounters.registerCounter(
Brian O'Connorc67f9fa2014-08-07 18:17:46 -07001342 prefix, "set-same-role",
1343 "Controller received a role request for the same " +
Saurav Dasfcdad072014-08-13 14:15:21 -07001344 "role the controller already had",
Brian O'Connorc67f9fa2014-08-07 18:17:46 -07001345 CounterType.ALWAYS_COUNT,
1346 IDebugCounterService.CTR_MDATA_WARN);
1347
1348 setRoleMaster =
Saurav Dasfcdad072014-08-13 14:15:21 -07001349 debugCounters.registerCounter(
Brian O'Connorc67f9fa2014-08-07 18:17:46 -07001350 prefix, "set-role-master",
1351 "Controller received a role request with role of " +
Saurav Dasfcdad072014-08-13 14:15:21 -07001352 "MASTER. This counter can be at most 1.",
Brian O'Connorc67f9fa2014-08-07 18:17:46 -07001353 CounterType.ALWAYS_COUNT);
1354
1355 remoteStoreNotification =
Saurav Dasfcdad072014-08-13 14:15:21 -07001356 debugCounters.registerCounter(
Brian O'Connorc67f9fa2014-08-07 18:17:46 -07001357 prefix, "remote-store-notification",
1358 "Received a notification from the sync service " +
Saurav Dasfcdad072014-08-13 14:15:21 -07001359 "indicating that switch information has changed",
Brian O'Connorc67f9fa2014-08-07 18:17:46 -07001360 CounterType.ALWAYS_COUNT);
1361
1362 invalidPortsChanged =
Saurav Dasfcdad072014-08-13 14:15:21 -07001363 debugCounters.registerCounter(
Brian O'Connorc67f9fa2014-08-07 18:17:46 -07001364 prefix, "invalid-ports-changed",
1365 "Received an unexpected ports changed " +
Saurav Dasfcdad072014-08-13 14:15:21 -07001366 "notification while the controller was in " +
1367 "SLAVE role.",
Brian O'Connorc67f9fa2014-08-07 18:17:46 -07001368 CounterType.ALWAYS_COUNT,
1369 IDebugCounterService.CTR_MDATA_WARN);
1370
1371 invalidSwitchActivatedWhileSlave =
Saurav Dasfcdad072014-08-13 14:15:21 -07001372 debugCounters.registerCounter(
Brian O'Connorc67f9fa2014-08-07 18:17:46 -07001373 prefix, "invalid-switch-activated-while-slave",
1374 "Received an unexpected switchActivated " +
Saurav Dasfcdad072014-08-13 14:15:21 -07001375 "notification while the controller was in " +
1376 "SLAVE role.",
Brian O'Connorc67f9fa2014-08-07 18:17:46 -07001377 CounterType.ALWAYS_COUNT,
1378 IDebugCounterService.CTR_MDATA_WARN);
1379
1380 invalidStoreEventWhileMaster =
Saurav Dasfcdad072014-08-13 14:15:21 -07001381 debugCounters.registerCounter(
Brian O'Connorc67f9fa2014-08-07 18:17:46 -07001382 prefix, "invalid-store-event-while-master",
1383 "Received an unexpected notification from " +
Saurav Dasfcdad072014-08-13 14:15:21 -07001384 "the sync store while the controller was in " +
1385 "MASTER role.",
Brian O'Connorc67f9fa2014-08-07 18:17:46 -07001386 CounterType.ALWAYS_COUNT,
1387 IDebugCounterService.CTR_MDATA_WARN);
1388
1389 switchDisconnectedWhileSlave =
Saurav Dasfcdad072014-08-13 14:15:21 -07001390 debugCounters.registerCounter(
Brian O'Connorc67f9fa2014-08-07 18:17:46 -07001391 prefix, "switch-disconnected-while-slave",
1392 "A switch disconnected and the controller was " +
Saurav Dasfcdad072014-08-13 14:15:21 -07001393 "in SLAVE role.",
Brian O'Connorc67f9fa2014-08-07 18:17:46 -07001394 CounterType.ALWAYS_COUNT,
1395 IDebugCounterService.CTR_MDATA_WARN);
1396
1397 switchActivated =
Saurav Dasfcdad072014-08-13 14:15:21 -07001398 debugCounters.registerCounter(
Brian O'Connorc67f9fa2014-08-07 18:17:46 -07001399 prefix, "switch-activated",
1400 "A switch connected to this controller is now " +
Saurav Dasfcdad072014-08-13 14:15:21 -07001401 "in MASTER role",
Brian O'Connorc67f9fa2014-08-07 18:17:46 -07001402 CounterType.ALWAYS_COUNT);
1403
1404 errorSameSwitchReactivated = // err
Saurav Dasfcdad072014-08-13 14:15:21 -07001405 debugCounters.registerCounter(
1406 prefix, "error-same-switch-reactivated",
1407 "A switch that was already in active state " +
Brian O'Connorc67f9fa2014-08-07 18:17:46 -07001408 "was activated again. This indicates a " +
1409 "controller defect",
Saurav Dasfcdad072014-08-13 14:15:21 -07001410 CounterType.ALWAYS_COUNT,
1411 IDebugCounterService.CTR_MDATA_ERROR);
Brian O'Connorc67f9fa2014-08-07 18:17:46 -07001412
1413 switchWithSameDpidActivated = // warn
Saurav Dasfcdad072014-08-13 14:15:21 -07001414 debugCounters.registerCounter(
1415 prefix, "switch-with-same-dpid-activated",
1416 "A switch with the same DPID as another switch " +
Brian O'Connorc67f9fa2014-08-07 18:17:46 -07001417 "connected to the controller. This can be " +
1418 "caused by multiple switches configured with " +
1419 "the same DPID or by a switch reconnecting very " +
1420 "quickly.",
Saurav Dasfcdad072014-08-13 14:15:21 -07001421 CounterType.COUNT_ON_DEMAND,
1422 IDebugCounterService.CTR_MDATA_WARN);
Brian O'Connorc67f9fa2014-08-07 18:17:46 -07001423
Saurav Dasfcdad072014-08-13 14:15:21 -07001424 newSwitchActivated = // new switch
1425 debugCounters.registerCounter(
1426 prefix, "new-switch-activated",
1427 "A new switch has completed the handshake as " +
Brian O'Connorc67f9fa2014-08-07 18:17:46 -07001428 "MASTER. The switch was not known to any other " +
1429 "controller in the cluster",
Saurav Dasfcdad072014-08-13 14:15:21 -07001430 CounterType.ALWAYS_COUNT);
Brian O'Connorc67f9fa2014-08-07 18:17:46 -07001431 syncedSwitchActivated =
Saurav Dasfcdad072014-08-13 14:15:21 -07001432 debugCounters.registerCounter(
Brian O'Connorc67f9fa2014-08-07 18:17:46 -07001433 prefix, "synced-switch-activated",
1434 "A switch has completed the handshake as " +
Saurav Dasfcdad072014-08-13 14:15:21 -07001435 "MASTER. The switch was known to another " +
1436 "controller in the cluster",
Brian O'Connorc67f9fa2014-08-07 18:17:46 -07001437 CounterType.ALWAYS_COUNT);
1438
1439 readyForReconcile =
Saurav Dasfcdad072014-08-13 14:15:21 -07001440 debugCounters.registerCounter(
Brian O'Connorc67f9fa2014-08-07 18:17:46 -07001441 prefix, "ready-for-reconcile",
1442 "Controller is ready for flow reconciliation " +
Saurav Dasfcdad072014-08-13 14:15:21 -07001443 "after Slave to Master transition. Either all " +
1444 "previously known switches are now active " +
1445 "or they have timed out and have been removed." +
1446 "This counter will be 0 or 1.",
Brian O'Connorc67f9fa2014-08-07 18:17:46 -07001447 CounterType.ALWAYS_COUNT);
1448
1449 newSwitchFromStore =
Saurav Dasfcdad072014-08-13 14:15:21 -07001450 debugCounters.registerCounter(
Brian O'Connorc67f9fa2014-08-07 18:17:46 -07001451 prefix, "new-switch-from-store",
1452 "A new switch has connected to another " +
Saurav Dasfcdad072014-08-13 14:15:21 -07001453 "another controller in the cluster. This " +
1454 "controller instance has received a sync store " +
1455 "notification for it.",
Brian O'Connorc67f9fa2014-08-07 18:17:46 -07001456 CounterType.ALWAYS_COUNT);
1457
1458 updatedSwitchFromStore =
Saurav Dasfcdad072014-08-13 14:15:21 -07001459 debugCounters.registerCounter(
Brian O'Connorc67f9fa2014-08-07 18:17:46 -07001460 prefix, "updated-switch-from-store",
1461 "Information about a switch connected to " +
Saurav Dasfcdad072014-08-13 14:15:21 -07001462 "another controller instance was updated in " +
1463 "the sync store. This controller instance has " +
1464 "received a notification for it",
Brian O'Connorc67f9fa2014-08-07 18:17:46 -07001465 CounterType.ALWAYS_COUNT);
1466
1467 switchDisconnected =
Saurav Dasfcdad072014-08-13 14:15:21 -07001468 debugCounters.registerCounter(
Brian O'Connorc67f9fa2014-08-07 18:17:46 -07001469 prefix, "switch-disconnected",
1470 "FIXME: switch has disconnected",
1471 CounterType.ALWAYS_COUNT);
1472
1473 syncedSwitchRemoved =
Saurav Dasfcdad072014-08-13 14:15:21 -07001474 debugCounters.registerCounter(
Brian O'Connorc67f9fa2014-08-07 18:17:46 -07001475 prefix, "synced-switch-removed",
1476 "A switch connected to another controller " +
Saurav Dasfcdad072014-08-13 14:15:21 -07001477 "instance has disconnected from the controller " +
1478 "cluster. This controller instance has " +
1479 "received a notification for it",
Brian O'Connorc67f9fa2014-08-07 18:17:46 -07001480 CounterType.ALWAYS_COUNT);
1481
1482 unknownSwitchRemovedFromStore =
Saurav Dasfcdad072014-08-13 14:15:21 -07001483 debugCounters.registerCounter(
Brian O'Connorc67f9fa2014-08-07 18:17:46 -07001484 prefix, "unknown-switch-removed-from-store",
1485 "This controller instances has received a sync " +
Saurav Dasfcdad072014-08-13 14:15:21 -07001486 "store notification that a switch has " +
1487 "disconnected but this controller instance " +
1488 "did not have the any information about the " +
1489 "switch", // might be less than warning
Brian O'Connorc67f9fa2014-08-07 18:17:46 -07001490 CounterType.ALWAYS_COUNT,
1491 IDebugCounterService.CTR_MDATA_WARN);
1492
1493 consolidateStoreRunCount =
Saurav Dasfcdad072014-08-13 14:15:21 -07001494 debugCounters.registerCounter(
Brian O'Connorc67f9fa2014-08-07 18:17:46 -07001495 prefix, "consolidate-store-run-count",
1496 "This controller has transitioned from SLAVE " +
Saurav Dasfcdad072014-08-13 14:15:21 -07001497 "to MASTER and waited for switches to reconnect. " +
1498 "The controller has finished waiting and has " +
1499 "reconciled switch entries in the sync store " +
1500 "with live state",
Brian O'Connorc67f9fa2014-08-07 18:17:46 -07001501 CounterType.ALWAYS_COUNT);
1502
1503 consolidateStoreInconsistencies =
1504 debugCounters.registerCounter(
Saurav Dasfcdad072014-08-13 14:15:21 -07001505 prefix, "consolidate-store-inconsistencies",
1506 "During switch sync store consolidation: " +
1507 "Number of switches that were in the store " +
1508 "but not otherwise known plus number of " +
1509 "switches that were in the store previously " +
1510 "but are now missing plus number of " +
1511 "connected switches that were absent from " +
1512 "the store although this controller has " +
1513 "written them. A non-zero count " +
1514 "indicates a brief split-brain dual MASTER " +
1515 "situation during fail-over",
1516 CounterType.ALWAYS_COUNT);
Brian O'Connorc67f9fa2014-08-07 18:17:46 -07001517
1518 storeSyncError =
Saurav Dasfcdad072014-08-13 14:15:21 -07001519 debugCounters.registerCounter(
Brian O'Connorc67f9fa2014-08-07 18:17:46 -07001520 prefix, "store-sync-error",
1521 "Number of times a sync store operation failed " +
Saurav Dasfcdad072014-08-13 14:15:21 -07001522 "due to a store sync exception or an entry in " +
1523 "in the store had invalid data.",
Brian O'Connorc67f9fa2014-08-07 18:17:46 -07001524 CounterType.ALWAYS_COUNT,
1525 IDebugCounterService.CTR_MDATA_ERROR);
1526
1527 switchesNotReconnectingToNewMaster =
Saurav Dasfcdad072014-08-13 14:15:21 -07001528 debugCounters.registerCounter(
Brian O'Connorc67f9fa2014-08-07 18:17:46 -07001529 prefix, "switches-not-reconnecting-to-new-master",
1530 "Switches that were connected to another " +
Saurav Dasfcdad072014-08-13 14:15:21 -07001531 "controller instance in the cluster but that " +
1532 "did not reconnect to this controller after it " +
1533 "transitioned to MASTER", // might be less
1534 // than warning
Brian O'Connorc67f9fa2014-08-07 18:17:46 -07001535 CounterType.ALWAYS_COUNT);
1536
1537 switchPortChanged =
Saurav Dasfcdad072014-08-13 14:15:21 -07001538 debugCounters.registerCounter(
Brian O'Connorc67f9fa2014-08-07 18:17:46 -07001539 prefix, "switch-port-changed",
1540 "Number of times switch ports have changed",
1541 CounterType.ALWAYS_COUNT);
1542 switchOtherChange =
Saurav Dasfcdad072014-08-13 14:15:21 -07001543 debugCounters.registerCounter(
Brian O'Connorc67f9fa2014-08-07 18:17:46 -07001544 prefix, "switch-other-change",
1545 "Number of times other information of a switch " +
Saurav Dasfcdad072014-08-13 14:15:21 -07001546 "has changed.",
Brian O'Connorc67f9fa2014-08-07 18:17:46 -07001547 CounterType.ALWAYS_COUNT);
1548
1549 dispatchMessageWhileSlave =
Saurav Dasfcdad072014-08-13 14:15:21 -07001550 debugCounters.registerCounter(
Brian O'Connorc67f9fa2014-08-07 18:17:46 -07001551 prefix, "dispatch-message-while-slave",
1552 "Number of times an OF message was received " +
Saurav Dasfcdad072014-08-13 14:15:21 -07001553 "and supposed to be dispatched but the " +
1554 "controller was in SLAVE role and the message " +
1555 "was not dispatched",
Brian O'Connorc67f9fa2014-08-07 18:17:46 -07001556 CounterType.ALWAYS_COUNT);
1557
Saurav Dasfcdad072014-08-13 14:15:21 -07001558 dispatchMessage = // does this cnt make sense? more specific?? per
1559 // type? count stops?
1560 debugCounters.registerCounter(
1561 prefix, "dispatch-message",
1562 "Number of times an OF message was dispatched " +
Brian O'Connorc67f9fa2014-08-07 18:17:46 -07001563 "to registered modules",
Saurav Dasfcdad072014-08-13 14:15:21 -07001564 CounterType.ALWAYS_COUNT);
Brian O'Connorc67f9fa2014-08-07 18:17:46 -07001565
1566 controllerNodeIpsChanged =
Saurav Dasfcdad072014-08-13 14:15:21 -07001567 debugCounters.registerCounter(
Brian O'Connorc67f9fa2014-08-07 18:17:46 -07001568 prefix, "controller-nodes-ips-changed",
1569 "IP addresses of controller nodes have changed",
1570 CounterType.ALWAYS_COUNT);
1571
Saurav Dasfcdad072014-08-13 14:15:21 -07001572 // ------------------------
1573 // channel handler counters. Factor them out ??
Brian O'Connorc67f9fa2014-08-07 18:17:46 -07001574 messageReceived =
Saurav Dasfcdad072014-08-13 14:15:21 -07001575 debugCounters.registerCounter(
Brian O'Connorc67f9fa2014-08-07 18:17:46 -07001576 prefix, "message-received",
1577 "Number of OpenFlow messages received. Some of " +
Saurav Dasfcdad072014-08-13 14:15:21 -07001578 "these might be throttled",
Brian O'Connorc67f9fa2014-08-07 18:17:46 -07001579 CounterType.ALWAYS_COUNT);
1580 messageInputThrottled =
Saurav Dasfcdad072014-08-13 14:15:21 -07001581 debugCounters.registerCounter(
Brian O'Connorc67f9fa2014-08-07 18:17:46 -07001582 prefix, "message-input-throttled",
1583 "Number of OpenFlow messages that were " +
Saurav Dasfcdad072014-08-13 14:15:21 -07001584 "throttled due to high load from the sender",
Brian O'Connorc67f9fa2014-08-07 18:17:46 -07001585 CounterType.ALWAYS_COUNT,
1586 IDebugCounterService.CTR_MDATA_WARN);
Saurav Dasfcdad072014-08-13 14:15:21 -07001587 // TODO: more counters in messageReceived ??
Brian O'Connorc67f9fa2014-08-07 18:17:46 -07001588
1589 switchDisconnectReadTimeout =
Saurav Dasfcdad072014-08-13 14:15:21 -07001590 debugCounters.registerCounter(
Brian O'Connorc67f9fa2014-08-07 18:17:46 -07001591 prefix, "switch-disconnect-read-timeout",
1592 "Number of times a switch was disconnected due " +
Saurav Dasfcdad072014-08-13 14:15:21 -07001593 "due the switch failing to send OpenFlow " +
1594 "messages or responding to OpenFlow ECHOs",
Brian O'Connorc67f9fa2014-08-07 18:17:46 -07001595 CounterType.ALWAYS_COUNT,
1596 IDebugCounterService.CTR_MDATA_ERROR);
1597 switchDisconnectHandshakeTimeout =
Saurav Dasfcdad072014-08-13 14:15:21 -07001598 debugCounters.registerCounter(
Brian O'Connorc67f9fa2014-08-07 18:17:46 -07001599 prefix, "switch-disconnect-handshake-timeout",
1600 "Number of times a switch was disconnected " +
Saurav Dasfcdad072014-08-13 14:15:21 -07001601 "because it failed to complete the handshake " +
1602 "in time.",
Brian O'Connorc67f9fa2014-08-07 18:17:46 -07001603 CounterType.ALWAYS_COUNT,
1604 IDebugCounterService.CTR_MDATA_ERROR);
1605 switchDisconnectIOError =
Saurav Dasfcdad072014-08-13 14:15:21 -07001606 debugCounters.registerCounter(
Brian O'Connorc67f9fa2014-08-07 18:17:46 -07001607 prefix, "switch-disconnect-io-error",
1608 "Number of times a switch was disconnected " +
Saurav Dasfcdad072014-08-13 14:15:21 -07001609 "due to IO errors on the switch connection.",
Brian O'Connorc67f9fa2014-08-07 18:17:46 -07001610 CounterType.ALWAYS_COUNT,
1611 IDebugCounterService.CTR_MDATA_ERROR);
1612 switchDisconnectParseError =
Saurav Dasfcdad072014-08-13 14:15:21 -07001613 debugCounters.registerCounter(
Brian O'Connorc67f9fa2014-08-07 18:17:46 -07001614 prefix, "switch-disconnect-parse-error",
Saurav Dasfcdad072014-08-13 14:15:21 -07001615 "Number of times a switch was disconnected " +
1616 "because it sent an invalid packet that could " +
1617 "not be parsed",
1618 CounterType.ALWAYS_COUNT,
1619 IDebugCounterService.CTR_MDATA_ERROR);
Brian O'Connorc67f9fa2014-08-07 18:17:46 -07001620
1621 switchDisconnectSwitchStateException =
Saurav Dasfcdad072014-08-13 14:15:21 -07001622 debugCounters.registerCounter(
Brian O'Connorc67f9fa2014-08-07 18:17:46 -07001623 prefix, "switch-disconnect-switch-state-exception",
1624 "Number of times a switch was disconnected " +
Saurav Dasfcdad072014-08-13 14:15:21 -07001625 "because it sent messages that were invalid " +
1626 "given the switch connection's state.",
Brian O'Connorc67f9fa2014-08-07 18:17:46 -07001627 CounterType.ALWAYS_COUNT,
1628 IDebugCounterService.CTR_MDATA_ERROR);
1629 rejectedExecutionException =
Saurav Dasfcdad072014-08-13 14:15:21 -07001630 debugCounters.registerCounter(
Brian O'Connorc67f9fa2014-08-07 18:17:46 -07001631 prefix, "rejected-execution-exception",
1632 "TODO",
1633 CounterType.ALWAYS_COUNT,
1634 IDebugCounterService.CTR_MDATA_ERROR);
1635
1636 switchDisconnectOtherException =
Saurav Dasfcdad072014-08-13 14:15:21 -07001637 debugCounters.registerCounter(
1638 prefix, "switch-disconnect-other-exception",
Brian O'Connorc67f9fa2014-08-07 18:17:46 -07001639 "Number of times a switch was disconnected " +
Saurav Dasfcdad072014-08-13 14:15:21 -07001640 "due to an exceptional situation not covered " +
1641 "by other counters",
Brian O'Connorc67f9fa2014-08-07 18:17:46 -07001642 CounterType.ALWAYS_COUNT,
1643 IDebugCounterService.CTR_MDATA_ERROR);
1644
1645 switchConnected =
Saurav Dasfcdad072014-08-13 14:15:21 -07001646 debugCounters.registerCounter(
Brian O'Connorc67f9fa2014-08-07 18:17:46 -07001647 prefix, "switch-connected",
1648 "Number of times a new switch connection was " +
Saurav Dasfcdad072014-08-13 14:15:21 -07001649 "established",
Brian O'Connorc67f9fa2014-08-07 18:17:46 -07001650 CounterType.ALWAYS_COUNT);
1651
1652 unhandledMessage =
Saurav Dasfcdad072014-08-13 14:15:21 -07001653 debugCounters.registerCounter(
Brian O'Connorc67f9fa2014-08-07 18:17:46 -07001654 prefix, "unhandled-message",
1655 "Number of times an OpenFlow message was " +
Saurav Dasfcdad072014-08-13 14:15:21 -07001656 "received that the controller ignored because " +
1657 "it was inapproriate given the switch " +
1658 "connection's state.",
Brian O'Connorc67f9fa2014-08-07 18:17:46 -07001659 CounterType.ALWAYS_COUNT,
1660 IDebugCounterService.CTR_MDATA_WARN);
Saurav Dasfcdad072014-08-13 14:15:21 -07001661 // might be less than warning
Brian O'Connorc67f9fa2014-08-07 18:17:46 -07001662
1663 packetInWhileSwitchIsSlave =
Saurav Dasfcdad072014-08-13 14:15:21 -07001664 debugCounters.registerCounter(
Brian O'Connorc67f9fa2014-08-07 18:17:46 -07001665 prefix, "packet-in-while-switch-is-slave",
1666 "Number of times a packet in was received " +
Saurav Dasfcdad072014-08-13 14:15:21 -07001667 "from a switch that was in SLAVE role. " +
1668 "Possibly inidicates inconsistent roles.",
Brian O'Connorc67f9fa2014-08-07 18:17:46 -07001669 CounterType.ALWAYS_COUNT);
1670 epermErrorWhileSwitchIsMaster =
Saurav Dasfcdad072014-08-13 14:15:21 -07001671 debugCounters.registerCounter(
Brian O'Connorc67f9fa2014-08-07 18:17:46 -07001672 prefix, "eperm-error-while-switch-is-master",
1673 "Number of times a permission error was " +
Saurav Dasfcdad072014-08-13 14:15:21 -07001674 "received while the switch was in MASTER role. " +
1675 "Possibly inidicates inconsistent roles.",
Brian O'Connorc67f9fa2014-08-07 18:17:46 -07001676 CounterType.ALWAYS_COUNT,
1677 IDebugCounterService.CTR_MDATA_WARN);
1678
1679 roleNotResentBecauseRolePending =
Saurav Dasfcdad072014-08-13 14:15:21 -07001680 debugCounters.registerCounter(
Brian O'Connorc67f9fa2014-08-07 18:17:46 -07001681 prefix, "role-not-resent-because-role-pending",
1682 "The controller tried to reestablish a role " +
Saurav Dasfcdad072014-08-13 14:15:21 -07001683 "with a switch but did not do so because a " +
1684 "previous role request was still pending",
Brian O'Connorc67f9fa2014-08-07 18:17:46 -07001685 CounterType.ALWAYS_COUNT);
1686 roleRequestSent =
Saurav Dasfcdad072014-08-13 14:15:21 -07001687 debugCounters.registerCounter(
Brian O'Connorc67f9fa2014-08-07 18:17:46 -07001688 prefix, "role-request-sent",
1689 "Number of times the controller sent a role " +
Saurav Dasfcdad072014-08-13 14:15:21 -07001690 "request to a switch.",
Brian O'Connorc67f9fa2014-08-07 18:17:46 -07001691 CounterType.ALWAYS_COUNT);
1692 roleReplyTimeout =
Saurav Dasfcdad072014-08-13 14:15:21 -07001693 debugCounters.registerCounter(
Brian O'Connorc67f9fa2014-08-07 18:17:46 -07001694 prefix, "role-reply-timeout",
1695 "Number of times a role request message did not " +
Saurav Dasfcdad072014-08-13 14:15:21 -07001696 "receive the expected reply from a switch",
Brian O'Connorc67f9fa2014-08-07 18:17:46 -07001697 CounterType.ALWAYS_COUNT,
1698 IDebugCounterService.CTR_MDATA_WARN);
1699
1700 roleReplyReceived = // expected RoleReply received
Saurav Dasfcdad072014-08-13 14:15:21 -07001701 debugCounters.registerCounter(
1702 prefix, "role-reply-received",
1703 "Number of times the controller received the " +
Brian O'Connorc67f9fa2014-08-07 18:17:46 -07001704 "expected role reply message from a switch",
Saurav Dasfcdad072014-08-13 14:15:21 -07001705 CounterType.ALWAYS_COUNT);
Brian O'Connorc67f9fa2014-08-07 18:17:46 -07001706
1707 roleReplyErrorUnsupported =
Saurav Dasfcdad072014-08-13 14:15:21 -07001708 debugCounters.registerCounter(
Brian O'Connorc67f9fa2014-08-07 18:17:46 -07001709 prefix, "role-reply-error-unsupported",
1710 "Number of times the controller received an " +
Saurav Dasfcdad072014-08-13 14:15:21 -07001711 "error from a switch in response to a role " +
1712 "request indicating that the switch does not " +
1713 "support roles.",
Brian O'Connorc67f9fa2014-08-07 18:17:46 -07001714 CounterType.ALWAYS_COUNT);
1715
1716 switchCounterRegistrationFailed =
1717 debugCounters.registerCounter(prefix,
Saurav Dasfcdad072014-08-13 14:15:21 -07001718 "switch-counter-registration-failed",
1719 "Number of times the controller failed to " +
1720 "register per-switch debug counters",
1721 CounterType.ALWAYS_COUNT,
1722 IDebugCounterService.CTR_MDATA_WARN);
Brian O'Connorc67f9fa2014-08-07 18:17:46 -07001723
1724 packetParsingError =
1725 debugCounters.registerCounter(prefix,
Saurav Dasfcdad072014-08-13 14:15:21 -07001726 "packet-parsing-error",
1727 "Number of times the packet parsing " +
1728 "encountered an error",
1729 CounterType.ALWAYS_COUNT,
1730 IDebugCounterService.CTR_MDATA_ERROR);
Brian O'Connorc67f9fa2014-08-07 18:17:46 -07001731 }
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -08001732 }
1733
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -08001734 @Override
Brian O'Connorc67f9fa2014-08-07 18:17:46 -07001735 public Counters getCounters() {
1736 return this.counters;
1737 }
1738
1739 // **************
1740 // debugEvent registrations
1741 // **************
1742
1743 private void registerControllerDebugEvents() throws FloodlightModuleException {
1744 if (debugEvents == null) {
1745 debugEvents = new NullDebugEvent();
1746 }
1747 try {
1748 evSwitch = debugEvents.registerEvent(
Saurav Dasfcdad072014-08-13 14:15:21 -07001749 Counters.prefix, "switchevent",
1750 "Switch connected, disconnected or port changed",
1751 EventType.ALWAYS_LOG, SwitchEvent.class, 100);
Brian O'Connorc67f9fa2014-08-07 18:17:46 -07001752 } catch (MaxEventsRegistered e) {
1753 throw new FloodlightModuleException("Max events registered", e);
1754 }
1755 }
1756
1757 public class SwitchEvent {
1758 @EventColumn(name = "dpid", description = EventFieldType.DPID)
1759 long dpid;
1760
1761 @EventColumn(name = "reason", description = EventFieldType.STRING)
1762 String reason;
1763
1764 public SwitchEvent(long dpid, String reason) {
1765 this.dpid = dpid;
1766 this.reason = reason;
1767 }
1768 }
1769
1770 // **************
1771 // Utility methods
1772 // **************
1773
1774 @Override
1775 public void setAlwaysClearFlowsOnSwActivate(boolean value) {
Saurav Dasfcdad072014-08-13 14:15:21 -07001776 // this.alwaysClearFlowsOnSwActivate = value;
Brian O'Connorc67f9fa2014-08-07 18:17:46 -07001777 // XXX S need to be a little more careful about this
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -08001778 }
1779
1780 @Override
Brian O'Connorc67f9fa2014-08-07 18:17:46 -07001781 public Map<String, Long> getMemory() {
1782 Map<String, Long> m = new HashMap<String, Long>();
1783 Runtime runtime = Runtime.getRuntime();
1784 m.put("total", runtime.totalMemory());
1785 m.put("free", runtime.freeMemory());
1786 return m;
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -08001787 }
Ray Milkey269ffb92014-04-03 14:43:30 -07001788
Brian O'Connorc67f9fa2014-08-07 18:17:46 -07001789 @Override
1790 public Long getUptime() {
1791 RuntimeMXBean rb = ManagementFactory.getRuntimeMXBean();
1792 return rb.getUptime();
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -08001793 }
Brian O'Connorc67f9fa2014-08-07 18:17:46 -07001794
1795 /**
1796 * Forward to the driver-manager to get an IOFSwitch instance.
Jonathan Hartcb34f382014-08-12 21:11:03 -07001797 *
Brian O'Connorc67f9fa2014-08-07 18:17:46 -07001798 * @param desc
1799 * @return
1800 */
1801 protected IOFSwitch getOFSwitchInstance(OFDescStatsReply desc, OFVersion ofv) {
1802 return DriverManager.getOFSwitchImpl(desc, ofv);
1803 }
1804
1805 protected IThreadPoolService getThreadPoolService() {
1806 return this.threadPool;
1807 }
1808
1809 /**
Saurav Dasfcdad072014-08-13 14:15:21 -07001810 * Part of the controller updates framework (see 'run()' method) Use this
1811 * method to add an IUpdate. A thread-pool will serve the update by
1812 * dispatching it to all listeners for that update.
Jonathan Hartcb34f382014-08-12 21:11:03 -07001813 *
Brian O'Connorc67f9fa2014-08-07 18:17:46 -07001814 * @param update
1815 */
Saurav Dasfcdad072014-08-13 14:15:21 -07001816 @LogMessageDoc(level = "WARN",
1817 message = "Failure adding update {} to queue",
1818 explanation = "The controller tried to add an internal notification" +
1819 " to its message queue but the add failed.",
1820 recommendation = LogMessageDoc.REPORT_CONTROLLER_BUG)
Brian O'Connorc67f9fa2014-08-07 18:17:46 -07001821 private void addUpdateToQueue(IUpdate update) {
1822 try {
1823 this.updates.put(update);
1824 } catch (InterruptedException e) {
1825 // This should never happen
1826 log.error("Failure adding update {} to queue.", update);
1827 }
1828 }
1829
1830 void flushAll() {
1831 // Flush all flow-mods/packet-out/stats generated from this "train"
1832 OFSwitchImplBase.flush_all();
1833 debugCounters.flushCounters();
1834 debugEvents.flushEvents();
1835 }
1836
1837 /**
1838 * flcontext_free - Free the context to the current thread
Jonathan Hartcb34f382014-08-12 21:11:03 -07001839 *
Brian O'Connorc67f9fa2014-08-07 18:17:46 -07001840 * @param flcontext
1841 */
1842 protected void flcontext_free(FloodlightContext flcontext) {
1843 flcontext.getStorage().clear();
1844 flcontext_cache.get().push(flcontext);
1845 }
1846
1847 @LogMessageDoc(message = "Calling System.exit",
1848 explanation = "The controller is terminating")
1849 private synchronized void terminate() {
1850 log.info("Calling System.exit");
1851 System.exit(1);
1852 }
1853
Brian O'Connorc67f9fa2014-08-07 18:17:46 -07001854 // ***************
1855 // Floodlight context related
1856 // ***************
1857
1858 /**
1859 * flcontext_cache - Keep a thread local stack of contexts
1860 */
1861 protected static final ThreadLocal<Stack<FloodlightContext>> flcontext_cache =
1862 new ThreadLocal<Stack<FloodlightContext>>() {
1863 @Override
1864 protected Stack<FloodlightContext> initialValue() {
1865 return new Stack<FloodlightContext>();
1866 }
1867 };
1868
1869 /**
Saurav Dasfcdad072014-08-13 14:15:21 -07001870 * flcontext_alloc - pop a context off the stack, if required create a new
1871 * one
Jonathan Hartcb34f382014-08-12 21:11:03 -07001872 *
Brian O'Connorc67f9fa2014-08-07 18:17:46 -07001873 * @return FloodlightContext
1874 */
1875 protected static FloodlightContext flcontext_alloc() {
1876 FloodlightContext flcontext = null;
1877
1878 if (flcontext_cache.get().empty()) {
1879 flcontext = new FloodlightContext();
1880 } else {
1881 flcontext = flcontext_cache.get().pop();
1882 }
1883
1884 return flcontext;
1885 }
1886
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -08001887}