blob: 2152875b0f54d619747379ba9a680d28d7537ccc [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;
71import net.onrc.onos.core.drivermanager.DriverManager;
Jonathan Hart23701d12014-04-03 10:45:48 -070072import net.onrc.onos.core.linkdiscovery.ILinkDiscoveryService;
Jonathan Hartdeda0ba2014-04-03 11:14:12 -070073import net.onrc.onos.core.packet.Ethernet;
74import net.onrc.onos.core.registry.IControllerRegistryService;
Jonathan Hartdeda0ba2014-04-03 11:14:12 -070075import net.onrc.onos.core.registry.IControllerRegistryService.ControlChangeCallback;
Jonathan Harta99ec672014-04-03 11:30:34 -070076import net.onrc.onos.core.registry.RegistryException;
Pavlin Radoslavov695f8952014-07-23 16:57:01 -070077import net.onrc.onos.core.util.Dpid;
Pavlin Radoslavov53b208a2014-07-28 13:16:11 -070078import net.onrc.onos.core.util.OnosInstanceId;
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -080079
80import org.jboss.netty.bootstrap.ServerBootstrap;
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -080081import org.jboss.netty.channel.ChannelPipelineFactory;
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -080082import org.jboss.netty.channel.group.ChannelGroup;
83import org.jboss.netty.channel.group.DefaultChannelGroup;
84import org.jboss.netty.channel.socket.nio.NioServerSocketChannelFactory;
Brian O'Connorc67f9fa2014-08-07 18:17:46 -070085import org.projectfloodlight.openflow.protocol.OFDescStatsReply;
86import org.projectfloodlight.openflow.protocol.OFFactories;
87import org.projectfloodlight.openflow.protocol.OFFactory;
88import org.projectfloodlight.openflow.protocol.OFMessage;
89import org.projectfloodlight.openflow.protocol.OFPacketIn;
90import org.projectfloodlight.openflow.protocol.OFPortDesc;
91import org.projectfloodlight.openflow.protocol.OFType;
92import org.projectfloodlight.openflow.protocol.OFVersion;
93import org.projectfloodlight.openflow.protocol.match.MatchField;
94import org.projectfloodlight.openflow.protocol.match.MatchFields;
95import org.projectfloodlight.openflow.types.EthType;
96import org.projectfloodlight.openflow.types.OFPort;
97import org.projectfloodlight.openflow.util.HexString;
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -080098import org.slf4j.Logger;
99import org.slf4j.LoggerFactory;
100
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -0800101/**
Saurav Dasfcdad072014-08-13 14:15:21 -0700102 * The main controller class. Handles all setup and network listeners -
103 * Distributed ownership control of switch through IControllerRegistryService
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -0800104 */
Jonathan Hart2fa28062013-11-25 20:16:28 -0800105public class Controller implements IFloodlightProviderService {
Ray Milkey269ffb92014-04-03 14:43:30 -0700106
Yuta HIGUCHI6ac8d182013-10-22 15:24:56 -0700107 protected final static Logger log = LoggerFactory.getLogger(Controller.class);
Brian O'Connorc67f9fa2014-08-07 18:17:46 -0700108 static final String ERROR_DATABASE =
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -0800109 "The controller could not communicate with the system database.";
Brian O'Connorc67f9fa2014-08-07 18:17:46 -0700110 protected static OFFactory factory13 = OFFactories.getFactory(OFVersion.OF_13);
111 protected static OFFactory factory10 = OFFactories.getFactory(OFVersion.OF_10);
Ray Milkey269ffb92014-04-03 14:43:30 -0700112
Brian O'Connorc67f9fa2014-08-07 18:17:46 -0700113 // connectedSwitches cache contains all connected switch's channelHandlers
114 // including ones where this controller is a master/equal/slave controller
115 // as well as ones that have not been activated yet
116 protected ConcurrentHashMap<Long, OFChannelHandler> connectedSwitches;
117 // These caches contains only those switches that are active
118 protected ConcurrentHashMap<Long, IOFSwitch> activeMasterSwitches;
119 protected ConcurrentHashMap<Long, IOFSwitch> activeEqualSwitches;
120 // lock to synchronize on, when manipulating multiple caches above
121 private Object multiCacheLock;
Ray Milkey269ffb92014-04-03 14:43:30 -0700122
Brian O'Connorc67f9fa2014-08-07 18:17:46 -0700123 // The controllerNodeIPsCache maps Controller IDs to their IP address.
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -0800124 // It's only used by handleControllerNodeIPsChanged
125 protected HashMap<String, String> controllerNodeIPsCache;
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -0800126 protected BlockingQueue<IUpdate> updates;
Ray Milkey269ffb92014-04-03 14:43:30 -0700127
Saurav Dasfcdad072014-08-13 14:15:21 -0700128 protected ConcurrentMap<OFType, ListenerDispatcher<OFType, IOFMessageListener>> messageListeners;
Brian O'Connorc67f9fa2014-08-07 18:17:46 -0700129 protected Set<IOFSwitchListener> switchListeners;
Pavlin Radoslavov695f8952014-07-23 16:57:01 -0700130
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -0800131 // Module dependencies
132 protected IRestApiService restApi;
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -0800133 protected IThreadPoolService threadPool;
Jonathan Hartd10008d2013-02-23 17:04:08 -0800134 protected IControllerRegistryService registryService;
Brian O'Connorc67f9fa2014-08-07 18:17:46 -0700135 protected IDebugCounterService debugCounters;
136 protected IDebugEventService debugEvents;
Ray Milkey269ffb92014-04-03 14:43:30 -0700137
Jonathan Hart8a5d0972013-12-04 10:02:44 -0800138 protected ILinkDiscoveryService linkDiscovery;
Ray Milkey269ffb92014-04-03 14:43:30 -0700139
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -0800140 // Configuration options
141 protected int openFlowPort = 6633;
142 protected int workerThreads = 0;
Brian O'Connorc67f9fa2014-08-07 18:17:46 -0700143
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -0800144 // The id for this controller node. Should be unique for each controller
145 // node in a controller cluster.
Pavlin Radoslavov53b208a2014-07-28 13:16:11 -0700146 private OnosInstanceId onosInstanceId = new OnosInstanceId("localhost");
Ray Milkey269ffb92014-04-03 14:43:30 -0700147
Brian O'Connorc67f9fa2014-08-07 18:17:46 -0700148 // defined counters
149 private Counters counters;
150 // Event IDs for debug events
151 protected IEventUpdater<SwitchEvent> evSwitch;
152
153 // Load monitor for overload protection
154 protected final boolean overload_drop =
Saurav Dasfcdad072014-08-13 14:15:21 -0700155 Boolean.parseBoolean(System.getProperty("overload_drop", "false"));
Brian O'Connorc67f9fa2014-08-07 18:17:46 -0700156 protected final LoadMonitor loadmonitor = new LoadMonitor(log);
Ray Milkey269ffb92014-04-03 14:43:30 -0700157
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -0800158 // Start time of the controller
159 protected long systemStartTime;
Ray Milkey269ffb92014-04-03 14:43:30 -0700160
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -0800161 // Flag to always flush flow table on switch reconnect (HA or otherwise)
162 protected boolean alwaysClearFlowsOnSwAdd = false;
Ray Milkey269ffb92014-04-03 14:43:30 -0700163
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -0800164 // Perf. related configuration
165 protected static final int SEND_BUFFER_SIZE = 4 * 1024 * 1024;
166 protected static final int BATCH_MAX_SIZE = 100;
Ray Milkey269ffb92014-04-03 14:43:30 -0700167 protected static final boolean ALWAYS_DECODE_ETH = true;
168
Brian O'Connorc67f9fa2014-08-07 18:17:46 -0700169 // ******************************
170 // Switch Management and Updates
171 // ******************************
172
173 /**
Saurav Dasfcdad072014-08-13 14:15:21 -0700174 * Switch updates are sent to all IOFSwitchListeners. A switch that is
175 * connected to this controller instance, but not activated, is not
176 * available for updates.
Jonathan Hartcb34f382014-08-12 21:11:03 -0700177 *
Saurav Dasfcdad072014-08-13 14:15:21 -0700178 * In ONOS, each controller instance can simultaneously serve in a MASTER
179 * role for some connected switches, and in a EQUAL role for other connected
180 * switches. The EQUAL role can be treated as a SLAVE role, by ensuring that
181 * the controller instance never sends packets or commands out to the
182 * switch. Activated switches, either with Controller Role MASTER or EQUAL
183 * are announced as updates. We also support announcements of controller
184 * role transitions from MASTER --> EQUAL, and EQUAL --> MASTER, for an
185 * individual switch.
Jonathan Hartcb34f382014-08-12 21:11:03 -0700186 *
Brian O'Connorc67f9fa2014-08-07 18:17:46 -0700187 * Disconnection of only activated switches are announced. Finally, changes
188 * to switch ports are announced with a portChangeType (see @IOFSwitch)
Jonathan Hartcb34f382014-08-12 21:11:03 -0700189 *
Brian O'Connorc67f9fa2014-08-07 18:17:46 -0700190 * @author saurav
191 */
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -0800192 public enum SwitchUpdateType {
Brian O'Connorc67f9fa2014-08-07 18:17:46 -0700193 /** switch activated with this controller's role as MASTER */
194 ACTIVATED_MASTER,
Saurav Dasfcdad072014-08-13 14:15:21 -0700195 /**
196 * switch activated with this controller's role as EQUAL. listener can
197 * treat this controller's role as SLAVE by not sending packets or
198 * commands to the switch
199 */
Brian O'Connorc67f9fa2014-08-07 18:17:46 -0700200 ACTIVATED_EQUAL,
201 /** this controller's role for this switch changed from Master to Equal */
202 MASTER_TO_EQUAL,
203 /** this controller's role for this switch changed form Equal to Master */
204 EQUAL_TO_MASTER,
205 /** A previously activated switch disconnected */
206 DISCONNECTED,
207 /** Port changed on a previously activated switch */
Pankaj Berde465ac7c2013-05-23 13:47:49 -0700208 PORTCHANGED,
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -0800209 }
Ray Milkey269ffb92014-04-03 14:43:30 -0700210
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -0800211 /**
Saurav Dasfcdad072014-08-13 14:15:21 -0700212 * Update message indicating a switch was added or removed ONOS: This
213 * message extended to indicate Port add or removed event.
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -0800214 */
215 protected class SwitchUpdate implements IUpdate {
Brian O'Connorc67f9fa2014-08-07 18:17:46 -0700216 public long getSwId() {
217 return swId;
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -0800218 }
Ray Milkey269ffb92014-04-03 14:43:30 -0700219
Brian O'Connorc67f9fa2014-08-07 18:17:46 -0700220 public SwitchUpdateType getSwitchUpdateType() {
221 return switchUpdateType;
222 }
223
224 public PortChangeType getPortChangeType() {
225 return changeType;
226 }
227
228 private final long swId;
229 private final SwitchUpdateType switchUpdateType;
230 private final OFPortDesc port;
231 private final PortChangeType changeType;
232
233 public SwitchUpdate(long swId, SwitchUpdateType switchUpdateType) {
234 this(swId, switchUpdateType, null, null);
235 }
Saurav Dasfcdad072014-08-13 14:15:21 -0700236
Brian O'Connorc67f9fa2014-08-07 18:17:46 -0700237 public SwitchUpdate(long swId,
Saurav Dasfcdad072014-08-13 14:15:21 -0700238 SwitchUpdateType switchUpdateType,
239 OFPortDesc port,
240 PortChangeType changeType) {
Brian O'Connorc67f9fa2014-08-07 18:17:46 -0700241 if (switchUpdateType == SwitchUpdateType.PORTCHANGED) {
242 if (port == null) {
243 throw new NullPointerException("Port must not be null " +
244 "for PORTCHANGED updates");
245 }
246 if (changeType == null) {
247 throw new NullPointerException("ChangeType must not be " +
248 "null for PORTCHANGED updates");
249 }
250 } else {
251 if (port != null || changeType != null) {
252 throw new IllegalArgumentException("port and changeType " +
253 "must be null for " + switchUpdateType +
254 " updates");
255 }
256 }
257 this.swId = swId;
258 this.switchUpdateType = switchUpdateType;
Pankaj Berde465ac7c2013-05-23 13:47:49 -0700259 this.port = port;
Brian O'Connorc67f9fa2014-08-07 18:17:46 -0700260 this.changeType = changeType;
Pankaj Berde465ac7c2013-05-23 13:47:49 -0700261 }
Ray Milkey269ffb92014-04-03 14:43:30 -0700262
Brian O'Connorc67f9fa2014-08-07 18:17:46 -0700263 @Override
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -0800264 public void dispatch() {
265 if (log.isTraceEnabled()) {
266 log.trace("Dispatching switch update {} {}",
Brian O'Connorc67f9fa2014-08-07 18:17:46 -0700267 HexString.toHexString(swId), switchUpdateType);
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -0800268 }
269 if (switchListeners != null) {
270 for (IOFSwitchListener listener : switchListeners) {
Saurav Dasfcdad072014-08-13 14:15:21 -0700271 switch (switchUpdateType) {
272 case ACTIVATED_MASTER:
273 // don't count here. We have more specific
274 // counters before the update is created
275 listener.switchActivatedMaster(swId);
276 break;
277 case ACTIVATED_EQUAL:
278 // don't count here. We have more specific
279 // counters before the update is created
280 listener.switchActivatedEqual(swId);
281 break;
282 case MASTER_TO_EQUAL:
283 listener.switchMasterToEqual(swId);
284 break;
285 case EQUAL_TO_MASTER:
286 listener.switchEqualToMaster(swId);
287 break;
288 case DISCONNECTED:
289 // don't count here. We have more specific
290 // counters before the update is created
291 listener.switchDisconnected(swId);
292 break;
293 case PORTCHANGED:
294 counters.switchPortChanged.updateCounterWithFlush();
295 listener.switchPortChanged(swId, port, changeType);
296 break;
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -0800297 }
298 }
299 }
300 }
Brian O'Connorc67f9fa2014-08-07 18:17:46 -0700301
Brian O'Connorc67f9fa2014-08-07 18:17:46 -0700302 }
303
304 protected boolean addConnectedSwitch(long dpid, OFChannelHandler h) {
305 if (connectedSwitches.get(dpid) != null) {
306 log.error("Trying to add connectedSwitch but found a previous "
307 + "value for dpid: {}", dpid);
308 return false;
309 } else {
310 connectedSwitches.put(dpid, h);
311 return true;
312 }
313 }
314
315 /**
Saurav Dasfcdad072014-08-13 14:15:21 -0700316 * Switch Events
Brian O'Connorc67f9fa2014-08-07 18:17:46 -0700317 */
318 @Override
319 public void addSwitchEvent(long dpid, String reason, boolean flushNow) {
320 if (flushNow)
321 evSwitch.updateEventWithFlush(new SwitchEvent(dpid, reason));
322 else
323 evSwitch.updateEventNoFlush(new SwitchEvent(dpid, reason));
324 }
325
326 private boolean validActivation(long dpid) {
327 if (connectedSwitches.get(dpid) == null) {
328 log.error("Trying to activate switch but is not in "
329 + "connected switches: dpid {}. Aborting ..",
330 HexString.toHexString(dpid));
331 return false;
332 }
333 if (activeMasterSwitches.get(dpid) != null ||
334 activeEqualSwitches.get(dpid) != null) {
335 log.error("Trying to activate switch but it is already "
336 + "activated: dpid {}. Found in activeMaster: {} "
337 + "Found in activeEqual: {}. Aborting ..", new Object[] {
Saurav Dasfcdad072014-08-13 14:15:21 -0700338 HexString.toHexString(dpid),
339 (activeMasterSwitches.get(dpid) == null) ? 'Y' : 'N',
340 (activeEqualSwitches.get(dpid) == null) ? 'Y' : 'N'});
Brian O'Connorc67f9fa2014-08-07 18:17:46 -0700341 counters.switchWithSameDpidActivated.updateCounterWithFlush();
342 return false;
343 }
344 return true;
345 }
346
347 /**
348 * Called when a switch is activated, with this controller's role as MASTER
349 */
350 protected boolean addActivatedMasterSwitch(long dpid, IOFSwitch sw) {
Saurav Dasfcdad072014-08-13 14:15:21 -0700351 synchronized (multiCacheLock) {
352 if (!validActivation(dpid))
353 return false;
Brian O'Connorc67f9fa2014-08-07 18:17:46 -0700354 activeMasterSwitches.put(dpid, sw);
355 }
Pavlin Radoslavov000fbae2014-08-19 19:42:58 -0700356
Saurav Dasfcdad072014-08-13 14:15:21 -0700357 // update counters and events
Brian O'Connorc67f9fa2014-08-07 18:17:46 -0700358 counters.switchActivated.updateCounterWithFlush();
359 evSwitch.updateEventWithFlush(new SwitchEvent(dpid, "activeMaster"));
360 addUpdateToQueue(new SwitchUpdate(dpid,
361 SwitchUpdateType.ACTIVATED_MASTER));
362 return true;
363 }
364
365 /**
366 * Called when a switch is activated, with this controller's role as EQUAL
367 */
368 protected boolean addActivatedEqualSwitch(long dpid, IOFSwitch sw) {
Saurav Dasfcdad072014-08-13 14:15:21 -0700369 synchronized (multiCacheLock) {
370 if (!validActivation(dpid))
371 return false;
Brian O'Connorc67f9fa2014-08-07 18:17:46 -0700372 activeEqualSwitches.put(dpid, sw);
373 }
Saurav Dasfcdad072014-08-13 14:15:21 -0700374 // update counters and events
Brian O'Connorc67f9fa2014-08-07 18:17:46 -0700375 counters.switchActivated.updateCounterWithFlush();
376 evSwitch.updateEventWithFlush(new SwitchEvent(dpid, "activeEqual"));
377 addUpdateToQueue(new SwitchUpdate(dpid,
378 SwitchUpdateType.ACTIVATED_EQUAL));
379 return true;
380 }
381
382 /**
Saurav Dasfcdad072014-08-13 14:15:21 -0700383 * Called when this controller's role for a switch transitions from equal to
384 * master. For 1.0 switches, we internally refer to the role 'slave' as
Brian O'Connorc67f9fa2014-08-07 18:17:46 -0700385 * 'equal' - so this transition is equivalent to 'addActivatedMasterSwitch'.
386 */
387 protected void transitionToMasterSwitch(long dpid) {
Saurav Dasfcdad072014-08-13 14:15:21 -0700388 synchronized (multiCacheLock) {
389 IOFSwitch sw = activeEqualSwitches.remove(dpid);
390 if (sw == null) {
391 log.error("Transition to master called on sw {}, but switch "
392 + "was not found in controller-cache", dpid);
393 return;
394 }
395 activeMasterSwitches.put(dpid, sw);
396 }
397 addUpdateToQueue(new SwitchUpdate(dpid,
Brian O'Connorc67f9fa2014-08-07 18:17:46 -0700398 SwitchUpdateType.EQUAL_TO_MASTER));
399 }
400
Brian O'Connorc67f9fa2014-08-07 18:17:46 -0700401 /**
Saurav Dasfcdad072014-08-13 14:15:21 -0700402 * Called when this controller's role for a switch transitions to equal. For
403 * 1.0 switches, we internally refer to the role 'slave' as 'equal'.
Brian O'Connorc67f9fa2014-08-07 18:17:46 -0700404 */
405 protected void transitionToEqualSwitch(long dpid) {
Saurav Dasfcdad072014-08-13 14:15:21 -0700406 synchronized (multiCacheLock) {
407 IOFSwitch sw = activeMasterSwitches.remove(dpid);
408 if (sw == null) {
409 log.error("Transition to equal called on sw {}, but switch "
410 + "was not found in controller-cache", dpid);
411 return;
412 }
413 activeEqualSwitches.put(dpid, sw);
414 }
415 addUpdateToQueue(new SwitchUpdate(dpid,
Brian O'Connorc67f9fa2014-08-07 18:17:46 -0700416 SwitchUpdateType.MASTER_TO_EQUAL));
417 }
418
419 /**
420 * Clear all state in controller switch maps for a switch that has
Saurav Dasfcdad072014-08-13 14:15:21 -0700421 * disconnected from the local controller. Also release control for that
422 * switch from the global repository. Notify switch listeners.
Brian O'Connorc67f9fa2014-08-07 18:17:46 -0700423 */
424 protected void removeConnectedSwitch(long dpid) {
425 releaseRegistryControl(dpid);
426 connectedSwitches.remove(dpid);
427 IOFSwitch sw = activeMasterSwitches.remove(dpid);
Saurav Dasfcdad072014-08-13 14:15:21 -0700428 if (sw == null) {
429 sw = activeEqualSwitches.remove(dpid);
430 }
Brian O'Connorc67f9fa2014-08-07 18:17:46 -0700431 if (sw != null) {
432 sw.cancelAllStatisticsReplies();
433 sw.setConnected(false); // do we need this?
434 }
435 evSwitch.updateEventWithFlush(new SwitchEvent(dpid, "disconnected"));
436 counters.switchDisconnected.updateCounterWithFlush();
437 addUpdateToQueue(new SwitchUpdate(dpid, SwitchUpdateType.DISCONNECTED));
438 }
439
440 /**
Saurav Dasfcdad072014-08-13 14:15:21 -0700441 * Indicates that ports on the given switch have changed. Enqueue a switch
442 * update.
Jonathan Hartcb34f382014-08-12 21:11:03 -0700443 *
Brian O'Connorc67f9fa2014-08-07 18:17:46 -0700444 * @param sw
445 */
446 protected void notifyPortChanged(long dpid, OFPortDesc port,
447 PortChangeType changeType) {
448 if (port == null || changeType == null) {
449 String msg = String.format("Switch port or changetType must not "
450 + "be null in port change notification");
451 throw new NullPointerException(msg);
452 }
453 if (connectedSwitches.get(dpid) == null || getSwitch(dpid) == null) {
454 log.warn("Port change update on switch {} not connected or activated "
455 + "... Aborting.", HexString.toHexString(dpid));
456 return;
457 }
458
Brian O'Connorc67f9fa2014-08-07 18:17:46 -0700459 SwitchUpdate update = new SwitchUpdate(dpid, SwitchUpdateType.PORTCHANGED,
460 port, changeType);
461 addUpdateToQueue(update);
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -0800462 }
Ray Milkey269ffb92014-04-03 14:43:30 -0700463
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -0800464 // ***************
465 // Getters/Setters
Brian O'Connorc67f9fa2014-08-07 18:17:46 -0700466 // ***************
Ray Milkey269ffb92014-04-03 14:43:30 -0700467
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -0800468 public void setRestApiService(IRestApiService restApi) {
469 this.restApi = restApi;
470 }
Ray Milkey269ffb92014-04-03 14:43:30 -0700471
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -0800472 public void setThreadPoolService(IThreadPoolService tp) {
473 this.threadPool = tp;
474 }
475
Ray Milkey269ffb92014-04-03 14:43:30 -0700476 public void setMastershipService(IControllerRegistryService serviceImpl) {
477 this.registryService = serviceImpl;
Pankaj Berdedc73bb12013-08-14 13:46:38 -0700478 }
Ray Milkey269ffb92014-04-03 14:43:30 -0700479
480 public void setLinkDiscoveryService(ILinkDiscoveryService linkDiscovery) {
481 this.linkDiscovery = linkDiscovery;
482 }
483
Brian O'Connorc67f9fa2014-08-07 18:17:46 -0700484 public void setDebugCounter(IDebugCounterService debugCounters) {
485 this.debugCounters = debugCounters;
486 }
487
488 public void setDebugEvent(IDebugEventService debugEvents) {
489 this.debugEvents = debugEvents;
490 }
491
492 IDebugCounterService getDebugCounter() {
493 return this.debugCounters;
Ray Milkey269ffb92014-04-03 14:43:30 -0700494 }
495
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -0800496 // **********************
Brian O'Connorc67f9fa2014-08-07 18:17:46 -0700497 // Role Handling
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -0800498 // **********************
Ray Milkey269ffb92014-04-03 14:43:30 -0700499
Saurav Dasfcdad072014-08-13 14:15:21 -0700500 /**
501 * created by ONOS - works with registry service
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -0800502 */
Jonathan Hartcc957a02013-02-26 10:39:04 -0800503 protected class RoleChangeCallback implements ControlChangeCallback {
Ray Milkey269ffb92014-04-03 14:43:30 -0700504 @Override
Pavlin Radoslavov695f8952014-07-23 16:57:01 -0700505 public void controlChanged(long dpidLong, boolean hasControl) {
506 Dpid dpid = new Dpid(dpidLong);
Ray Milkey269ffb92014-04-03 14:43:30 -0700507 log.info("Role change callback for switch {}, hasControl {}",
Brian O'Connorc67f9fa2014-08-07 18:17:46 -0700508 dpid, hasControl);
Pankaj Berde01939e92013-03-08 14:38:27 -0800509
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -0800510 Role role = null;
Ray Milkey269ffb92014-04-03 14:43:30 -0700511
Brian O'Connorc67f9fa2014-08-07 18:17:46 -0700512 /*
513 * issue #229
514 * Cannot rely on sw.getRole() as it can be behind due to pending
515 * role changes in the queue. Just submit it and late the
516 * RoleChanger handle duplicates.
517 */
Ray Milkey269ffb92014-04-03 14:43:30 -0700518
Brian O'Connorc67f9fa2014-08-07 18:17:46 -0700519 if (hasControl) {
520 role = Role.MASTER;
Ray Milkey269ffb92014-04-03 14:43:30 -0700521 } else {
Brian O'Connorc67f9fa2014-08-07 18:17:46 -0700522 role = Role.EQUAL; // treat the same as Role.SLAVE
Ray Milkey269ffb92014-04-03 14:43:30 -0700523 }
Ray Milkey269ffb92014-04-03 14:43:30 -0700524
Brian O'Connorc67f9fa2014-08-07 18:17:46 -0700525 OFChannelHandler swCh = connectedSwitches.get(dpid.value());
526 if (swCh == null) {
527 log.warn("Switch {} not found in connected switches", dpid);
528 return;
Pankaj Berde465ac7c2013-05-23 13:47:49 -0700529 }
Brian O'Connorc67f9fa2014-08-07 18:17:46 -0700530
531 log.debug("Sending role request {} msg to {}", role, dpid);
532 swCh.sendRoleRequest(role, RoleRecvStatus.MATCHED_SET_ROLE);
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -0800533 }
Brian O'Connorc67f9fa2014-08-07 18:17:46 -0700534 }
535
536 public synchronized void submitRegistryRequest(long dpid) {
537 OFChannelHandler h = connectedSwitches.get(dpid);
538 if (h == null) {
539 log.error("Trying to request registry control for switch {} "
540 + "not in connected switches. Aborting.. ",
541 HexString.toHexString(dpid));
542 // FIXME shouldn't we immediately return here?
543 }
Saurav Dasfcdad072014-08-13 14:15:21 -0700544 // Request control of the switch from the global registry
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -0800545 try {
Brian O'Connorc67f9fa2014-08-07 18:17:46 -0700546 h.controlRequested = Boolean.TRUE;
547 registryService.requestControl(dpid, new RoleChangeCallback());
548 } catch (RegistryException e) {
549 log.debug("Registry error: {}", e.getMessage());
550 h.controlRequested = Boolean.FALSE;
551 }
552 if (!h.controlRequested) { // XXX what is being attempted here?
553 // yield to allow other thread(s) to release control
554 try {
555 Thread.sleep(10);
556 } catch (InterruptedException e) {
557 // Ignore interruptions
558 }
Saurav Dasfcdad072014-08-13 14:15:21 -0700559 // safer to bounce the switch to reconnect here than proceeding
560 // further
Brian O'Connorc67f9fa2014-08-07 18:17:46 -0700561 // XXX S why? can't we just try again a little later?
562 log.debug("Closing sw:{} because we weren't able to request control " +
563 "successfully" + dpid);
564 connectedSwitches.get(dpid).disconnectSwitch();
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -0800565 }
566 }
Ray Milkey269ffb92014-04-03 14:43:30 -0700567
Brian O'Connorc67f9fa2014-08-07 18:17:46 -0700568 public synchronized void releaseRegistryControl(long dpidLong) {
569 OFChannelHandler h = connectedSwitches.get(dpidLong);
570 if (h == null) {
571 log.error("Trying to release registry control for switch {} "
572 + "not in connected switches. Aborting.. ",
573 HexString.toHexString(dpidLong));
574 return;
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -0800575 }
Brian O'Connorc67f9fa2014-08-07 18:17:46 -0700576 if (h.controlRequested) {
577 registryService.releaseControl(dpidLong);
578 }
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -0800579 }
580
Brian O'Connorc67f9fa2014-08-07 18:17:46 -0700581 // *******************
582 // OF Message Handling
583 // *******************
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -0800584
585 /**
Brian O'Connorc67f9fa2014-08-07 18:17:46 -0700586 * Handle and dispatch a message to IOFMessageListeners.
Jonathan Hartcb34f382014-08-12 21:11:03 -0700587 *
Saurav Dasfcdad072014-08-13 14:15:21 -0700588 * We only dispatch messages to listeners if the controller's role is
589 * MASTER.
Jonathan Hartcb34f382014-08-12 21:11:03 -0700590 *
Brian O'Connorc67f9fa2014-08-07 18:17:46 -0700591 * @param sw The switch sending the message
592 * @param m The message the switch sent
Saurav Dasfcdad072014-08-13 14:15:21 -0700593 * @param flContext The floodlight context to use for this message. If null,
594 * a new context will be allocated.
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -0800595 * @throws IOException
Jonathan Hartcb34f382014-08-12 21:11:03 -0700596 *
Saurav Dasfcdad072014-08-13 14:15:21 -0700597 * FIXME: this method and the ChannelHandler disagree on which
598 * messages should be dispatched and which shouldn't
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -0800599 */
600 @LogMessageDocs({
Ray Milkey269ffb92014-04-03 14:43:30 -0700601 @LogMessageDoc(level = "ERROR",
602 message = "Ignoring PacketIn (Xid = {xid}) because the data" +
603 " field is empty.",
604 explanation = "The switch sent an improperly-formatted PacketIn" +
605 " message",
606 recommendation = LogMessageDoc.CHECK_SWITCH),
607 @LogMessageDoc(level = "WARN",
608 message = "Unhandled OF Message: {} from {}",
609 explanation = "The switch sent a message not handled by " +
610 "the controller")
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -0800611 })
Saurav Dasfcdad072014-08-13 14:15:21 -0700612 @SuppressWarnings({"fallthrough", "unchecked"})
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -0800613 protected void handleMessage(IOFSwitch sw, OFMessage m,
Saurav Dasfcdad072014-08-13 14:15:21 -0700614 FloodlightContext bContext)
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -0800615 throws IOException {
616 Ethernet eth = null;
Yuta HIGUCHIa507baf2014-08-22 13:42:40 -0700617 // FIXME losing port number precision here
Brian O'Connorc67f9fa2014-08-07 18:17:46 -0700618 short inport = -1;
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -0800619
620 switch (m.getType()) {
Saurav Dasfcdad072014-08-13 14:15:21 -0700621 case PACKET_IN:
622 OFPacketIn pi = (OFPacketIn) m;
623 // log.info("saw packet in from sw {}", sw.getStringId());
624 if (pi.getData().length <= 0) {
625 log.error("Ignoring PacketIn (Xid = " + pi.getXid() +
626 ") because/* the data field is empty.");
627 return;
628 }
629
630 // get incoming port to store in floodlight context
631 if (sw.getOFVersion() == OFVersion.OF_10) {
632 inport = pi.getInPort().getShortPortNumber();
633 } else if (sw.getOFVersion() == OFVersion.OF_13) {
634 for (MatchField<?> mf : pi.getMatch().getMatchFields()) {
635 if (mf.id == MatchFields.IN_PORT) {
636 inport = pi.getMatch().get((MatchField<OFPort>) mf)
637 .getShortPortNumber();
638 break;
639 }
640 }
641 if (inport == -1) {
642 log.error("Match field for incoming port missing in "
643 + "packet-in from sw {}. Ignoring msg",
644 sw.getStringId());
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -0800645 return;
646 }
Saurav Dasfcdad072014-08-13 14:15:21 -0700647 } else {
648 // should have been taken care of earlier in handshake
649 log.error("OFVersion {} not supported for "
650 + "packet-in from sw {}. Ignoring msg",
651 sw.getOFVersion(), sw.getStringId());
652 return;
653 }
Ray Milkey269ffb92014-04-03 14:43:30 -0700654
Saurav Dasfcdad072014-08-13 14:15:21 -0700655 // decode enclosed ethernet packet to store in floodlight context
656 if (Controller.ALWAYS_DECODE_ETH) {
657 eth = new Ethernet();
658 eth.deserialize(pi.getData(), 0,
659 pi.getData().length);
660 }
661 // fall through to default case...
662
663 /*log.debug("Sw:{} packet-in: {}", sw.getStringId(),
664 String.format("0x%x", eth.getEtherType()));*/
665 if (eth.getEtherType() != (short) EthType.LLDP.getValue())
666 log.trace("Sw:{} packet-in: {}", sw.getStringId(), pi);
667
668 default:
669
670 List<IOFMessageListener> listeners = null;
671
672 if (messageListeners.containsKey(m.getType())) {
673 listeners = messageListeners.get(m.getType()).
674 getOrderedListeners();
675 }
676 FloodlightContext bc = null;
677 if (listeners != null) {
678 // Check if floodlight context is passed from the calling
679 // function, if so use that floodlight context, otherwise
680 // allocate one
681 if (bContext == null) {
682 bc = flcontext_alloc();
Brian O'Connorc67f9fa2014-08-07 18:17:46 -0700683 } else {
Saurav Dasfcdad072014-08-13 14:15:21 -0700684 bc = bContext;
685 }
686 if (eth != null) {
687 IFloodlightProviderService.bcStore.put(bc,
688 IFloodlightProviderService.CONTEXT_PI_PAYLOAD,
689 eth);
690 }
691 if (inport != -1) {
692 bc.getStorage().put(
693 IFloodlightProviderService.CONTEXT_PI_INPORT,
694 inport);
Brian O'Connorc67f9fa2014-08-07 18:17:46 -0700695 }
696
Saurav Dasfcdad072014-08-13 14:15:21 -0700697 // Get the starting time (overall and per-component) of
698 // the processing chain for this packet if performance
699 // monitoring is turned on
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -0800700
Saurav Dasfcdad072014-08-13 14:15:21 -0700701 Command cmd = null;
702 for (IOFMessageListener listener : listeners) {
703 if (listener instanceof IOFSwitchFilter) {
704 if (!((IOFSwitchFilter) listener).isInterested(sw)) {
705 continue;
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -0800706 }
707 }
mininet73e7fb72013-12-03 14:25:53 -0800708
Saurav Dasfcdad072014-08-13 14:15:21 -0700709 cmd = listener.receive(sw, m, bc);
710
711 if (Command.STOP.equals(cmd)) {
712 break;
713 }
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -0800714 }
Ray Milkey269ffb92014-04-03 14:43:30 -0700715
Saurav Dasfcdad072014-08-13 14:15:21 -0700716 } else {
717 log.warn("Unhandled OF Message: {} from {}", m, sw);
718 }
719
720 if ((bContext == null) && (bc != null))
721 flcontext_free(bc);
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -0800722 }
723 }
Ray Milkey269ffb92014-04-03 14:43:30 -0700724
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -0800725 // ***************
Brian O'Connorc67f9fa2014-08-07 18:17:46 -0700726 // IFloodlightProviderService
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -0800727 // ***************
Ray Milkey269ffb92014-04-03 14:43:30 -0700728
Brian O'Connorc67f9fa2014-08-07 18:17:46 -0700729 // FIXME: remove this method
730 @Override
Saurav Dasfcdad072014-08-13 14:15:21 -0700731 public Map<Long, IOFSwitch> getSwitches() {
Brian O'Connorc67f9fa2014-08-07 18:17:46 -0700732 return getMasterSwitches();
733 }
734
735 // FIXME: remove this method
736 public Map<Long, IOFSwitch> getMasterSwitches() {
737 return Collections.unmodifiableMap(activeMasterSwitches);
738 }
739
Brian O'Connorc67f9fa2014-08-07 18:17:46 -0700740 @Override
741 public Set<Long> getAllSwitchDpids() {
742 Set<Long> dpids = new HashSet<Long>();
743 dpids.addAll(activeMasterSwitches.keySet());
744 dpids.addAll(activeEqualSwitches.keySet());
745 return dpids;
746 }
747
748 @Override
749 public Set<Long> getAllMasterSwitchDpids() {
750 Set<Long> dpids = new HashSet<Long>();
751 dpids.addAll(activeMasterSwitches.keySet());
752 return dpids;
753 }
754
755 @Override
756 public Set<Long> getAllEqualSwitchDpids() {
757 Set<Long> dpids = new HashSet<Long>();
758 dpids.addAll(activeEqualSwitches.keySet());
759 return dpids;
760 }
761
762 @Override
763 public IOFSwitch getSwitch(long dpid) {
764 IOFSwitch sw = null;
Saurav Dasfcdad072014-08-13 14:15:21 -0700765 if ((sw = activeMasterSwitches.get(dpid)) != null)
766 return sw;
767 if ((sw = activeEqualSwitches.get(dpid)) != null)
768 return sw;
Brian O'Connorc67f9fa2014-08-07 18:17:46 -0700769 return sw;
770 }
771
772 @Override
773 public IOFSwitch getMasterSwitch(long dpid) {
Saurav Dasfcdad072014-08-13 14:15:21 -0700774 return activeMasterSwitches.get(dpid);
Brian O'Connorc67f9fa2014-08-07 18:17:46 -0700775 }
776
777 @Override
778 public IOFSwitch getEqualSwitch(long dpid) {
Saurav Dasfcdad072014-08-13 14:15:21 -0700779 return activeEqualSwitches.get(dpid);
Brian O'Connorc67f9fa2014-08-07 18:17:46 -0700780 }
781
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -0800782 @Override
Ray Milkey269ffb92014-04-03 14:43:30 -0700783 public synchronized void addOFMessageListener(OFType type,
Saurav Dasfcdad072014-08-13 14:15:21 -0700784 IOFMessageListener listener) {
Ray Milkey269ffb92014-04-03 14:43:30 -0700785 ListenerDispatcher<OFType, IOFMessageListener> ldd =
786 messageListeners.get(type);
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -0800787 if (ldd == null) {
788 ldd = new ListenerDispatcher<OFType, IOFMessageListener>();
789 messageListeners.put(type, ldd);
790 }
791 ldd.addListener(type, listener);
792 }
793
794 @Override
795 public synchronized void removeOFMessageListener(OFType type,
Saurav Dasfcdad072014-08-13 14:15:21 -0700796 IOFMessageListener listener) {
Ray Milkey269ffb92014-04-03 14:43:30 -0700797 ListenerDispatcher<OFType, IOFMessageListener> ldd =
798 messageListeners.get(type);
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -0800799 if (ldd != null) {
800 ldd.removeListener(listener);
801 }
802 }
Ray Milkey269ffb92014-04-03 14:43:30 -0700803
Brian O'Connorc67f9fa2014-08-07 18:17:46 -0700804 public void removeOFMessageListeners(OFType type) {
805 messageListeners.remove(type);
806 }
807
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -0800808 private void logListeners() {
Saurav Dasfcdad072014-08-13 14:15:21 -0700809 for (Map.Entry<OFType, ListenerDispatcher<OFType, IOFMessageListener>> entry : messageListeners
810 .entrySet()) {
Ray Milkey269ffb92014-04-03 14:43:30 -0700811
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -0800812 OFType type = entry.getKey();
Ray Milkey269ffb92014-04-03 14:43:30 -0700813 ListenerDispatcher<OFType, IOFMessageListener> ldd =
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -0800814 entry.getValue();
Ray Milkey269ffb92014-04-03 14:43:30 -0700815
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -0800816 StringBuffer sb = new StringBuffer();
Brian O'Connorc67f9fa2014-08-07 18:17:46 -0700817 sb.append("OFMessageListeners for ");
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -0800818 sb.append(type);
819 sb.append(": ");
820 for (IOFMessageListener l : ldd.getOrderedListeners()) {
821 sb.append(l.getName());
822 sb.append(",");
823 }
Ray Milkey269ffb92014-04-03 14:43:30 -0700824 log.debug(sb.toString());
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -0800825 }
Brian O'Connorc67f9fa2014-08-07 18:17:46 -0700826 StringBuffer sl = new StringBuffer();
827 sl.append("SwitchUpdate Listeners: ");
828 for (IOFSwitchListener swlistener : switchListeners) {
829 sl.append(swlistener.getName());
830 sl.append(",");
831 }
832 log.debug(sl.toString());
Ray Milkey269ffb92014-04-03 14:43:30 -0700833
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -0800834 }
835
836 @Override
837 public void addOFSwitchListener(IOFSwitchListener listener) {
838 this.switchListeners.add(listener);
839 }
840
841 @Override
842 public void removeOFSwitchListener(IOFSwitchListener listener) {
843 this.switchListeners.remove(listener);
844 }
845
846 @Override
847 public Map<OFType, List<IOFMessageListener>> getListeners() {
Ray Milkey269ffb92014-04-03 14:43:30 -0700848 Map<OFType, List<IOFMessageListener>> lers =
849 new HashMap<OFType, List<IOFMessageListener>>();
Saurav Dasfcdad072014-08-13 14:15:21 -0700850 for (Entry<OFType, ListenerDispatcher<OFType, IOFMessageListener>> e : messageListeners
851 .entrySet()) {
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -0800852 lers.put(e.getKey(), e.getValue().getOrderedListeners());
853 }
854 return Collections.unmodifiableMap(lers);
855 }
Ray Milkey269ffb92014-04-03 14:43:30 -0700856
Brian O'Connorc67f9fa2014-08-07 18:17:46 -0700857 /*@Override
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -0800858 @LogMessageDocs({
Ray Milkey269ffb92014-04-03 14:43:30 -0700859 @LogMessageDoc(message = "Failed to inject OFMessage {message} onto " +
860 "a null switch",
861 explanation = "Failed to process a message because the switch " +
862 " is no longer connected."),
863 @LogMessageDoc(level = "ERROR",
864 message = "Error reinjecting OFMessage on switch {switch}",
865 explanation = "An I/O error occured while attempting to " +
866 "process an OpenFlow message",
867 recommendation = LogMessageDoc.CHECK_SWITCH)
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -0800868 })
869 public boolean injectOfMessage(IOFSwitch sw, OFMessage msg,
870 FloodlightContext bc) {
871 if (sw == null) {
872 log.info("Failed to inject OFMessage {} onto a null switch", msg);
873 return false;
874 }
Ray Milkey269ffb92014-04-03 14:43:30 -0700875
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -0800876 // FIXME: Do we need to be able to inject messages to switches
877 // where we're the slave controller (i.e. they're connected but
878 // not active)?
879 // FIXME: Don't we need synchronization logic here so we're holding
880 // the listener read lock when we call handleMessage? After some
881 // discussions it sounds like the right thing to do here would be to
882 // inject the message as a netty upstream channel event so it goes
883 // through the normal netty event processing, including being
Brian O'Connorc67f9fa2014-08-07 18:17:46 -0700884 // handled
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -0800885 if (!activeSwitches.containsKey(sw.getId())) return false;
Ray Milkey269ffb92014-04-03 14:43:30 -0700886
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -0800887 try {
888 // Pass Floodlight context to the handleMessages()
889 handleMessage(sw, msg, bc);
890 } catch (IOException e) {
Ray Milkey269ffb92014-04-03 14:43:30 -0700891 log.error("Error reinjecting OFMessage on switch {}",
892 HexString.toHexString(sw.getId()));
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -0800893 return false;
894 }
895 return true;
Brian O'Connorc67f9fa2014-08-07 18:17:46 -0700896 }*/
897
Saurav Dasfcdad072014-08-13 14:15:21 -0700898 // @Override
899 // public boolean injectOfMessage(IOFSwitch sw, OFMessage msg) {
900 // // call the overloaded version with floodlight context set to null
901 // return injectOfMessage(sw, msg, null);
902 // }
Brian O'Connorc67f9fa2014-08-07 18:17:46 -0700903
Saurav Dasfcdad072014-08-13 14:15:21 -0700904 // @Override
905 // public void handleOutgoingMessage(IOFSwitch sw, OFMessage m,
906 // FloodlightContext bc) {
907 //
908 // List<IOFMessageListener> listeners = null;
909 // if (messageListeners.containsKey(m.getType())) {
910 // listeners =
911 // messageListeners.get(m.getType()).getOrderedListeners();
912 // }
913 //
914 // if (listeners != null) {
915 // for (IOFMessageListener listener : listeners) {
916 // if (listener instanceof IOFSwitchFilter) {
917 // if (!((IOFSwitchFilter) listener).isInterested(sw)) {
918 // continue;
919 // }
920 // }
921 // if (Command.STOP.equals(listener.receive(sw, m, bc))) {
922 // break;
923 // }
924 // }
925 // }
926 // }
Jonathan Harta213bce2014-08-11 15:44:07 -0700927
928 /**
929 * Gets an OpenFlow message factory for version 1.0.
Jonathan Hartcb34f382014-08-12 21:11:03 -0700930 *
Jonathan Harta213bce2014-08-11 15:44:07 -0700931 * @return an OpenFlow 1.0 message factory
932 */
Brian O'Connorc67f9fa2014-08-07 18:17:46 -0700933 public OFFactory getOFMessageFactory_10() {
934 return factory10;
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -0800935 }
936
Jonathan Harta213bce2014-08-11 15:44:07 -0700937 /**
938 * Gets an OpenFlow message factory for version 1.3.
Jonathan Hartcb34f382014-08-12 21:11:03 -0700939 *
Jonathan Harta213bce2014-08-11 15:44:07 -0700940 * @return an OpenFlow 1.3 message factory
941 */
Brian O'Connorc67f9fa2014-08-07 18:17:46 -0700942 public OFFactory getOFMessageFactory_13() {
943 return factory13;
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -0800944 }
Ray Milkey269ffb92014-04-03 14:43:30 -0700945
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -0800946 @Override
Brian O'Connorc67f9fa2014-08-07 18:17:46 -0700947 public void publishUpdate(IUpdate update) {
948 try {
949 this.updates.put(update);
950 } catch (InterruptedException e) {
951 log.error("Failure adding update to queue", e);
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -0800952 }
953 }
954
955 @Override
Brian O'Connorc67f9fa2014-08-07 18:17:46 -0700956 public Map<String, String> getControllerNodeIPs() {
957 // We return a copy of the mapping so we can guarantee that
958 // the mapping return is the same as one that will be (or was)
959 // dispatched to IHAListeners
960 HashMap<String, String> retval = new HashMap<String, String>();
961 synchronized (controllerNodeIPsCache) {
962 retval.putAll(controllerNodeIPsCache);
963 }
964 return retval;
965 }
966
967 @Override
968 public long getSystemStartTime() {
969 return (this.systemStartTime);
970 }
971
972 @Override
973 public void setAlwaysClearFlowsOnSwAdd(boolean value) {
974 this.alwaysClearFlowsOnSwAdd = value;
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -0800975 }
Ray Milkey269ffb92014-04-03 14:43:30 -0700976
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -0800977 @Override
Pavlin Radoslavov53b208a2014-07-28 13:16:11 -0700978 public OnosInstanceId getOnosInstanceId() {
979 return onosInstanceId;
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -0800980 }
Ray Milkey269ffb92014-04-03 14:43:30 -0700981
Brian O'Connorc67f9fa2014-08-07 18:17:46 -0700982 /**
983 * FOR TESTING ONLY. Dispatch all updates in the update queue until queue is
984 * empty
985 */
986 void processUpdateQueueForTesting() {
987 while (!updates.isEmpty()) {
988 IUpdate update = updates.poll();
989 if (update != null)
990 update.dispatch();
991 }
992 }
993
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -0800994 // **************
995 // Initialization
996 // **************
997
Brian O'Connorc67f9fa2014-08-07 18:17:46 -0700998 // XXX S This should probably go away OR it should be edited to handle
999 // controller roles per switch! Then it could be a way to
1000 // deterministically configure a switch to a MASTER controller instance
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -08001001 /**
Saurav Dasfcdad072014-08-13 14:15:21 -07001002 * Sets the initial role based on properties in the config params. It looks
1003 * for two different properties. If the "role" property is specified then
1004 * the value should be either "EQUAL", "MASTER", or "SLAVE" and the role of
1005 * the controller is set to the specified value. If the "role" property is
1006 * not specified then it looks next for the "role.path" property. In this
1007 * case the value should be the path to a property file in the file system
1008 * that contains a property called "floodlight.role" which can be one of the
1009 * values listed above for the "role" property. The idea behind the
1010 * "role.path" mechanism is that you have some separate heartbeat and master
1011 * controller election algorithm that determines the role of the controller.
1012 * When a role transition happens, it updates the current role in the file
1013 * specified by the "role.path" file. Then if floodlight restarts for some
1014 * reason it can get the correct current role of the controller from the
1015 * file.
Jonathan Hartcb34f382014-08-12 21:11:03 -07001016 *
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -08001017 * @param configParams The config params for the FloodlightProvider service
Saurav Dasfcdad072014-08-13 14:15:21 -07001018 * @return A valid role if role information is specified in the config
1019 * params, otherwise null
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -08001020 */
1021 @LogMessageDocs({
Ray Milkey269ffb92014-04-03 14:43:30 -07001022 @LogMessageDoc(message = "Controller role set to {role}",
1023 explanation = "Setting the initial HA role to "),
1024 @LogMessageDoc(level = "ERROR",
1025 message = "Invalid current role value: {role}",
1026 explanation = "An invalid HA role value was read from the " +
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -08001027 "properties file",
Ray Milkey269ffb92014-04-03 14:43:30 -07001028 recommendation = LogMessageDoc.CHECK_CONTROLLER)
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -08001029 })
1030 protected Role getInitialRole(Map<String, String> configParams) {
1031 Role role = null;
1032 String roleString = configParams.get("role");
Praseed Balakrishnan59469e92014-06-20 11:55:13 -07001033 FileInputStream fs = null;
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -08001034 if (roleString == null) {
1035 String rolePath = configParams.get("rolepath");
1036 if (rolePath != null) {
1037 Properties properties = new Properties();
1038 try {
Praseed Balakrishnan59469e92014-06-20 11:55:13 -07001039 fs = new FileInputStream(rolePath);
1040 properties.load(fs);
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -08001041 roleString = properties.getProperty("floodlight.role");
Ray Milkey269ffb92014-04-03 14:43:30 -07001042 } catch (IOException exc) {
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -08001043 // Don't treat it as an error if the file specified by the
1044 // rolepath property doesn't exist. This lets us enable the
1045 // HA mechanism by just creating/setting the floodlight.role
1046 // property in that file without having to modify the
1047 // floodlight properties.
Praseed Balakrishnan59469e92014-06-20 11:55:13 -07001048 } finally {
1049 if (fs != null) {
1050 try {
1051 fs.close();
1052 } catch (IOException e) {
1053 log.error("Exception while closing resource ", e);
1054 }
1055 }
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -08001056 }
1057 }
1058 }
Ray Milkey269ffb92014-04-03 14:43:30 -07001059
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -08001060 if (roleString != null) {
1061 // Canonicalize the string to the form used for the enum constants
1062 roleString = roleString.trim().toUpperCase();
1063 try {
1064 role = Role.valueOf(roleString);
Ray Milkey269ffb92014-04-03 14:43:30 -07001065 } catch (IllegalArgumentException exc) {
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -08001066 log.error("Invalid current role value: {}", roleString);
1067 }
1068 }
Ray Milkey269ffb92014-04-03 14:43:30 -07001069
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -08001070 log.info("Controller role set to {}", role);
Ray Milkey269ffb92014-04-03 14:43:30 -07001071
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -08001072 return role;
1073 }
Ray Milkey269ffb92014-04-03 14:43:30 -07001074
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -08001075 /**
1076 * Tell controller that we're ready to accept switches loop
Jonathan Hartcb34f382014-08-12 21:11:03 -07001077 *
Ray Milkey269ffb92014-04-03 14:43:30 -07001078 * @throws IOException
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -08001079 */
Brian O'Connorc67f9fa2014-08-07 18:17:46 -07001080 @Override
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -08001081 @LogMessageDocs({
Ray Milkey269ffb92014-04-03 14:43:30 -07001082 @LogMessageDoc(message = "Listening for switch connections on {address}",
1083 explanation = "The controller is ready and listening for new" +
1084 " switch connections"),
1085 @LogMessageDoc(message = "Storage exception in controller " +
1086 "updates loop; terminating process",
1087 explanation = ERROR_DATABASE,
1088 recommendation = LogMessageDoc.CHECK_CONTROLLER),
1089 @LogMessageDoc(level = "ERROR",
1090 message = "Exception in controller updates loop",
1091 explanation = "Failed to dispatch controller event",
1092 recommendation = LogMessageDoc.GENERIC_ACTION)
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -08001093 })
1094 public void run() {
1095 if (log.isDebugEnabled()) {
1096 logListeners();
1097 }
Ray Milkey269ffb92014-04-03 14:43:30 -07001098
1099 try {
1100 final ServerBootstrap bootstrap = createServerBootStrap();
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -08001101
1102 bootstrap.setOption("reuseAddr", true);
1103 bootstrap.setOption("child.keepAlive", true);
1104 bootstrap.setOption("child.tcpNoDelay", true);
1105 bootstrap.setOption("child.sendBufferSize", Controller.SEND_BUFFER_SIZE);
1106
Ray Milkey269ffb92014-04-03 14:43:30 -07001107 ChannelPipelineFactory pfact =
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -08001108 new OpenflowPipelineFactory(this, null);
1109 bootstrap.setPipelineFactory(pfact);
1110 InetSocketAddress sa = new InetSocketAddress(openFlowPort);
1111 final ChannelGroup cg = new DefaultChannelGroup();
1112 cg.add(bootstrap.bind(sa));
Ray Milkey269ffb92014-04-03 14:43:30 -07001113
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -08001114 log.info("Listening for switch connections on {}", sa);
1115 } catch (Exception e) {
1116 throw new RuntimeException(e);
1117 }
1118
1119 // main loop
1120 while (true) {
1121 try {
1122 IUpdate update = updates.take();
1123 update.dispatch();
1124 } catch (InterruptedException e) {
Brian O'Connorc67f9fa2014-08-07 18:17:46 -07001125 log.error("Received interrupted exception in updates loop;" +
Saurav Dasfcdad072014-08-13 14:15:21 -07001126 "terminating process");
Brian O'Connorc67f9fa2014-08-07 18:17:46 -07001127 terminate();
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -08001128 } catch (Exception e) {
1129 log.error("Exception in controller updates loop", e);
1130 }
1131 }
1132 }
1133
1134 private ServerBootstrap createServerBootStrap() {
1135 if (workerThreads == 0) {
1136 return new ServerBootstrap(
1137 new NioServerSocketChannelFactory(
1138 Executors.newCachedThreadPool(),
1139 Executors.newCachedThreadPool()));
1140 } else {
1141 return new ServerBootstrap(
1142 new NioServerSocketChannelFactory(
1143 Executors.newCachedThreadPool(),
1144 Executors.newCachedThreadPool(), workerThreads));
1145 }
1146 }
Ray Milkey269ffb92014-04-03 14:43:30 -07001147
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -08001148 public void setConfigParams(Map<String, String> configParams) {
1149 String ofPort = configParams.get("openflowport");
1150 if (ofPort != null) {
1151 this.openFlowPort = Integer.parseInt(ofPort);
1152 }
1153 log.debug("OpenFlow port set to {}", this.openFlowPort);
1154 String threads = configParams.get("workerthreads");
1155 if (threads != null) {
1156 this.workerThreads = Integer.parseInt(threads);
1157 }
1158 log.debug("Number of worker threads set to {}", this.workerThreads);
1159 String controllerId = configParams.get("controllerid");
1160 if (controllerId != null) {
Pavlin Radoslavov53b208a2014-07-28 13:16:11 -07001161 this.onosInstanceId = new OnosInstanceId(controllerId);
Ray Milkey269ffb92014-04-03 14:43:30 -07001162 } else {
Saurav Dasfcdad072014-08-13 14:15:21 -07001163 // Try to get the hostname of the machine and use that for
1164 // controller ID
Ray Milkey269ffb92014-04-03 14:43:30 -07001165 try {
1166 String hostname = java.net.InetAddress.getLocalHost().getHostName();
Pavlin Radoslavov53b208a2014-07-28 13:16:11 -07001167 this.onosInstanceId = new OnosInstanceId(hostname);
Ray Milkey269ffb92014-04-03 14:43:30 -07001168 } catch (UnknownHostException e) {
1169 // Can't get hostname, we'll just use the default
1170 }
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -08001171 }
Ray Milkey269ffb92014-04-03 14:43:30 -07001172
Jonathan Hart6eda2302014-08-14 14:57:03 -07001173 String useOnly10 = configParams.get("useOnly10");
1174 if (useOnly10 != null && useOnly10.equalsIgnoreCase("true")) {
1175 OFChannelHandler.useOnly10 = true;
1176 log.info("Setting controller to only use OpenFlow 1.0");
1177 }
1178
Pavlin Radoslavov53b208a2014-07-28 13:16:11 -07001179 log.debug("ControllerId set to {}", this.onosInstanceId);
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -08001180 }
1181
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -08001182 /**
1183 * Initialize internal data structures
1184 */
1185 public void init(Map<String, String> configParams) {
1186 // These data structures are initialized here because other
1187 // module's startUp() might be called before ours
1188 this.messageListeners =
Brian O'Connorc67f9fa2014-08-07 18:17:46 -07001189 new ConcurrentHashMap<OFType, ListenerDispatcher<OFType,
Saurav Dasfcdad072014-08-13 14:15:21 -07001190 IOFMessageListener>>();
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -08001191 this.switchListeners = new CopyOnWriteArraySet<IOFSwitchListener>();
Brian O'Connorc67f9fa2014-08-07 18:17:46 -07001192 this.activeMasterSwitches = new ConcurrentHashMap<Long, IOFSwitch>();
1193 this.activeEqualSwitches = new ConcurrentHashMap<Long, IOFSwitch>();
1194 this.connectedSwitches = new ConcurrentHashMap<Long, OFChannelHandler>();
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -08001195 this.controllerNodeIPsCache = new HashMap<String, String>();
1196 this.updates = new LinkedBlockingQueue<IUpdate>();
Brian O'Connorc67f9fa2014-08-07 18:17:46 -07001197
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -08001198 setConfigParams(configParams);
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -08001199 this.systemStartTime = System.currentTimeMillis();
Brian O'Connorc67f9fa2014-08-07 18:17:46 -07001200 this.counters = new Counters();
1201 this.multiCacheLock = new Object();
1202
1203 String option = configParams.get("flushSwitchesOnReconnect");
1204 if (option != null && option.equalsIgnoreCase("true")) {
1205 this.setAlwaysClearFlowsOnSwActivate(true);
1206 log.info("Flush switches on reconnect -- Enabled.");
1207 } else {
1208 this.setAlwaysClearFlowsOnSwActivate(false);
1209 log.info("Flush switches on reconnect -- Disabled");
1210 }
Jonathan Hartcb34f382014-08-12 21:11:03 -07001211
1212 option = configParams.get("cpqdUsePipeline13");
1213 if (option != null && option.equalsIgnoreCase("true")) {
1214 DriverManager.setConfigForCpqd(true);
1215 log.info("Using OF1.3 pipeline for the CPqD software switch");
1216 } else {
1217 log.info("Using OF1.0 pipeline for the CPqD software switch");
1218 }
Jonathan Hart2c44a642014-08-19 03:40:43 -07001219
1220 String disableOvsClassification =
1221 configParams.get("disableOvsClassification");
1222 if (disableOvsClassification != null &&
1223 disableOvsClassification.equalsIgnoreCase("true")) {
1224 DriverManager.setDisableOvsClassification(true);
1225 log.info("OVS switches will be classified as default switches");
1226 }
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -08001227 }
Ray Milkey269ffb92014-04-03 14:43:30 -07001228
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -08001229 /**
1230 * Startup all of the controller's components
Jonathan Hartcb34f382014-08-12 21:11:03 -07001231 *
Brian O'Connorc67f9fa2014-08-07 18:17:46 -07001232 * @throws FloodlightModuleException
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -08001233 */
Ray Milkey269ffb92014-04-03 14:43:30 -07001234 @LogMessageDoc(message = "Waiting for storage source",
1235 explanation = "The system database is not yet ready",
1236 recommendation = "If this message persists, this indicates " +
1237 "that the system database has failed to start. " +
1238 LogMessageDoc.CHECK_CONTROLLER)
Brian O'Connorc67f9fa2014-08-07 18:17:46 -07001239 public void startupComponents() throws FloodlightModuleException {
Ray Milkey269ffb92014-04-03 14:43:30 -07001240 try {
Pavlin Radoslavov53b208a2014-07-28 13:16:11 -07001241 registryService.registerController(onosInstanceId.toString());
Ray Milkey269ffb92014-04-03 14:43:30 -07001242 } catch (RegistryException e) {
1243 log.warn("Registry service error: {}", e.getMessage());
1244 }
1245
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -08001246 // Add our REST API
1247 restApi.addRestletRoutable(new CoreWebRoutable());
Ray Milkey269ffb92014-04-03 14:43:30 -07001248
Brian O'Connorc67f9fa2014-08-07 18:17:46 -07001249 // Startup load monitoring
1250 if (overload_drop) {
1251 this.loadmonitor.startMonitoring(
Saurav Dasfcdad072014-08-13 14:15:21 -07001252 this.threadPool.getScheduledExecutor());
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -08001253 }
Brian O'Connorc67f9fa2014-08-07 18:17:46 -07001254
1255 // register counters and events
1256 try {
1257 this.counters.createCounters(debugCounters);
1258 } catch (CounterException e) {
1259 throw new FloodlightModuleException(e.getMessage());
1260 }
1261 registerControllerDebugEvents();
1262 }
1263
1264 // **************
1265 // debugCounter registrations
1266 // **************
1267
1268 public static class Counters {
1269 public static final String prefix = "controller";
1270 public IDebugCounter setRoleEqual;
1271 public IDebugCounter setSameRole;
1272 public IDebugCounter setRoleMaster;
1273 public IDebugCounter remoteStoreNotification;
1274 public IDebugCounter invalidPortsChanged;
1275 public IDebugCounter invalidSwitchActivatedWhileSlave;
1276 public IDebugCounter invalidStoreEventWhileMaster;
1277 public IDebugCounter switchDisconnectedWhileSlave;
1278 public IDebugCounter switchActivated;
1279 public IDebugCounter errorSameSwitchReactivated; // err
1280 public IDebugCounter switchWithSameDpidActivated; // warn
Saurav Dasfcdad072014-08-13 14:15:21 -07001281 public IDebugCounter newSwitchActivated; // new switch
Brian O'Connorc67f9fa2014-08-07 18:17:46 -07001282 public IDebugCounter syncedSwitchActivated;
1283 public IDebugCounter readyForReconcile;
1284 public IDebugCounter newSwitchFromStore;
1285 public IDebugCounter updatedSwitchFromStore;
1286 public IDebugCounter switchDisconnected;
1287 public IDebugCounter syncedSwitchRemoved;
1288 public IDebugCounter unknownSwitchRemovedFromStore;
1289 public IDebugCounter consolidateStoreRunCount;
1290 public IDebugCounter consolidateStoreInconsistencies;
1291 public IDebugCounter storeSyncError;
1292 public IDebugCounter switchesNotReconnectingToNewMaster;
1293 public IDebugCounter switchPortChanged;
1294 public IDebugCounter switchOtherChange;
1295 public IDebugCounter dispatchMessageWhileSlave;
Saurav Dasfcdad072014-08-13 14:15:21 -07001296 public IDebugCounter dispatchMessage; // does this cnt make sense? more
1297 // specific?? per type? count
1298 // stops?
Brian O'Connorc67f9fa2014-08-07 18:17:46 -07001299 public IDebugCounter controllerNodeIpsChanged;
1300 public IDebugCounter messageReceived;
1301 public IDebugCounter messageInputThrottled;
1302 public IDebugCounter switchDisconnectReadTimeout;
1303 public IDebugCounter switchDisconnectHandshakeTimeout;
1304 public IDebugCounter switchDisconnectIOError;
1305 public IDebugCounter switchDisconnectParseError;
1306 public IDebugCounter switchDisconnectSwitchStateException;
1307 public IDebugCounter rejectedExecutionException;
1308 public IDebugCounter switchDisconnectOtherException;
1309 public IDebugCounter switchConnected;
1310 public IDebugCounter unhandledMessage;
1311 public IDebugCounter packetInWhileSwitchIsSlave;
1312 public IDebugCounter epermErrorWhileSwitchIsMaster;
1313 public IDebugCounter roleNotResentBecauseRolePending;
1314 public IDebugCounter roleRequestSent;
1315 public IDebugCounter roleReplyTimeout;
1316 public IDebugCounter roleReplyReceived; // expected RoleReply received
1317 public IDebugCounter roleReplyErrorUnsupported;
1318 public IDebugCounter switchCounterRegistrationFailed;
1319 public IDebugCounter packetParsingError;
1320
1321 void createCounters(IDebugCounterService debugCounters) throws CounterException {
1322 setRoleEqual =
Saurav Dasfcdad072014-08-13 14:15:21 -07001323 debugCounters.registerCounter(
Brian O'Connorc67f9fa2014-08-07 18:17:46 -07001324 prefix, "set-role-equal",
Saurav Dasfcdad072014-08-13 14:15:21 -07001325 "Controller received a role request with role of " +
1326 "EQUAL which is unusual",
Brian O'Connorc67f9fa2014-08-07 18:17:46 -07001327 CounterType.ALWAYS_COUNT);
1328 setSameRole =
Saurav Dasfcdad072014-08-13 14:15:21 -07001329 debugCounters.registerCounter(
Brian O'Connorc67f9fa2014-08-07 18:17:46 -07001330 prefix, "set-same-role",
1331 "Controller received a role request for the same " +
Saurav Dasfcdad072014-08-13 14:15:21 -07001332 "role the controller already had",
Brian O'Connorc67f9fa2014-08-07 18:17:46 -07001333 CounterType.ALWAYS_COUNT,
1334 IDebugCounterService.CTR_MDATA_WARN);
1335
1336 setRoleMaster =
Saurav Dasfcdad072014-08-13 14:15:21 -07001337 debugCounters.registerCounter(
Brian O'Connorc67f9fa2014-08-07 18:17:46 -07001338 prefix, "set-role-master",
1339 "Controller received a role request with role of " +
Saurav Dasfcdad072014-08-13 14:15:21 -07001340 "MASTER. This counter can be at most 1.",
Brian O'Connorc67f9fa2014-08-07 18:17:46 -07001341 CounterType.ALWAYS_COUNT);
1342
1343 remoteStoreNotification =
Saurav Dasfcdad072014-08-13 14:15:21 -07001344 debugCounters.registerCounter(
Brian O'Connorc67f9fa2014-08-07 18:17:46 -07001345 prefix, "remote-store-notification",
1346 "Received a notification from the sync service " +
Saurav Dasfcdad072014-08-13 14:15:21 -07001347 "indicating that switch information has changed",
Brian O'Connorc67f9fa2014-08-07 18:17:46 -07001348 CounterType.ALWAYS_COUNT);
1349
1350 invalidPortsChanged =
Saurav Dasfcdad072014-08-13 14:15:21 -07001351 debugCounters.registerCounter(
Brian O'Connorc67f9fa2014-08-07 18:17:46 -07001352 prefix, "invalid-ports-changed",
1353 "Received an unexpected ports changed " +
Saurav Dasfcdad072014-08-13 14:15:21 -07001354 "notification while the controller was in " +
1355 "SLAVE role.",
Brian O'Connorc67f9fa2014-08-07 18:17:46 -07001356 CounterType.ALWAYS_COUNT,
1357 IDebugCounterService.CTR_MDATA_WARN);
1358
1359 invalidSwitchActivatedWhileSlave =
Saurav Dasfcdad072014-08-13 14:15:21 -07001360 debugCounters.registerCounter(
Brian O'Connorc67f9fa2014-08-07 18:17:46 -07001361 prefix, "invalid-switch-activated-while-slave",
1362 "Received an unexpected switchActivated " +
Saurav Dasfcdad072014-08-13 14:15:21 -07001363 "notification while the controller was in " +
1364 "SLAVE role.",
Brian O'Connorc67f9fa2014-08-07 18:17:46 -07001365 CounterType.ALWAYS_COUNT,
1366 IDebugCounterService.CTR_MDATA_WARN);
1367
1368 invalidStoreEventWhileMaster =
Saurav Dasfcdad072014-08-13 14:15:21 -07001369 debugCounters.registerCounter(
Brian O'Connorc67f9fa2014-08-07 18:17:46 -07001370 prefix, "invalid-store-event-while-master",
1371 "Received an unexpected notification from " +
Saurav Dasfcdad072014-08-13 14:15:21 -07001372 "the sync store while the controller was in " +
1373 "MASTER role.",
Brian O'Connorc67f9fa2014-08-07 18:17:46 -07001374 CounterType.ALWAYS_COUNT,
1375 IDebugCounterService.CTR_MDATA_WARN);
1376
1377 switchDisconnectedWhileSlave =
Saurav Dasfcdad072014-08-13 14:15:21 -07001378 debugCounters.registerCounter(
Brian O'Connorc67f9fa2014-08-07 18:17:46 -07001379 prefix, "switch-disconnected-while-slave",
1380 "A switch disconnected and the controller was " +
Saurav Dasfcdad072014-08-13 14:15:21 -07001381 "in SLAVE role.",
Brian O'Connorc67f9fa2014-08-07 18:17:46 -07001382 CounterType.ALWAYS_COUNT,
1383 IDebugCounterService.CTR_MDATA_WARN);
1384
1385 switchActivated =
Saurav Dasfcdad072014-08-13 14:15:21 -07001386 debugCounters.registerCounter(
Brian O'Connorc67f9fa2014-08-07 18:17:46 -07001387 prefix, "switch-activated",
1388 "A switch connected to this controller is now " +
Saurav Dasfcdad072014-08-13 14:15:21 -07001389 "in MASTER role",
Brian O'Connorc67f9fa2014-08-07 18:17:46 -07001390 CounterType.ALWAYS_COUNT);
1391
1392 errorSameSwitchReactivated = // err
Saurav Dasfcdad072014-08-13 14:15:21 -07001393 debugCounters.registerCounter(
1394 prefix, "error-same-switch-reactivated",
1395 "A switch that was already in active state " +
Brian O'Connorc67f9fa2014-08-07 18:17:46 -07001396 "was activated again. This indicates a " +
1397 "controller defect",
Saurav Dasfcdad072014-08-13 14:15:21 -07001398 CounterType.ALWAYS_COUNT,
1399 IDebugCounterService.CTR_MDATA_ERROR);
Brian O'Connorc67f9fa2014-08-07 18:17:46 -07001400
1401 switchWithSameDpidActivated = // warn
Saurav Dasfcdad072014-08-13 14:15:21 -07001402 debugCounters.registerCounter(
1403 prefix, "switch-with-same-dpid-activated",
1404 "A switch with the same DPID as another switch " +
Brian O'Connorc67f9fa2014-08-07 18:17:46 -07001405 "connected to the controller. This can be " +
1406 "caused by multiple switches configured with " +
1407 "the same DPID or by a switch reconnecting very " +
1408 "quickly.",
Saurav Dasfcdad072014-08-13 14:15:21 -07001409 CounterType.COUNT_ON_DEMAND,
1410 IDebugCounterService.CTR_MDATA_WARN);
Brian O'Connorc67f9fa2014-08-07 18:17:46 -07001411
Saurav Dasfcdad072014-08-13 14:15:21 -07001412 newSwitchActivated = // new switch
1413 debugCounters.registerCounter(
1414 prefix, "new-switch-activated",
1415 "A new switch has completed the handshake as " +
Brian O'Connorc67f9fa2014-08-07 18:17:46 -07001416 "MASTER. The switch was not known to any other " +
1417 "controller in the cluster",
Saurav Dasfcdad072014-08-13 14:15:21 -07001418 CounterType.ALWAYS_COUNT);
Brian O'Connorc67f9fa2014-08-07 18:17:46 -07001419 syncedSwitchActivated =
Saurav Dasfcdad072014-08-13 14:15:21 -07001420 debugCounters.registerCounter(
Brian O'Connorc67f9fa2014-08-07 18:17:46 -07001421 prefix, "synced-switch-activated",
1422 "A switch has completed the handshake as " +
Saurav Dasfcdad072014-08-13 14:15:21 -07001423 "MASTER. The switch was known to another " +
1424 "controller in the cluster",
Brian O'Connorc67f9fa2014-08-07 18:17:46 -07001425 CounterType.ALWAYS_COUNT);
1426
1427 readyForReconcile =
Saurav Dasfcdad072014-08-13 14:15:21 -07001428 debugCounters.registerCounter(
Brian O'Connorc67f9fa2014-08-07 18:17:46 -07001429 prefix, "ready-for-reconcile",
1430 "Controller is ready for flow reconciliation " +
Saurav Dasfcdad072014-08-13 14:15:21 -07001431 "after Slave to Master transition. Either all " +
1432 "previously known switches are now active " +
1433 "or they have timed out and have been removed." +
1434 "This counter will be 0 or 1.",
Brian O'Connorc67f9fa2014-08-07 18:17:46 -07001435 CounterType.ALWAYS_COUNT);
1436
1437 newSwitchFromStore =
Saurav Dasfcdad072014-08-13 14:15:21 -07001438 debugCounters.registerCounter(
Brian O'Connorc67f9fa2014-08-07 18:17:46 -07001439 prefix, "new-switch-from-store",
1440 "A new switch has connected to another " +
Saurav Dasfcdad072014-08-13 14:15:21 -07001441 "another controller in the cluster. This " +
1442 "controller instance has received a sync store " +
1443 "notification for it.",
Brian O'Connorc67f9fa2014-08-07 18:17:46 -07001444 CounterType.ALWAYS_COUNT);
1445
1446 updatedSwitchFromStore =
Saurav Dasfcdad072014-08-13 14:15:21 -07001447 debugCounters.registerCounter(
Brian O'Connorc67f9fa2014-08-07 18:17:46 -07001448 prefix, "updated-switch-from-store",
1449 "Information about a switch connected to " +
Saurav Dasfcdad072014-08-13 14:15:21 -07001450 "another controller instance was updated in " +
1451 "the sync store. This controller instance has " +
1452 "received a notification for it",
Brian O'Connorc67f9fa2014-08-07 18:17:46 -07001453 CounterType.ALWAYS_COUNT);
1454
1455 switchDisconnected =
Saurav Dasfcdad072014-08-13 14:15:21 -07001456 debugCounters.registerCounter(
Brian O'Connorc67f9fa2014-08-07 18:17:46 -07001457 prefix, "switch-disconnected",
1458 "FIXME: switch has disconnected",
1459 CounterType.ALWAYS_COUNT);
1460
1461 syncedSwitchRemoved =
Saurav Dasfcdad072014-08-13 14:15:21 -07001462 debugCounters.registerCounter(
Brian O'Connorc67f9fa2014-08-07 18:17:46 -07001463 prefix, "synced-switch-removed",
1464 "A switch connected to another controller " +
Saurav Dasfcdad072014-08-13 14:15:21 -07001465 "instance has disconnected from the controller " +
1466 "cluster. This controller instance has " +
1467 "received a notification for it",
Brian O'Connorc67f9fa2014-08-07 18:17:46 -07001468 CounterType.ALWAYS_COUNT);
1469
1470 unknownSwitchRemovedFromStore =
Saurav Dasfcdad072014-08-13 14:15:21 -07001471 debugCounters.registerCounter(
Brian O'Connorc67f9fa2014-08-07 18:17:46 -07001472 prefix, "unknown-switch-removed-from-store",
1473 "This controller instances has received a sync " +
Saurav Dasfcdad072014-08-13 14:15:21 -07001474 "store notification that a switch has " +
1475 "disconnected but this controller instance " +
1476 "did not have the any information about the " +
1477 "switch", // might be less than warning
Brian O'Connorc67f9fa2014-08-07 18:17:46 -07001478 CounterType.ALWAYS_COUNT,
1479 IDebugCounterService.CTR_MDATA_WARN);
1480
1481 consolidateStoreRunCount =
Saurav Dasfcdad072014-08-13 14:15:21 -07001482 debugCounters.registerCounter(
Brian O'Connorc67f9fa2014-08-07 18:17:46 -07001483 prefix, "consolidate-store-run-count",
1484 "This controller has transitioned from SLAVE " +
Saurav Dasfcdad072014-08-13 14:15:21 -07001485 "to MASTER and waited for switches to reconnect. " +
1486 "The controller has finished waiting and has " +
1487 "reconciled switch entries in the sync store " +
1488 "with live state",
Brian O'Connorc67f9fa2014-08-07 18:17:46 -07001489 CounterType.ALWAYS_COUNT);
1490
1491 consolidateStoreInconsistencies =
1492 debugCounters.registerCounter(
Saurav Dasfcdad072014-08-13 14:15:21 -07001493 prefix, "consolidate-store-inconsistencies",
1494 "During switch sync store consolidation: " +
1495 "Number of switches that were in the store " +
1496 "but not otherwise known plus number of " +
1497 "switches that were in the store previously " +
1498 "but are now missing plus number of " +
1499 "connected switches that were absent from " +
1500 "the store although this controller has " +
1501 "written them. A non-zero count " +
1502 "indicates a brief split-brain dual MASTER " +
1503 "situation during fail-over",
1504 CounterType.ALWAYS_COUNT);
Brian O'Connorc67f9fa2014-08-07 18:17:46 -07001505
1506 storeSyncError =
Saurav Dasfcdad072014-08-13 14:15:21 -07001507 debugCounters.registerCounter(
Brian O'Connorc67f9fa2014-08-07 18:17:46 -07001508 prefix, "store-sync-error",
1509 "Number of times a sync store operation failed " +
Saurav Dasfcdad072014-08-13 14:15:21 -07001510 "due to a store sync exception or an entry in " +
1511 "in the store had invalid data.",
Brian O'Connorc67f9fa2014-08-07 18:17:46 -07001512 CounterType.ALWAYS_COUNT,
1513 IDebugCounterService.CTR_MDATA_ERROR);
1514
1515 switchesNotReconnectingToNewMaster =
Saurav Dasfcdad072014-08-13 14:15:21 -07001516 debugCounters.registerCounter(
Brian O'Connorc67f9fa2014-08-07 18:17:46 -07001517 prefix, "switches-not-reconnecting-to-new-master",
1518 "Switches that were connected to another " +
Saurav Dasfcdad072014-08-13 14:15:21 -07001519 "controller instance in the cluster but that " +
1520 "did not reconnect to this controller after it " +
1521 "transitioned to MASTER", // might be less
1522 // than warning
Brian O'Connorc67f9fa2014-08-07 18:17:46 -07001523 CounterType.ALWAYS_COUNT);
1524
1525 switchPortChanged =
Saurav Dasfcdad072014-08-13 14:15:21 -07001526 debugCounters.registerCounter(
Brian O'Connorc67f9fa2014-08-07 18:17:46 -07001527 prefix, "switch-port-changed",
1528 "Number of times switch ports have changed",
1529 CounterType.ALWAYS_COUNT);
1530 switchOtherChange =
Saurav Dasfcdad072014-08-13 14:15:21 -07001531 debugCounters.registerCounter(
Brian O'Connorc67f9fa2014-08-07 18:17:46 -07001532 prefix, "switch-other-change",
1533 "Number of times other information of a switch " +
Saurav Dasfcdad072014-08-13 14:15:21 -07001534 "has changed.",
Brian O'Connorc67f9fa2014-08-07 18:17:46 -07001535 CounterType.ALWAYS_COUNT);
1536
1537 dispatchMessageWhileSlave =
Saurav Dasfcdad072014-08-13 14:15:21 -07001538 debugCounters.registerCounter(
Brian O'Connorc67f9fa2014-08-07 18:17:46 -07001539 prefix, "dispatch-message-while-slave",
1540 "Number of times an OF message was received " +
Saurav Dasfcdad072014-08-13 14:15:21 -07001541 "and supposed to be dispatched but the " +
1542 "controller was in SLAVE role and the message " +
1543 "was not dispatched",
Brian O'Connorc67f9fa2014-08-07 18:17:46 -07001544 CounterType.ALWAYS_COUNT);
1545
Saurav Dasfcdad072014-08-13 14:15:21 -07001546 dispatchMessage = // does this cnt make sense? more specific?? per
1547 // type? count stops?
1548 debugCounters.registerCounter(
1549 prefix, "dispatch-message",
1550 "Number of times an OF message was dispatched " +
Brian O'Connorc67f9fa2014-08-07 18:17:46 -07001551 "to registered modules",
Saurav Dasfcdad072014-08-13 14:15:21 -07001552 CounterType.ALWAYS_COUNT);
Brian O'Connorc67f9fa2014-08-07 18:17:46 -07001553
1554 controllerNodeIpsChanged =
Saurav Dasfcdad072014-08-13 14:15:21 -07001555 debugCounters.registerCounter(
Brian O'Connorc67f9fa2014-08-07 18:17:46 -07001556 prefix, "controller-nodes-ips-changed",
1557 "IP addresses of controller nodes have changed",
1558 CounterType.ALWAYS_COUNT);
1559
Saurav Dasfcdad072014-08-13 14:15:21 -07001560 // ------------------------
1561 // channel handler counters. Factor them out ??
Brian O'Connorc67f9fa2014-08-07 18:17:46 -07001562 messageReceived =
Saurav Dasfcdad072014-08-13 14:15:21 -07001563 debugCounters.registerCounter(
Brian O'Connorc67f9fa2014-08-07 18:17:46 -07001564 prefix, "message-received",
1565 "Number of OpenFlow messages received. Some of " +
Saurav Dasfcdad072014-08-13 14:15:21 -07001566 "these might be throttled",
Brian O'Connorc67f9fa2014-08-07 18:17:46 -07001567 CounterType.ALWAYS_COUNT);
1568 messageInputThrottled =
Saurav Dasfcdad072014-08-13 14:15:21 -07001569 debugCounters.registerCounter(
Brian O'Connorc67f9fa2014-08-07 18:17:46 -07001570 prefix, "message-input-throttled",
1571 "Number of OpenFlow messages that were " +
Saurav Dasfcdad072014-08-13 14:15:21 -07001572 "throttled due to high load from the sender",
Brian O'Connorc67f9fa2014-08-07 18:17:46 -07001573 CounterType.ALWAYS_COUNT,
1574 IDebugCounterService.CTR_MDATA_WARN);
Saurav Dasfcdad072014-08-13 14:15:21 -07001575 // TODO: more counters in messageReceived ??
Brian O'Connorc67f9fa2014-08-07 18:17:46 -07001576
1577 switchDisconnectReadTimeout =
Saurav Dasfcdad072014-08-13 14:15:21 -07001578 debugCounters.registerCounter(
Brian O'Connorc67f9fa2014-08-07 18:17:46 -07001579 prefix, "switch-disconnect-read-timeout",
1580 "Number of times a switch was disconnected due " +
Saurav Dasfcdad072014-08-13 14:15:21 -07001581 "due the switch failing to send OpenFlow " +
1582 "messages or responding to OpenFlow ECHOs",
Brian O'Connorc67f9fa2014-08-07 18:17:46 -07001583 CounterType.ALWAYS_COUNT,
1584 IDebugCounterService.CTR_MDATA_ERROR);
1585 switchDisconnectHandshakeTimeout =
Saurav Dasfcdad072014-08-13 14:15:21 -07001586 debugCounters.registerCounter(
Brian O'Connorc67f9fa2014-08-07 18:17:46 -07001587 prefix, "switch-disconnect-handshake-timeout",
1588 "Number of times a switch was disconnected " +
Saurav Dasfcdad072014-08-13 14:15:21 -07001589 "because it failed to complete the handshake " +
1590 "in time.",
Brian O'Connorc67f9fa2014-08-07 18:17:46 -07001591 CounterType.ALWAYS_COUNT,
1592 IDebugCounterService.CTR_MDATA_ERROR);
1593 switchDisconnectIOError =
Saurav Dasfcdad072014-08-13 14:15:21 -07001594 debugCounters.registerCounter(
Brian O'Connorc67f9fa2014-08-07 18:17:46 -07001595 prefix, "switch-disconnect-io-error",
1596 "Number of times a switch was disconnected " +
Saurav Dasfcdad072014-08-13 14:15:21 -07001597 "due to IO errors on the switch connection.",
Brian O'Connorc67f9fa2014-08-07 18:17:46 -07001598 CounterType.ALWAYS_COUNT,
1599 IDebugCounterService.CTR_MDATA_ERROR);
1600 switchDisconnectParseError =
Saurav Dasfcdad072014-08-13 14:15:21 -07001601 debugCounters.registerCounter(
Brian O'Connorc67f9fa2014-08-07 18:17:46 -07001602 prefix, "switch-disconnect-parse-error",
Saurav Dasfcdad072014-08-13 14:15:21 -07001603 "Number of times a switch was disconnected " +
1604 "because it sent an invalid packet that could " +
1605 "not be parsed",
1606 CounterType.ALWAYS_COUNT,
1607 IDebugCounterService.CTR_MDATA_ERROR);
Brian O'Connorc67f9fa2014-08-07 18:17:46 -07001608
1609 switchDisconnectSwitchStateException =
Saurav Dasfcdad072014-08-13 14:15:21 -07001610 debugCounters.registerCounter(
Brian O'Connorc67f9fa2014-08-07 18:17:46 -07001611 prefix, "switch-disconnect-switch-state-exception",
1612 "Number of times a switch was disconnected " +
Saurav Dasfcdad072014-08-13 14:15:21 -07001613 "because it sent messages that were invalid " +
1614 "given the switch connection's state.",
Brian O'Connorc67f9fa2014-08-07 18:17:46 -07001615 CounterType.ALWAYS_COUNT,
1616 IDebugCounterService.CTR_MDATA_ERROR);
1617 rejectedExecutionException =
Saurav Dasfcdad072014-08-13 14:15:21 -07001618 debugCounters.registerCounter(
Brian O'Connorc67f9fa2014-08-07 18:17:46 -07001619 prefix, "rejected-execution-exception",
1620 "TODO",
1621 CounterType.ALWAYS_COUNT,
1622 IDebugCounterService.CTR_MDATA_ERROR);
1623
1624 switchDisconnectOtherException =
Saurav Dasfcdad072014-08-13 14:15:21 -07001625 debugCounters.registerCounter(
1626 prefix, "switch-disconnect-other-exception",
Brian O'Connorc67f9fa2014-08-07 18:17:46 -07001627 "Number of times a switch was disconnected " +
Saurav Dasfcdad072014-08-13 14:15:21 -07001628 "due to an exceptional situation not covered " +
1629 "by other counters",
Brian O'Connorc67f9fa2014-08-07 18:17:46 -07001630 CounterType.ALWAYS_COUNT,
1631 IDebugCounterService.CTR_MDATA_ERROR);
1632
1633 switchConnected =
Saurav Dasfcdad072014-08-13 14:15:21 -07001634 debugCounters.registerCounter(
Brian O'Connorc67f9fa2014-08-07 18:17:46 -07001635 prefix, "switch-connected",
1636 "Number of times a new switch connection was " +
Saurav Dasfcdad072014-08-13 14:15:21 -07001637 "established",
Brian O'Connorc67f9fa2014-08-07 18:17:46 -07001638 CounterType.ALWAYS_COUNT);
1639
1640 unhandledMessage =
Saurav Dasfcdad072014-08-13 14:15:21 -07001641 debugCounters.registerCounter(
Brian O'Connorc67f9fa2014-08-07 18:17:46 -07001642 prefix, "unhandled-message",
1643 "Number of times an OpenFlow message was " +
Saurav Dasfcdad072014-08-13 14:15:21 -07001644 "received that the controller ignored because " +
1645 "it was inapproriate given the switch " +
1646 "connection's state.",
Brian O'Connorc67f9fa2014-08-07 18:17:46 -07001647 CounterType.ALWAYS_COUNT,
1648 IDebugCounterService.CTR_MDATA_WARN);
Saurav Dasfcdad072014-08-13 14:15:21 -07001649 // might be less than warning
Brian O'Connorc67f9fa2014-08-07 18:17:46 -07001650
1651 packetInWhileSwitchIsSlave =
Saurav Dasfcdad072014-08-13 14:15:21 -07001652 debugCounters.registerCounter(
Brian O'Connorc67f9fa2014-08-07 18:17:46 -07001653 prefix, "packet-in-while-switch-is-slave",
1654 "Number of times a packet in was received " +
Saurav Dasfcdad072014-08-13 14:15:21 -07001655 "from a switch that was in SLAVE role. " +
1656 "Possibly inidicates inconsistent roles.",
Brian O'Connorc67f9fa2014-08-07 18:17:46 -07001657 CounterType.ALWAYS_COUNT);
1658 epermErrorWhileSwitchIsMaster =
Saurav Dasfcdad072014-08-13 14:15:21 -07001659 debugCounters.registerCounter(
Brian O'Connorc67f9fa2014-08-07 18:17:46 -07001660 prefix, "eperm-error-while-switch-is-master",
1661 "Number of times a permission error was " +
Saurav Dasfcdad072014-08-13 14:15:21 -07001662 "received while the switch was in MASTER role. " +
1663 "Possibly inidicates inconsistent roles.",
Brian O'Connorc67f9fa2014-08-07 18:17:46 -07001664 CounterType.ALWAYS_COUNT,
1665 IDebugCounterService.CTR_MDATA_WARN);
1666
1667 roleNotResentBecauseRolePending =
Saurav Dasfcdad072014-08-13 14:15:21 -07001668 debugCounters.registerCounter(
Brian O'Connorc67f9fa2014-08-07 18:17:46 -07001669 prefix, "role-not-resent-because-role-pending",
1670 "The controller tried to reestablish a role " +
Saurav Dasfcdad072014-08-13 14:15:21 -07001671 "with a switch but did not do so because a " +
1672 "previous role request was still pending",
Brian O'Connorc67f9fa2014-08-07 18:17:46 -07001673 CounterType.ALWAYS_COUNT);
1674 roleRequestSent =
Saurav Dasfcdad072014-08-13 14:15:21 -07001675 debugCounters.registerCounter(
Brian O'Connorc67f9fa2014-08-07 18:17:46 -07001676 prefix, "role-request-sent",
1677 "Number of times the controller sent a role " +
Saurav Dasfcdad072014-08-13 14:15:21 -07001678 "request to a switch.",
Brian O'Connorc67f9fa2014-08-07 18:17:46 -07001679 CounterType.ALWAYS_COUNT);
1680 roleReplyTimeout =
Saurav Dasfcdad072014-08-13 14:15:21 -07001681 debugCounters.registerCounter(
Brian O'Connorc67f9fa2014-08-07 18:17:46 -07001682 prefix, "role-reply-timeout",
1683 "Number of times a role request message did not " +
Saurav Dasfcdad072014-08-13 14:15:21 -07001684 "receive the expected reply from a switch",
Brian O'Connorc67f9fa2014-08-07 18:17:46 -07001685 CounterType.ALWAYS_COUNT,
1686 IDebugCounterService.CTR_MDATA_WARN);
1687
1688 roleReplyReceived = // expected RoleReply received
Saurav Dasfcdad072014-08-13 14:15:21 -07001689 debugCounters.registerCounter(
1690 prefix, "role-reply-received",
1691 "Number of times the controller received the " +
Brian O'Connorc67f9fa2014-08-07 18:17:46 -07001692 "expected role reply message from a switch",
Saurav Dasfcdad072014-08-13 14:15:21 -07001693 CounterType.ALWAYS_COUNT);
Brian O'Connorc67f9fa2014-08-07 18:17:46 -07001694
1695 roleReplyErrorUnsupported =
Saurav Dasfcdad072014-08-13 14:15:21 -07001696 debugCounters.registerCounter(
Brian O'Connorc67f9fa2014-08-07 18:17:46 -07001697 prefix, "role-reply-error-unsupported",
1698 "Number of times the controller received an " +
Saurav Dasfcdad072014-08-13 14:15:21 -07001699 "error from a switch in response to a role " +
1700 "request indicating that the switch does not " +
1701 "support roles.",
Brian O'Connorc67f9fa2014-08-07 18:17:46 -07001702 CounterType.ALWAYS_COUNT);
1703
1704 switchCounterRegistrationFailed =
1705 debugCounters.registerCounter(prefix,
Saurav Dasfcdad072014-08-13 14:15:21 -07001706 "switch-counter-registration-failed",
1707 "Number of times the controller failed to " +
1708 "register per-switch debug counters",
1709 CounterType.ALWAYS_COUNT,
1710 IDebugCounterService.CTR_MDATA_WARN);
Brian O'Connorc67f9fa2014-08-07 18:17:46 -07001711
1712 packetParsingError =
1713 debugCounters.registerCounter(prefix,
Saurav Dasfcdad072014-08-13 14:15:21 -07001714 "packet-parsing-error",
1715 "Number of times the packet parsing " +
1716 "encountered an error",
1717 CounterType.ALWAYS_COUNT,
1718 IDebugCounterService.CTR_MDATA_ERROR);
Brian O'Connorc67f9fa2014-08-07 18:17:46 -07001719 }
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -08001720 }
1721
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -08001722 @Override
Brian O'Connorc67f9fa2014-08-07 18:17:46 -07001723 public Counters getCounters() {
1724 return this.counters;
1725 }
1726
1727 // **************
1728 // debugEvent registrations
1729 // **************
1730
1731 private void registerControllerDebugEvents() throws FloodlightModuleException {
1732 if (debugEvents == null) {
1733 debugEvents = new NullDebugEvent();
1734 }
1735 try {
1736 evSwitch = debugEvents.registerEvent(
Saurav Dasfcdad072014-08-13 14:15:21 -07001737 Counters.prefix, "switchevent",
1738 "Switch connected, disconnected or port changed",
1739 EventType.ALWAYS_LOG, SwitchEvent.class, 100);
Brian O'Connorc67f9fa2014-08-07 18:17:46 -07001740 } catch (MaxEventsRegistered e) {
1741 throw new FloodlightModuleException("Max events registered", e);
1742 }
1743 }
1744
1745 public class SwitchEvent {
1746 @EventColumn(name = "dpid", description = EventFieldType.DPID)
1747 long dpid;
1748
1749 @EventColumn(name = "reason", description = EventFieldType.STRING)
1750 String reason;
1751
1752 public SwitchEvent(long dpid, String reason) {
1753 this.dpid = dpid;
1754 this.reason = reason;
1755 }
1756 }
1757
1758 // **************
1759 // Utility methods
1760 // **************
1761
1762 @Override
1763 public void setAlwaysClearFlowsOnSwActivate(boolean value) {
Saurav Dasfcdad072014-08-13 14:15:21 -07001764 // this.alwaysClearFlowsOnSwActivate = value;
Brian O'Connorc67f9fa2014-08-07 18:17:46 -07001765 // XXX S need to be a little more careful about this
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -08001766 }
1767
1768 @Override
Brian O'Connorc67f9fa2014-08-07 18:17:46 -07001769 public Map<String, Long> getMemory() {
1770 Map<String, Long> m = new HashMap<String, Long>();
1771 Runtime runtime = Runtime.getRuntime();
1772 m.put("total", runtime.totalMemory());
1773 m.put("free", runtime.freeMemory());
1774 return m;
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -08001775 }
Ray Milkey269ffb92014-04-03 14:43:30 -07001776
Brian O'Connorc67f9fa2014-08-07 18:17:46 -07001777 @Override
1778 public Long getUptime() {
1779 RuntimeMXBean rb = ManagementFactory.getRuntimeMXBean();
1780 return rb.getUptime();
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -08001781 }
Brian O'Connorc67f9fa2014-08-07 18:17:46 -07001782
1783 /**
1784 * Forward to the driver-manager to get an IOFSwitch instance.
Jonathan Hartcb34f382014-08-12 21:11:03 -07001785 *
Brian O'Connorc67f9fa2014-08-07 18:17:46 -07001786 * @param desc
1787 * @return
1788 */
1789 protected IOFSwitch getOFSwitchInstance(OFDescStatsReply desc, OFVersion ofv) {
1790 return DriverManager.getOFSwitchImpl(desc, ofv);
1791 }
1792
1793 protected IThreadPoolService getThreadPoolService() {
1794 return this.threadPool;
1795 }
1796
1797 /**
Saurav Dasfcdad072014-08-13 14:15:21 -07001798 * Part of the controller updates framework (see 'run()' method) Use this
1799 * method to add an IUpdate. A thread-pool will serve the update by
1800 * dispatching it to all listeners for that update.
Jonathan Hartcb34f382014-08-12 21:11:03 -07001801 *
Brian O'Connorc67f9fa2014-08-07 18:17:46 -07001802 * @param update
1803 */
Saurav Dasfcdad072014-08-13 14:15:21 -07001804 @LogMessageDoc(level = "WARN",
1805 message = "Failure adding update {} to queue",
1806 explanation = "The controller tried to add an internal notification" +
1807 " to its message queue but the add failed.",
1808 recommendation = LogMessageDoc.REPORT_CONTROLLER_BUG)
Brian O'Connorc67f9fa2014-08-07 18:17:46 -07001809 private void addUpdateToQueue(IUpdate update) {
1810 try {
1811 this.updates.put(update);
1812 } catch (InterruptedException e) {
1813 // This should never happen
1814 log.error("Failure adding update {} to queue.", update);
1815 }
1816 }
1817
1818 void flushAll() {
1819 // Flush all flow-mods/packet-out/stats generated from this "train"
1820 OFSwitchImplBase.flush_all();
1821 debugCounters.flushCounters();
1822 debugEvents.flushEvents();
1823 }
1824
1825 /**
1826 * flcontext_free - Free the context to the current thread
Jonathan Hartcb34f382014-08-12 21:11:03 -07001827 *
Brian O'Connorc67f9fa2014-08-07 18:17:46 -07001828 * @param flcontext
1829 */
1830 protected void flcontext_free(FloodlightContext flcontext) {
1831 flcontext.getStorage().clear();
1832 flcontext_cache.get().push(flcontext);
1833 }
1834
1835 @LogMessageDoc(message = "Calling System.exit",
1836 explanation = "The controller is terminating")
1837 private synchronized void terminate() {
1838 log.info("Calling System.exit");
1839 System.exit(1);
1840 }
1841
Brian O'Connorc67f9fa2014-08-07 18:17:46 -07001842 // ***************
1843 // Floodlight context related
1844 // ***************
1845
1846 /**
1847 * flcontext_cache - Keep a thread local stack of contexts
1848 */
1849 protected static final ThreadLocal<Stack<FloodlightContext>> flcontext_cache =
1850 new ThreadLocal<Stack<FloodlightContext>>() {
1851 @Override
1852 protected Stack<FloodlightContext> initialValue() {
1853 return new Stack<FloodlightContext>();
1854 }
1855 };
1856
1857 /**
Saurav Dasfcdad072014-08-13 14:15:21 -07001858 * flcontext_alloc - pop a context off the stack, if required create a new
1859 * one
Jonathan Hartcb34f382014-08-12 21:11:03 -07001860 *
Brian O'Connorc67f9fa2014-08-07 18:17:46 -07001861 * @return FloodlightContext
1862 */
1863 protected static FloodlightContext flcontext_alloc() {
1864 FloodlightContext flcontext = null;
1865
1866 if (flcontext_cache.get().empty()) {
1867 flcontext = new FloodlightContext();
1868 } else {
1869 flcontext = flcontext_cache.get().pop();
1870 }
1871
1872 return flcontext;
1873 }
1874
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -08001875}