blob: 69f706c491a4fd23d87e821bf105ee477d7dada2 [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 }
356 // XXX Workaround to prevent race condition where a link is detected
357 // and attempted to be written to the database before the port is in
358 // the database. We now suppress link discovery on ports until we're
359 // sure they're in the database.
360 for (OFPortDesc port : sw.getPorts()) {
361 linkDiscovery.disableDiscoveryOnPort(sw.getId(),
362 port.getPortNo().getShortPortNumber());
363 }
Saurav Dasfcdad072014-08-13 14:15:21 -0700364 // update counters and events
Brian O'Connorc67f9fa2014-08-07 18:17:46 -0700365 counters.switchActivated.updateCounterWithFlush();
366 evSwitch.updateEventWithFlush(new SwitchEvent(dpid, "activeMaster"));
367 addUpdateToQueue(new SwitchUpdate(dpid,
368 SwitchUpdateType.ACTIVATED_MASTER));
369 return true;
370 }
371
372 /**
373 * Called when a switch is activated, with this controller's role as EQUAL
374 */
375 protected boolean addActivatedEqualSwitch(long dpid, IOFSwitch sw) {
Saurav Dasfcdad072014-08-13 14:15:21 -0700376 synchronized (multiCacheLock) {
377 if (!validActivation(dpid))
378 return false;
Brian O'Connorc67f9fa2014-08-07 18:17:46 -0700379 activeEqualSwitches.put(dpid, sw);
380 }
Saurav Dasfcdad072014-08-13 14:15:21 -0700381 // update counters and events
Brian O'Connorc67f9fa2014-08-07 18:17:46 -0700382 counters.switchActivated.updateCounterWithFlush();
383 evSwitch.updateEventWithFlush(new SwitchEvent(dpid, "activeEqual"));
384 addUpdateToQueue(new SwitchUpdate(dpid,
385 SwitchUpdateType.ACTIVATED_EQUAL));
386 return true;
387 }
388
389 /**
Saurav Dasfcdad072014-08-13 14:15:21 -0700390 * Called when this controller's role for a switch transitions from equal to
391 * master. For 1.0 switches, we internally refer to the role 'slave' as
Brian O'Connorc67f9fa2014-08-07 18:17:46 -0700392 * 'equal' - so this transition is equivalent to 'addActivatedMasterSwitch'.
393 */
394 protected void transitionToMasterSwitch(long dpid) {
Saurav Dasfcdad072014-08-13 14:15:21 -0700395 synchronized (multiCacheLock) {
396 IOFSwitch sw = activeEqualSwitches.remove(dpid);
397 if (sw == null) {
398 log.error("Transition to master called on sw {}, but switch "
399 + "was not found in controller-cache", dpid);
400 return;
401 }
402 activeMasterSwitches.put(dpid, sw);
403 }
404 addUpdateToQueue(new SwitchUpdate(dpid,
Brian O'Connorc67f9fa2014-08-07 18:17:46 -0700405 SwitchUpdateType.EQUAL_TO_MASTER));
406 }
407
Brian O'Connorc67f9fa2014-08-07 18:17:46 -0700408 /**
Saurav Dasfcdad072014-08-13 14:15:21 -0700409 * Called when this controller's role for a switch transitions to equal. For
410 * 1.0 switches, we internally refer to the role 'slave' as 'equal'.
Brian O'Connorc67f9fa2014-08-07 18:17:46 -0700411 */
412 protected void transitionToEqualSwitch(long dpid) {
Saurav Dasfcdad072014-08-13 14:15:21 -0700413 synchronized (multiCacheLock) {
414 IOFSwitch sw = activeMasterSwitches.remove(dpid);
415 if (sw == null) {
416 log.error("Transition to equal called on sw {}, but switch "
417 + "was not found in controller-cache", dpid);
418 return;
419 }
420 activeEqualSwitches.put(dpid, sw);
421 }
422 addUpdateToQueue(new SwitchUpdate(dpid,
Brian O'Connorc67f9fa2014-08-07 18:17:46 -0700423 SwitchUpdateType.MASTER_TO_EQUAL));
424 }
425
426 /**
427 * Clear all state in controller switch maps for a switch that has
Saurav Dasfcdad072014-08-13 14:15:21 -0700428 * disconnected from the local controller. Also release control for that
429 * switch from the global repository. Notify switch listeners.
Brian O'Connorc67f9fa2014-08-07 18:17:46 -0700430 */
431 protected void removeConnectedSwitch(long dpid) {
432 releaseRegistryControl(dpid);
433 connectedSwitches.remove(dpid);
434 IOFSwitch sw = activeMasterSwitches.remove(dpid);
Saurav Dasfcdad072014-08-13 14:15:21 -0700435 if (sw == null) {
436 sw = activeEqualSwitches.remove(dpid);
437 }
Brian O'Connorc67f9fa2014-08-07 18:17:46 -0700438 if (sw != null) {
439 sw.cancelAllStatisticsReplies();
440 sw.setConnected(false); // do we need this?
441 }
442 evSwitch.updateEventWithFlush(new SwitchEvent(dpid, "disconnected"));
443 counters.switchDisconnected.updateCounterWithFlush();
444 addUpdateToQueue(new SwitchUpdate(dpid, SwitchUpdateType.DISCONNECTED));
445 }
446
447 /**
Saurav Dasfcdad072014-08-13 14:15:21 -0700448 * Indicates that ports on the given switch have changed. Enqueue a switch
449 * update.
Jonathan Hartcb34f382014-08-12 21:11:03 -0700450 *
Brian O'Connorc67f9fa2014-08-07 18:17:46 -0700451 * @param sw
452 */
453 protected void notifyPortChanged(long dpid, OFPortDesc port,
454 PortChangeType changeType) {
455 if (port == null || changeType == null) {
456 String msg = String.format("Switch port or changetType must not "
457 + "be null in port change notification");
458 throw new NullPointerException(msg);
459 }
460 if (connectedSwitches.get(dpid) == null || getSwitch(dpid) == null) {
461 log.warn("Port change update on switch {} not connected or activated "
462 + "... Aborting.", HexString.toHexString(dpid));
463 return;
464 }
465
466 if (changeType == PortChangeType.ADD) {
467 // XXX Workaround to prevent race condition where a link is detected
468 // and attempted to be written to the database before the port is in
469 // the database. We now suppress link discovery on ports until we're
470 // sure they're in the database.
Saurav Dasfcdad072014-08-13 14:15:21 -0700471 linkDiscovery.disableDiscoveryOnPort(dpid, port.getPortNo()
472 .getShortPortNumber());
Brian O'Connorc67f9fa2014-08-07 18:17:46 -0700473 }
474
475 SwitchUpdate update = new SwitchUpdate(dpid, SwitchUpdateType.PORTCHANGED,
476 port, changeType);
477 addUpdateToQueue(update);
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -0800478 }
Ray Milkey269ffb92014-04-03 14:43:30 -0700479
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -0800480 // ***************
481 // Getters/Setters
Brian O'Connorc67f9fa2014-08-07 18:17:46 -0700482 // ***************
Ray Milkey269ffb92014-04-03 14:43:30 -0700483
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -0800484 public void setRestApiService(IRestApiService restApi) {
485 this.restApi = restApi;
486 }
Ray Milkey269ffb92014-04-03 14:43:30 -0700487
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -0800488 public void setThreadPoolService(IThreadPoolService tp) {
489 this.threadPool = tp;
490 }
491
Ray Milkey269ffb92014-04-03 14:43:30 -0700492 public void setMastershipService(IControllerRegistryService serviceImpl) {
493 this.registryService = serviceImpl;
Pankaj Berdedc73bb12013-08-14 13:46:38 -0700494 }
Ray Milkey269ffb92014-04-03 14:43:30 -0700495
496 public void setLinkDiscoveryService(ILinkDiscoveryService linkDiscovery) {
497 this.linkDiscovery = linkDiscovery;
498 }
499
Brian O'Connorc67f9fa2014-08-07 18:17:46 -0700500 public void setDebugCounter(IDebugCounterService debugCounters) {
501 this.debugCounters = debugCounters;
502 }
503
504 public void setDebugEvent(IDebugEventService debugEvents) {
505 this.debugEvents = debugEvents;
506 }
507
508 IDebugCounterService getDebugCounter() {
509 return this.debugCounters;
Ray Milkey269ffb92014-04-03 14:43:30 -0700510 }
511
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -0800512 // **********************
Brian O'Connorc67f9fa2014-08-07 18:17:46 -0700513 // Role Handling
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -0800514 // **********************
Ray Milkey269ffb92014-04-03 14:43:30 -0700515
Saurav Dasfcdad072014-08-13 14:15:21 -0700516 /**
517 * created by ONOS - works with registry service
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -0800518 */
Jonathan Hartcc957a02013-02-26 10:39:04 -0800519 protected class RoleChangeCallback implements ControlChangeCallback {
Ray Milkey269ffb92014-04-03 14:43:30 -0700520 @Override
Pavlin Radoslavov695f8952014-07-23 16:57:01 -0700521 public void controlChanged(long dpidLong, boolean hasControl) {
522 Dpid dpid = new Dpid(dpidLong);
Ray Milkey269ffb92014-04-03 14:43:30 -0700523 log.info("Role change callback for switch {}, hasControl {}",
Brian O'Connorc67f9fa2014-08-07 18:17:46 -0700524 dpid, hasControl);
Pankaj Berde01939e92013-03-08 14:38:27 -0800525
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -0800526 Role role = null;
Ray Milkey269ffb92014-04-03 14:43:30 -0700527
Brian O'Connorc67f9fa2014-08-07 18:17:46 -0700528 /*
529 * issue #229
530 * Cannot rely on sw.getRole() as it can be behind due to pending
531 * role changes in the queue. Just submit it and late the
532 * RoleChanger handle duplicates.
533 */
Ray Milkey269ffb92014-04-03 14:43:30 -0700534
Brian O'Connorc67f9fa2014-08-07 18:17:46 -0700535 if (hasControl) {
536 role = Role.MASTER;
Ray Milkey269ffb92014-04-03 14:43:30 -0700537 } else {
Brian O'Connorc67f9fa2014-08-07 18:17:46 -0700538 role = Role.EQUAL; // treat the same as Role.SLAVE
Ray Milkey269ffb92014-04-03 14:43:30 -0700539 }
Ray Milkey269ffb92014-04-03 14:43:30 -0700540
Brian O'Connorc67f9fa2014-08-07 18:17:46 -0700541 OFChannelHandler swCh = connectedSwitches.get(dpid.value());
542 if (swCh == null) {
543 log.warn("Switch {} not found in connected switches", dpid);
544 return;
Pankaj Berde465ac7c2013-05-23 13:47:49 -0700545 }
Brian O'Connorc67f9fa2014-08-07 18:17:46 -0700546
547 log.debug("Sending role request {} msg to {}", role, dpid);
548 swCh.sendRoleRequest(role, RoleRecvStatus.MATCHED_SET_ROLE);
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -0800549 }
Brian O'Connorc67f9fa2014-08-07 18:17:46 -0700550 }
551
552 public synchronized void submitRegistryRequest(long dpid) {
553 OFChannelHandler h = connectedSwitches.get(dpid);
554 if (h == null) {
555 log.error("Trying to request registry control for switch {} "
556 + "not in connected switches. Aborting.. ",
557 HexString.toHexString(dpid));
558 // FIXME shouldn't we immediately return here?
559 }
Saurav Dasfcdad072014-08-13 14:15:21 -0700560 // Request control of the switch from the global registry
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -0800561 try {
Brian O'Connorc67f9fa2014-08-07 18:17:46 -0700562 h.controlRequested = Boolean.TRUE;
563 registryService.requestControl(dpid, new RoleChangeCallback());
564 } catch (RegistryException e) {
565 log.debug("Registry error: {}", e.getMessage());
566 h.controlRequested = Boolean.FALSE;
567 }
568 if (!h.controlRequested) { // XXX what is being attempted here?
569 // yield to allow other thread(s) to release control
570 try {
571 Thread.sleep(10);
572 } catch (InterruptedException e) {
573 // Ignore interruptions
574 }
Saurav Dasfcdad072014-08-13 14:15:21 -0700575 // safer to bounce the switch to reconnect here than proceeding
576 // further
Brian O'Connorc67f9fa2014-08-07 18:17:46 -0700577 // XXX S why? can't we just try again a little later?
578 log.debug("Closing sw:{} because we weren't able to request control " +
579 "successfully" + dpid);
580 connectedSwitches.get(dpid).disconnectSwitch();
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -0800581 }
582 }
Ray Milkey269ffb92014-04-03 14:43:30 -0700583
Brian O'Connorc67f9fa2014-08-07 18:17:46 -0700584 public synchronized void releaseRegistryControl(long dpidLong) {
585 OFChannelHandler h = connectedSwitches.get(dpidLong);
586 if (h == null) {
587 log.error("Trying to release registry control for switch {} "
588 + "not in connected switches. Aborting.. ",
589 HexString.toHexString(dpidLong));
590 return;
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -0800591 }
Brian O'Connorc67f9fa2014-08-07 18:17:46 -0700592 if (h.controlRequested) {
593 registryService.releaseControl(dpidLong);
594 }
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -0800595 }
596
Brian O'Connorc67f9fa2014-08-07 18:17:46 -0700597 // *******************
598 // OF Message Handling
599 // *******************
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -0800600
601 /**
Brian O'Connorc67f9fa2014-08-07 18:17:46 -0700602 * Handle and dispatch a message to IOFMessageListeners.
Jonathan Hartcb34f382014-08-12 21:11:03 -0700603 *
Saurav Dasfcdad072014-08-13 14:15:21 -0700604 * We only dispatch messages to listeners if the controller's role is
605 * MASTER.
Jonathan Hartcb34f382014-08-12 21:11:03 -0700606 *
Brian O'Connorc67f9fa2014-08-07 18:17:46 -0700607 * @param sw The switch sending the message
608 * @param m The message the switch sent
Saurav Dasfcdad072014-08-13 14:15:21 -0700609 * @param flContext The floodlight context to use for this message. If null,
610 * a new context will be allocated.
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -0800611 * @throws IOException
Jonathan Hartcb34f382014-08-12 21:11:03 -0700612 *
Saurav Dasfcdad072014-08-13 14:15:21 -0700613 * FIXME: this method and the ChannelHandler disagree on which
614 * messages should be dispatched and which shouldn't
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -0800615 */
616 @LogMessageDocs({
Ray Milkey269ffb92014-04-03 14:43:30 -0700617 @LogMessageDoc(level = "ERROR",
618 message = "Ignoring PacketIn (Xid = {xid}) because the data" +
619 " field is empty.",
620 explanation = "The switch sent an improperly-formatted PacketIn" +
621 " message",
622 recommendation = LogMessageDoc.CHECK_SWITCH),
623 @LogMessageDoc(level = "WARN",
624 message = "Unhandled OF Message: {} from {}",
625 explanation = "The switch sent a message not handled by " +
626 "the controller")
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -0800627 })
Saurav Dasfcdad072014-08-13 14:15:21 -0700628 @SuppressWarnings({"fallthrough", "unchecked"})
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -0800629 protected void handleMessage(IOFSwitch sw, OFMessage m,
Saurav Dasfcdad072014-08-13 14:15:21 -0700630 FloodlightContext bContext)
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -0800631 throws IOException {
632 Ethernet eth = null;
Brian O'Connorc67f9fa2014-08-07 18:17:46 -0700633 short inport = -1;
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -0800634
635 switch (m.getType()) {
Saurav Dasfcdad072014-08-13 14:15:21 -0700636 case PACKET_IN:
637 OFPacketIn pi = (OFPacketIn) m;
638 // log.info("saw packet in from sw {}", sw.getStringId());
639 if (pi.getData().length <= 0) {
640 log.error("Ignoring PacketIn (Xid = " + pi.getXid() +
641 ") because/* the data field is empty.");
642 return;
643 }
644
645 // get incoming port to store in floodlight context
646 if (sw.getOFVersion() == OFVersion.OF_10) {
647 inport = pi.getInPort().getShortPortNumber();
648 } else if (sw.getOFVersion() == OFVersion.OF_13) {
649 for (MatchField<?> mf : pi.getMatch().getMatchFields()) {
650 if (mf.id == MatchFields.IN_PORT) {
651 inport = pi.getMatch().get((MatchField<OFPort>) mf)
652 .getShortPortNumber();
653 break;
654 }
655 }
656 if (inport == -1) {
657 log.error("Match field for incoming port missing in "
658 + "packet-in from sw {}. Ignoring msg",
659 sw.getStringId());
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -0800660 return;
661 }
Saurav Dasfcdad072014-08-13 14:15:21 -0700662 } else {
663 // should have been taken care of earlier in handshake
664 log.error("OFVersion {} not supported for "
665 + "packet-in from sw {}. Ignoring msg",
666 sw.getOFVersion(), sw.getStringId());
667 return;
668 }
Ray Milkey269ffb92014-04-03 14:43:30 -0700669
Saurav Dasfcdad072014-08-13 14:15:21 -0700670 // decode enclosed ethernet packet to store in floodlight context
671 if (Controller.ALWAYS_DECODE_ETH) {
672 eth = new Ethernet();
673 eth.deserialize(pi.getData(), 0,
674 pi.getData().length);
675 }
676 // fall through to default case...
677
678 /*log.debug("Sw:{} packet-in: {}", sw.getStringId(),
679 String.format("0x%x", eth.getEtherType()));*/
680 if (eth.getEtherType() != (short) EthType.LLDP.getValue())
681 log.trace("Sw:{} packet-in: {}", sw.getStringId(), pi);
682
683 default:
684
685 List<IOFMessageListener> listeners = null;
686
687 if (messageListeners.containsKey(m.getType())) {
688 listeners = messageListeners.get(m.getType()).
689 getOrderedListeners();
690 }
691 FloodlightContext bc = null;
692 if (listeners != null) {
693 // Check if floodlight context is passed from the calling
694 // function, if so use that floodlight context, otherwise
695 // allocate one
696 if (bContext == null) {
697 bc = flcontext_alloc();
Brian O'Connorc67f9fa2014-08-07 18:17:46 -0700698 } else {
Saurav Dasfcdad072014-08-13 14:15:21 -0700699 bc = bContext;
700 }
701 if (eth != null) {
702 IFloodlightProviderService.bcStore.put(bc,
703 IFloodlightProviderService.CONTEXT_PI_PAYLOAD,
704 eth);
705 }
706 if (inport != -1) {
707 bc.getStorage().put(
708 IFloodlightProviderService.CONTEXT_PI_INPORT,
709 inport);
Brian O'Connorc67f9fa2014-08-07 18:17:46 -0700710 }
711
Saurav Dasfcdad072014-08-13 14:15:21 -0700712 // Get the starting time (overall and per-component) of
713 // the processing chain for this packet if performance
714 // monitoring is turned on
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -0800715
Saurav Dasfcdad072014-08-13 14:15:21 -0700716 Command cmd = null;
717 for (IOFMessageListener listener : listeners) {
718 if (listener instanceof IOFSwitchFilter) {
719 if (!((IOFSwitchFilter) listener).isInterested(sw)) {
720 continue;
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -0800721 }
722 }
mininet73e7fb72013-12-03 14:25:53 -0800723
Saurav Dasfcdad072014-08-13 14:15:21 -0700724 cmd = listener.receive(sw, m, bc);
725
726 if (Command.STOP.equals(cmd)) {
727 break;
728 }
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -0800729 }
Ray Milkey269ffb92014-04-03 14:43:30 -0700730
Saurav Dasfcdad072014-08-13 14:15:21 -0700731 } else {
732 log.warn("Unhandled OF Message: {} from {}", m, sw);
733 }
734
735 if ((bContext == null) && (bc != null))
736 flcontext_free(bc);
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -0800737 }
738 }
Ray Milkey269ffb92014-04-03 14:43:30 -0700739
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -0800740 // ***************
Brian O'Connorc67f9fa2014-08-07 18:17:46 -0700741 // IFloodlightProviderService
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -0800742 // ***************
Ray Milkey269ffb92014-04-03 14:43:30 -0700743
Brian O'Connorc67f9fa2014-08-07 18:17:46 -0700744 // FIXME: remove this method
745 @Override
Saurav Dasfcdad072014-08-13 14:15:21 -0700746 public Map<Long, IOFSwitch> getSwitches() {
Brian O'Connorc67f9fa2014-08-07 18:17:46 -0700747 return getMasterSwitches();
748 }
749
750 // FIXME: remove this method
751 public Map<Long, IOFSwitch> getMasterSwitches() {
752 return Collections.unmodifiableMap(activeMasterSwitches);
753 }
754
Brian O'Connorc67f9fa2014-08-07 18:17:46 -0700755 @Override
756 public Set<Long> getAllSwitchDpids() {
757 Set<Long> dpids = new HashSet<Long>();
758 dpids.addAll(activeMasterSwitches.keySet());
759 dpids.addAll(activeEqualSwitches.keySet());
760 return dpids;
761 }
762
763 @Override
764 public Set<Long> getAllMasterSwitchDpids() {
765 Set<Long> dpids = new HashSet<Long>();
766 dpids.addAll(activeMasterSwitches.keySet());
767 return dpids;
768 }
769
770 @Override
771 public Set<Long> getAllEqualSwitchDpids() {
772 Set<Long> dpids = new HashSet<Long>();
773 dpids.addAll(activeEqualSwitches.keySet());
774 return dpids;
775 }
776
777 @Override
778 public IOFSwitch getSwitch(long dpid) {
779 IOFSwitch sw = null;
Saurav Dasfcdad072014-08-13 14:15:21 -0700780 if ((sw = activeMasterSwitches.get(dpid)) != null)
781 return sw;
782 if ((sw = activeEqualSwitches.get(dpid)) != null)
783 return sw;
Brian O'Connorc67f9fa2014-08-07 18:17:46 -0700784 return sw;
785 }
786
787 @Override
788 public IOFSwitch getMasterSwitch(long dpid) {
Saurav Dasfcdad072014-08-13 14:15:21 -0700789 return activeMasterSwitches.get(dpid);
Brian O'Connorc67f9fa2014-08-07 18:17:46 -0700790 }
791
792 @Override
793 public IOFSwitch getEqualSwitch(long dpid) {
Saurav Dasfcdad072014-08-13 14:15:21 -0700794 return activeEqualSwitches.get(dpid);
Brian O'Connorc67f9fa2014-08-07 18:17:46 -0700795 }
796
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -0800797 @Override
Ray Milkey269ffb92014-04-03 14:43:30 -0700798 public synchronized void addOFMessageListener(OFType type,
Saurav Dasfcdad072014-08-13 14:15:21 -0700799 IOFMessageListener listener) {
Ray Milkey269ffb92014-04-03 14:43:30 -0700800 ListenerDispatcher<OFType, IOFMessageListener> ldd =
801 messageListeners.get(type);
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -0800802 if (ldd == null) {
803 ldd = new ListenerDispatcher<OFType, IOFMessageListener>();
804 messageListeners.put(type, ldd);
805 }
806 ldd.addListener(type, listener);
807 }
808
809 @Override
810 public synchronized void removeOFMessageListener(OFType type,
Saurav Dasfcdad072014-08-13 14:15:21 -0700811 IOFMessageListener listener) {
Ray Milkey269ffb92014-04-03 14:43:30 -0700812 ListenerDispatcher<OFType, IOFMessageListener> ldd =
813 messageListeners.get(type);
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -0800814 if (ldd != null) {
815 ldd.removeListener(listener);
816 }
817 }
Ray Milkey269ffb92014-04-03 14:43:30 -0700818
Brian O'Connorc67f9fa2014-08-07 18:17:46 -0700819 public void removeOFMessageListeners(OFType type) {
820 messageListeners.remove(type);
821 }
822
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -0800823 private void logListeners() {
Saurav Dasfcdad072014-08-13 14:15:21 -0700824 for (Map.Entry<OFType, ListenerDispatcher<OFType, IOFMessageListener>> entry : messageListeners
825 .entrySet()) {
Ray Milkey269ffb92014-04-03 14:43:30 -0700826
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -0800827 OFType type = entry.getKey();
Ray Milkey269ffb92014-04-03 14:43:30 -0700828 ListenerDispatcher<OFType, IOFMessageListener> ldd =
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -0800829 entry.getValue();
Ray Milkey269ffb92014-04-03 14:43:30 -0700830
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -0800831 StringBuffer sb = new StringBuffer();
Brian O'Connorc67f9fa2014-08-07 18:17:46 -0700832 sb.append("OFMessageListeners for ");
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -0800833 sb.append(type);
834 sb.append(": ");
835 for (IOFMessageListener l : ldd.getOrderedListeners()) {
836 sb.append(l.getName());
837 sb.append(",");
838 }
Ray Milkey269ffb92014-04-03 14:43:30 -0700839 log.debug(sb.toString());
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -0800840 }
Brian O'Connorc67f9fa2014-08-07 18:17:46 -0700841 StringBuffer sl = new StringBuffer();
842 sl.append("SwitchUpdate Listeners: ");
843 for (IOFSwitchListener swlistener : switchListeners) {
844 sl.append(swlistener.getName());
845 sl.append(",");
846 }
847 log.debug(sl.toString());
Ray Milkey269ffb92014-04-03 14:43:30 -0700848
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -0800849 }
850
851 @Override
852 public void addOFSwitchListener(IOFSwitchListener listener) {
853 this.switchListeners.add(listener);
854 }
855
856 @Override
857 public void removeOFSwitchListener(IOFSwitchListener listener) {
858 this.switchListeners.remove(listener);
859 }
860
861 @Override
862 public Map<OFType, List<IOFMessageListener>> getListeners() {
Ray Milkey269ffb92014-04-03 14:43:30 -0700863 Map<OFType, List<IOFMessageListener>> lers =
864 new HashMap<OFType, List<IOFMessageListener>>();
Saurav Dasfcdad072014-08-13 14:15:21 -0700865 for (Entry<OFType, ListenerDispatcher<OFType, IOFMessageListener>> e : messageListeners
866 .entrySet()) {
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -0800867 lers.put(e.getKey(), e.getValue().getOrderedListeners());
868 }
869 return Collections.unmodifiableMap(lers);
870 }
Ray Milkey269ffb92014-04-03 14:43:30 -0700871
Brian O'Connorc67f9fa2014-08-07 18:17:46 -0700872 /*@Override
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -0800873 @LogMessageDocs({
Ray Milkey269ffb92014-04-03 14:43:30 -0700874 @LogMessageDoc(message = "Failed to inject OFMessage {message} onto " +
875 "a null switch",
876 explanation = "Failed to process a message because the switch " +
877 " is no longer connected."),
878 @LogMessageDoc(level = "ERROR",
879 message = "Error reinjecting OFMessage on switch {switch}",
880 explanation = "An I/O error occured while attempting to " +
881 "process an OpenFlow message",
882 recommendation = LogMessageDoc.CHECK_SWITCH)
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -0800883 })
884 public boolean injectOfMessage(IOFSwitch sw, OFMessage msg,
885 FloodlightContext bc) {
886 if (sw == null) {
887 log.info("Failed to inject OFMessage {} onto a null switch", msg);
888 return false;
889 }
Ray Milkey269ffb92014-04-03 14:43:30 -0700890
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -0800891 // FIXME: Do we need to be able to inject messages to switches
892 // where we're the slave controller (i.e. they're connected but
893 // not active)?
894 // FIXME: Don't we need synchronization logic here so we're holding
895 // the listener read lock when we call handleMessage? After some
896 // discussions it sounds like the right thing to do here would be to
897 // inject the message as a netty upstream channel event so it goes
898 // through the normal netty event processing, including being
Brian O'Connorc67f9fa2014-08-07 18:17:46 -0700899 // handled
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -0800900 if (!activeSwitches.containsKey(sw.getId())) return false;
Ray Milkey269ffb92014-04-03 14:43:30 -0700901
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -0800902 try {
903 // Pass Floodlight context to the handleMessages()
904 handleMessage(sw, msg, bc);
905 } catch (IOException e) {
Ray Milkey269ffb92014-04-03 14:43:30 -0700906 log.error("Error reinjecting OFMessage on switch {}",
907 HexString.toHexString(sw.getId()));
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -0800908 return false;
909 }
910 return true;
Brian O'Connorc67f9fa2014-08-07 18:17:46 -0700911 }*/
912
Saurav Dasfcdad072014-08-13 14:15:21 -0700913 // @Override
914 // public boolean injectOfMessage(IOFSwitch sw, OFMessage msg) {
915 // // call the overloaded version with floodlight context set to null
916 // return injectOfMessage(sw, msg, null);
917 // }
Brian O'Connorc67f9fa2014-08-07 18:17:46 -0700918
Saurav Dasfcdad072014-08-13 14:15:21 -0700919 // @Override
920 // public void handleOutgoingMessage(IOFSwitch sw, OFMessage m,
921 // FloodlightContext bc) {
922 //
923 // List<IOFMessageListener> listeners = null;
924 // if (messageListeners.containsKey(m.getType())) {
925 // listeners =
926 // messageListeners.get(m.getType()).getOrderedListeners();
927 // }
928 //
929 // if (listeners != null) {
930 // for (IOFMessageListener listener : listeners) {
931 // if (listener instanceof IOFSwitchFilter) {
932 // if (!((IOFSwitchFilter) listener).isInterested(sw)) {
933 // continue;
934 // }
935 // }
936 // if (Command.STOP.equals(listener.receive(sw, m, bc))) {
937 // break;
938 // }
939 // }
940 // }
941 // }
Jonathan Harta213bce2014-08-11 15:44:07 -0700942
943 /**
944 * Gets an OpenFlow message factory for version 1.0.
Jonathan Hartcb34f382014-08-12 21:11:03 -0700945 *
Jonathan Harta213bce2014-08-11 15:44:07 -0700946 * @return an OpenFlow 1.0 message factory
947 */
Brian O'Connorc67f9fa2014-08-07 18:17:46 -0700948 public OFFactory getOFMessageFactory_10() {
949 return factory10;
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -0800950 }
951
Jonathan Harta213bce2014-08-11 15:44:07 -0700952 /**
953 * Gets an OpenFlow message factory for version 1.3.
Jonathan Hartcb34f382014-08-12 21:11:03 -0700954 *
Jonathan Harta213bce2014-08-11 15:44:07 -0700955 * @return an OpenFlow 1.3 message factory
956 */
Brian O'Connorc67f9fa2014-08-07 18:17:46 -0700957 public OFFactory getOFMessageFactory_13() {
958 return factory13;
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -0800959 }
Ray Milkey269ffb92014-04-03 14:43:30 -0700960
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -0800961 @Override
Brian O'Connorc67f9fa2014-08-07 18:17:46 -0700962 public void publishUpdate(IUpdate update) {
963 try {
964 this.updates.put(update);
965 } catch (InterruptedException e) {
966 log.error("Failure adding update to queue", e);
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -0800967 }
968 }
969
970 @Override
Brian O'Connorc67f9fa2014-08-07 18:17:46 -0700971 public Map<String, String> getControllerNodeIPs() {
972 // We return a copy of the mapping so we can guarantee that
973 // the mapping return is the same as one that will be (or was)
974 // dispatched to IHAListeners
975 HashMap<String, String> retval = new HashMap<String, String>();
976 synchronized (controllerNodeIPsCache) {
977 retval.putAll(controllerNodeIPsCache);
978 }
979 return retval;
980 }
981
982 @Override
983 public long getSystemStartTime() {
984 return (this.systemStartTime);
985 }
986
987 @Override
988 public void setAlwaysClearFlowsOnSwAdd(boolean value) {
989 this.alwaysClearFlowsOnSwAdd = value;
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -0800990 }
Ray Milkey269ffb92014-04-03 14:43:30 -0700991
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -0800992 @Override
Pavlin Radoslavov53b208a2014-07-28 13:16:11 -0700993 public OnosInstanceId getOnosInstanceId() {
994 return onosInstanceId;
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -0800995 }
Ray Milkey269ffb92014-04-03 14:43:30 -0700996
Brian O'Connorc67f9fa2014-08-07 18:17:46 -0700997 /**
998 * FOR TESTING ONLY. Dispatch all updates in the update queue until queue is
999 * empty
1000 */
1001 void processUpdateQueueForTesting() {
1002 while (!updates.isEmpty()) {
1003 IUpdate update = updates.poll();
1004 if (update != null)
1005 update.dispatch();
1006 }
1007 }
1008
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -08001009 // **************
1010 // Initialization
1011 // **************
1012
Brian O'Connorc67f9fa2014-08-07 18:17:46 -07001013 // XXX S This should probably go away OR it should be edited to handle
1014 // controller roles per switch! Then it could be a way to
1015 // deterministically configure a switch to a MASTER controller instance
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -08001016 /**
Saurav Dasfcdad072014-08-13 14:15:21 -07001017 * Sets the initial role based on properties in the config params. It looks
1018 * for two different properties. If the "role" property is specified then
1019 * the value should be either "EQUAL", "MASTER", or "SLAVE" and the role of
1020 * the controller is set to the specified value. If the "role" property is
1021 * not specified then it looks next for the "role.path" property. In this
1022 * case the value should be the path to a property file in the file system
1023 * that contains a property called "floodlight.role" which can be one of the
1024 * values listed above for the "role" property. The idea behind the
1025 * "role.path" mechanism is that you have some separate heartbeat and master
1026 * controller election algorithm that determines the role of the controller.
1027 * When a role transition happens, it updates the current role in the file
1028 * specified by the "role.path" file. Then if floodlight restarts for some
1029 * reason it can get the correct current role of the controller from the
1030 * file.
Jonathan Hartcb34f382014-08-12 21:11:03 -07001031 *
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -08001032 * @param configParams The config params for the FloodlightProvider service
Saurav Dasfcdad072014-08-13 14:15:21 -07001033 * @return A valid role if role information is specified in the config
1034 * params, otherwise null
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -08001035 */
1036 @LogMessageDocs({
Ray Milkey269ffb92014-04-03 14:43:30 -07001037 @LogMessageDoc(message = "Controller role set to {role}",
1038 explanation = "Setting the initial HA role to "),
1039 @LogMessageDoc(level = "ERROR",
1040 message = "Invalid current role value: {role}",
1041 explanation = "An invalid HA role value was read from the " +
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -08001042 "properties file",
Ray Milkey269ffb92014-04-03 14:43:30 -07001043 recommendation = LogMessageDoc.CHECK_CONTROLLER)
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -08001044 })
1045 protected Role getInitialRole(Map<String, String> configParams) {
1046 Role role = null;
1047 String roleString = configParams.get("role");
Praseed Balakrishnan59469e92014-06-20 11:55:13 -07001048 FileInputStream fs = null;
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -08001049 if (roleString == null) {
1050 String rolePath = configParams.get("rolepath");
1051 if (rolePath != null) {
1052 Properties properties = new Properties();
1053 try {
Praseed Balakrishnan59469e92014-06-20 11:55:13 -07001054 fs = new FileInputStream(rolePath);
1055 properties.load(fs);
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -08001056 roleString = properties.getProperty("floodlight.role");
Ray Milkey269ffb92014-04-03 14:43:30 -07001057 } catch (IOException exc) {
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -08001058 // Don't treat it as an error if the file specified by the
1059 // rolepath property doesn't exist. This lets us enable the
1060 // HA mechanism by just creating/setting the floodlight.role
1061 // property in that file without having to modify the
1062 // floodlight properties.
Praseed Balakrishnan59469e92014-06-20 11:55:13 -07001063 } finally {
1064 if (fs != null) {
1065 try {
1066 fs.close();
1067 } catch (IOException e) {
1068 log.error("Exception while closing resource ", e);
1069 }
1070 }
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -08001071 }
1072 }
1073 }
Ray Milkey269ffb92014-04-03 14:43:30 -07001074
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -08001075 if (roleString != null) {
1076 // Canonicalize the string to the form used for the enum constants
1077 roleString = roleString.trim().toUpperCase();
1078 try {
1079 role = Role.valueOf(roleString);
Ray Milkey269ffb92014-04-03 14:43:30 -07001080 } catch (IllegalArgumentException exc) {
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -08001081 log.error("Invalid current role value: {}", roleString);
1082 }
1083 }
Ray Milkey269ffb92014-04-03 14:43:30 -07001084
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -08001085 log.info("Controller role set to {}", role);
Ray Milkey269ffb92014-04-03 14:43:30 -07001086
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -08001087 return role;
1088 }
Ray Milkey269ffb92014-04-03 14:43:30 -07001089
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -08001090 /**
1091 * Tell controller that we're ready to accept switches loop
Jonathan Hartcb34f382014-08-12 21:11:03 -07001092 *
Ray Milkey269ffb92014-04-03 14:43:30 -07001093 * @throws IOException
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -08001094 */
Brian O'Connorc67f9fa2014-08-07 18:17:46 -07001095 @Override
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -08001096 @LogMessageDocs({
Ray Milkey269ffb92014-04-03 14:43:30 -07001097 @LogMessageDoc(message = "Listening for switch connections on {address}",
1098 explanation = "The controller is ready and listening for new" +
1099 " switch connections"),
1100 @LogMessageDoc(message = "Storage exception in controller " +
1101 "updates loop; terminating process",
1102 explanation = ERROR_DATABASE,
1103 recommendation = LogMessageDoc.CHECK_CONTROLLER),
1104 @LogMessageDoc(level = "ERROR",
1105 message = "Exception in controller updates loop",
1106 explanation = "Failed to dispatch controller event",
1107 recommendation = LogMessageDoc.GENERIC_ACTION)
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -08001108 })
1109 public void run() {
1110 if (log.isDebugEnabled()) {
1111 logListeners();
1112 }
Ray Milkey269ffb92014-04-03 14:43:30 -07001113
1114 try {
1115 final ServerBootstrap bootstrap = createServerBootStrap();
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -08001116
1117 bootstrap.setOption("reuseAddr", true);
1118 bootstrap.setOption("child.keepAlive", true);
1119 bootstrap.setOption("child.tcpNoDelay", true);
1120 bootstrap.setOption("child.sendBufferSize", Controller.SEND_BUFFER_SIZE);
1121
Ray Milkey269ffb92014-04-03 14:43:30 -07001122 ChannelPipelineFactory pfact =
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -08001123 new OpenflowPipelineFactory(this, null);
1124 bootstrap.setPipelineFactory(pfact);
1125 InetSocketAddress sa = new InetSocketAddress(openFlowPort);
1126 final ChannelGroup cg = new DefaultChannelGroup();
1127 cg.add(bootstrap.bind(sa));
Ray Milkey269ffb92014-04-03 14:43:30 -07001128
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -08001129 log.info("Listening for switch connections on {}", sa);
1130 } catch (Exception e) {
1131 throw new RuntimeException(e);
1132 }
1133
1134 // main loop
1135 while (true) {
1136 try {
1137 IUpdate update = updates.take();
1138 update.dispatch();
1139 } catch (InterruptedException e) {
Brian O'Connorc67f9fa2014-08-07 18:17:46 -07001140 log.error("Received interrupted exception in updates loop;" +
Saurav Dasfcdad072014-08-13 14:15:21 -07001141 "terminating process");
Brian O'Connorc67f9fa2014-08-07 18:17:46 -07001142 terminate();
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -08001143 } catch (Exception e) {
1144 log.error("Exception in controller updates loop", e);
1145 }
1146 }
1147 }
1148
1149 private ServerBootstrap createServerBootStrap() {
1150 if (workerThreads == 0) {
1151 return new ServerBootstrap(
1152 new NioServerSocketChannelFactory(
1153 Executors.newCachedThreadPool(),
1154 Executors.newCachedThreadPool()));
1155 } else {
1156 return new ServerBootstrap(
1157 new NioServerSocketChannelFactory(
1158 Executors.newCachedThreadPool(),
1159 Executors.newCachedThreadPool(), workerThreads));
1160 }
1161 }
Ray Milkey269ffb92014-04-03 14:43:30 -07001162
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -08001163 public void setConfigParams(Map<String, String> configParams) {
1164 String ofPort = configParams.get("openflowport");
1165 if (ofPort != null) {
1166 this.openFlowPort = Integer.parseInt(ofPort);
1167 }
1168 log.debug("OpenFlow port set to {}", this.openFlowPort);
1169 String threads = configParams.get("workerthreads");
1170 if (threads != null) {
1171 this.workerThreads = Integer.parseInt(threads);
1172 }
1173 log.debug("Number of worker threads set to {}", this.workerThreads);
1174 String controllerId = configParams.get("controllerid");
1175 if (controllerId != null) {
Pavlin Radoslavov53b208a2014-07-28 13:16:11 -07001176 this.onosInstanceId = new OnosInstanceId(controllerId);
Ray Milkey269ffb92014-04-03 14:43:30 -07001177 } else {
Saurav Dasfcdad072014-08-13 14:15:21 -07001178 // Try to get the hostname of the machine and use that for
1179 // controller ID
Ray Milkey269ffb92014-04-03 14:43:30 -07001180 try {
1181 String hostname = java.net.InetAddress.getLocalHost().getHostName();
Pavlin Radoslavov53b208a2014-07-28 13:16:11 -07001182 this.onosInstanceId = new OnosInstanceId(hostname);
Ray Milkey269ffb92014-04-03 14:43:30 -07001183 } catch (UnknownHostException e) {
1184 // Can't get hostname, we'll just use the default
1185 }
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -08001186 }
Ray Milkey269ffb92014-04-03 14:43:30 -07001187
Pavlin Radoslavov53b208a2014-07-28 13:16:11 -07001188 log.debug("ControllerId set to {}", this.onosInstanceId);
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -08001189 }
1190
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -08001191 /**
1192 * Initialize internal data structures
1193 */
1194 public void init(Map<String, String> configParams) {
1195 // These data structures are initialized here because other
1196 // module's startUp() might be called before ours
1197 this.messageListeners =
Brian O'Connorc67f9fa2014-08-07 18:17:46 -07001198 new ConcurrentHashMap<OFType, ListenerDispatcher<OFType,
Saurav Dasfcdad072014-08-13 14:15:21 -07001199 IOFMessageListener>>();
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -08001200 this.switchListeners = new CopyOnWriteArraySet<IOFSwitchListener>();
Brian O'Connorc67f9fa2014-08-07 18:17:46 -07001201 this.activeMasterSwitches = new ConcurrentHashMap<Long, IOFSwitch>();
1202 this.activeEqualSwitches = new ConcurrentHashMap<Long, IOFSwitch>();
1203 this.connectedSwitches = new ConcurrentHashMap<Long, OFChannelHandler>();
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -08001204 this.controllerNodeIPsCache = new HashMap<String, String>();
1205 this.updates = new LinkedBlockingQueue<IUpdate>();
Brian O'Connorc67f9fa2014-08-07 18:17:46 -07001206
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -08001207 setConfigParams(configParams);
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -08001208 this.systemStartTime = System.currentTimeMillis();
Brian O'Connorc67f9fa2014-08-07 18:17:46 -07001209 this.counters = new Counters();
1210 this.multiCacheLock = new Object();
1211
1212 String option = configParams.get("flushSwitchesOnReconnect");
1213 if (option != null && option.equalsIgnoreCase("true")) {
1214 this.setAlwaysClearFlowsOnSwActivate(true);
1215 log.info("Flush switches on reconnect -- Enabled.");
1216 } else {
1217 this.setAlwaysClearFlowsOnSwActivate(false);
1218 log.info("Flush switches on reconnect -- Disabled");
1219 }
Jonathan Hartcb34f382014-08-12 21:11:03 -07001220
1221 option = configParams.get("cpqdUsePipeline13");
1222 if (option != null && option.equalsIgnoreCase("true")) {
1223 DriverManager.setConfigForCpqd(true);
1224 log.info("Using OF1.3 pipeline for the CPqD software switch");
1225 } else {
1226 log.info("Using OF1.0 pipeline for the CPqD software switch");
1227 }
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -08001228 }
Ray Milkey269ffb92014-04-03 14:43:30 -07001229
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -08001230 /**
1231 * Startup all of the controller's components
Jonathan Hartcb34f382014-08-12 21:11:03 -07001232 *
Brian O'Connorc67f9fa2014-08-07 18:17:46 -07001233 * @throws FloodlightModuleException
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -08001234 */
Ray Milkey269ffb92014-04-03 14:43:30 -07001235 @LogMessageDoc(message = "Waiting for storage source",
1236 explanation = "The system database is not yet ready",
1237 recommendation = "If this message persists, this indicates " +
1238 "that the system database has failed to start. " +
1239 LogMessageDoc.CHECK_CONTROLLER)
Brian O'Connorc67f9fa2014-08-07 18:17:46 -07001240 public void startupComponents() throws FloodlightModuleException {
Ray Milkey269ffb92014-04-03 14:43:30 -07001241 try {
Pavlin Radoslavov53b208a2014-07-28 13:16:11 -07001242 registryService.registerController(onosInstanceId.toString());
Ray Milkey269ffb92014-04-03 14:43:30 -07001243 } catch (RegistryException e) {
1244 log.warn("Registry service error: {}", e.getMessage());
1245 }
1246
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -08001247 // Add our REST API
1248 restApi.addRestletRoutable(new CoreWebRoutable());
Ray Milkey269ffb92014-04-03 14:43:30 -07001249
Brian O'Connorc67f9fa2014-08-07 18:17:46 -07001250 // Startup load monitoring
1251 if (overload_drop) {
1252 this.loadmonitor.startMonitoring(
Saurav Dasfcdad072014-08-13 14:15:21 -07001253 this.threadPool.getScheduledExecutor());
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -08001254 }
Brian O'Connorc67f9fa2014-08-07 18:17:46 -07001255
1256 // register counters and events
1257 try {
1258 this.counters.createCounters(debugCounters);
1259 } catch (CounterException e) {
1260 throw new FloodlightModuleException(e.getMessage());
1261 }
1262 registerControllerDebugEvents();
1263 }
1264
1265 // **************
1266 // debugCounter registrations
1267 // **************
1268
1269 public static class Counters {
1270 public static final String prefix = "controller";
1271 public IDebugCounter setRoleEqual;
1272 public IDebugCounter setSameRole;
1273 public IDebugCounter setRoleMaster;
1274 public IDebugCounter remoteStoreNotification;
1275 public IDebugCounter invalidPortsChanged;
1276 public IDebugCounter invalidSwitchActivatedWhileSlave;
1277 public IDebugCounter invalidStoreEventWhileMaster;
1278 public IDebugCounter switchDisconnectedWhileSlave;
1279 public IDebugCounter switchActivated;
1280 public IDebugCounter errorSameSwitchReactivated; // err
1281 public IDebugCounter switchWithSameDpidActivated; // warn
Saurav Dasfcdad072014-08-13 14:15:21 -07001282 public IDebugCounter newSwitchActivated; // new switch
Brian O'Connorc67f9fa2014-08-07 18:17:46 -07001283 public IDebugCounter syncedSwitchActivated;
1284 public IDebugCounter readyForReconcile;
1285 public IDebugCounter newSwitchFromStore;
1286 public IDebugCounter updatedSwitchFromStore;
1287 public IDebugCounter switchDisconnected;
1288 public IDebugCounter syncedSwitchRemoved;
1289 public IDebugCounter unknownSwitchRemovedFromStore;
1290 public IDebugCounter consolidateStoreRunCount;
1291 public IDebugCounter consolidateStoreInconsistencies;
1292 public IDebugCounter storeSyncError;
1293 public IDebugCounter switchesNotReconnectingToNewMaster;
1294 public IDebugCounter switchPortChanged;
1295 public IDebugCounter switchOtherChange;
1296 public IDebugCounter dispatchMessageWhileSlave;
Saurav Dasfcdad072014-08-13 14:15:21 -07001297 public IDebugCounter dispatchMessage; // does this cnt make sense? more
1298 // specific?? per type? count
1299 // stops?
Brian O'Connorc67f9fa2014-08-07 18:17:46 -07001300 public IDebugCounter controllerNodeIpsChanged;
1301 public IDebugCounter messageReceived;
1302 public IDebugCounter messageInputThrottled;
1303 public IDebugCounter switchDisconnectReadTimeout;
1304 public IDebugCounter switchDisconnectHandshakeTimeout;
1305 public IDebugCounter switchDisconnectIOError;
1306 public IDebugCounter switchDisconnectParseError;
1307 public IDebugCounter switchDisconnectSwitchStateException;
1308 public IDebugCounter rejectedExecutionException;
1309 public IDebugCounter switchDisconnectOtherException;
1310 public IDebugCounter switchConnected;
1311 public IDebugCounter unhandledMessage;
1312 public IDebugCounter packetInWhileSwitchIsSlave;
1313 public IDebugCounter epermErrorWhileSwitchIsMaster;
1314 public IDebugCounter roleNotResentBecauseRolePending;
1315 public IDebugCounter roleRequestSent;
1316 public IDebugCounter roleReplyTimeout;
1317 public IDebugCounter roleReplyReceived; // expected RoleReply received
1318 public IDebugCounter roleReplyErrorUnsupported;
1319 public IDebugCounter switchCounterRegistrationFailed;
1320 public IDebugCounter packetParsingError;
1321
1322 void createCounters(IDebugCounterService debugCounters) throws CounterException {
1323 setRoleEqual =
Saurav Dasfcdad072014-08-13 14:15:21 -07001324 debugCounters.registerCounter(
Brian O'Connorc67f9fa2014-08-07 18:17:46 -07001325 prefix, "set-role-equal",
Saurav Dasfcdad072014-08-13 14:15:21 -07001326 "Controller received a role request with role of " +
1327 "EQUAL which is unusual",
Brian O'Connorc67f9fa2014-08-07 18:17:46 -07001328 CounterType.ALWAYS_COUNT);
1329 setSameRole =
Saurav Dasfcdad072014-08-13 14:15:21 -07001330 debugCounters.registerCounter(
Brian O'Connorc67f9fa2014-08-07 18:17:46 -07001331 prefix, "set-same-role",
1332 "Controller received a role request for the same " +
Saurav Dasfcdad072014-08-13 14:15:21 -07001333 "role the controller already had",
Brian O'Connorc67f9fa2014-08-07 18:17:46 -07001334 CounterType.ALWAYS_COUNT,
1335 IDebugCounterService.CTR_MDATA_WARN);
1336
1337 setRoleMaster =
Saurav Dasfcdad072014-08-13 14:15:21 -07001338 debugCounters.registerCounter(
Brian O'Connorc67f9fa2014-08-07 18:17:46 -07001339 prefix, "set-role-master",
1340 "Controller received a role request with role of " +
Saurav Dasfcdad072014-08-13 14:15:21 -07001341 "MASTER. This counter can be at most 1.",
Brian O'Connorc67f9fa2014-08-07 18:17:46 -07001342 CounterType.ALWAYS_COUNT);
1343
1344 remoteStoreNotification =
Saurav Dasfcdad072014-08-13 14:15:21 -07001345 debugCounters.registerCounter(
Brian O'Connorc67f9fa2014-08-07 18:17:46 -07001346 prefix, "remote-store-notification",
1347 "Received a notification from the sync service " +
Saurav Dasfcdad072014-08-13 14:15:21 -07001348 "indicating that switch information has changed",
Brian O'Connorc67f9fa2014-08-07 18:17:46 -07001349 CounterType.ALWAYS_COUNT);
1350
1351 invalidPortsChanged =
Saurav Dasfcdad072014-08-13 14:15:21 -07001352 debugCounters.registerCounter(
Brian O'Connorc67f9fa2014-08-07 18:17:46 -07001353 prefix, "invalid-ports-changed",
1354 "Received an unexpected ports changed " +
Saurav Dasfcdad072014-08-13 14:15:21 -07001355 "notification while the controller was in " +
1356 "SLAVE role.",
Brian O'Connorc67f9fa2014-08-07 18:17:46 -07001357 CounterType.ALWAYS_COUNT,
1358 IDebugCounterService.CTR_MDATA_WARN);
1359
1360 invalidSwitchActivatedWhileSlave =
Saurav Dasfcdad072014-08-13 14:15:21 -07001361 debugCounters.registerCounter(
Brian O'Connorc67f9fa2014-08-07 18:17:46 -07001362 prefix, "invalid-switch-activated-while-slave",
1363 "Received an unexpected switchActivated " +
Saurav Dasfcdad072014-08-13 14:15:21 -07001364 "notification while the controller was in " +
1365 "SLAVE role.",
Brian O'Connorc67f9fa2014-08-07 18:17:46 -07001366 CounterType.ALWAYS_COUNT,
1367 IDebugCounterService.CTR_MDATA_WARN);
1368
1369 invalidStoreEventWhileMaster =
Saurav Dasfcdad072014-08-13 14:15:21 -07001370 debugCounters.registerCounter(
Brian O'Connorc67f9fa2014-08-07 18:17:46 -07001371 prefix, "invalid-store-event-while-master",
1372 "Received an unexpected notification from " +
Saurav Dasfcdad072014-08-13 14:15:21 -07001373 "the sync store while the controller was in " +
1374 "MASTER role.",
Brian O'Connorc67f9fa2014-08-07 18:17:46 -07001375 CounterType.ALWAYS_COUNT,
1376 IDebugCounterService.CTR_MDATA_WARN);
1377
1378 switchDisconnectedWhileSlave =
Saurav Dasfcdad072014-08-13 14:15:21 -07001379 debugCounters.registerCounter(
Brian O'Connorc67f9fa2014-08-07 18:17:46 -07001380 prefix, "switch-disconnected-while-slave",
1381 "A switch disconnected and the controller was " +
Saurav Dasfcdad072014-08-13 14:15:21 -07001382 "in SLAVE role.",
Brian O'Connorc67f9fa2014-08-07 18:17:46 -07001383 CounterType.ALWAYS_COUNT,
1384 IDebugCounterService.CTR_MDATA_WARN);
1385
1386 switchActivated =
Saurav Dasfcdad072014-08-13 14:15:21 -07001387 debugCounters.registerCounter(
Brian O'Connorc67f9fa2014-08-07 18:17:46 -07001388 prefix, "switch-activated",
1389 "A switch connected to this controller is now " +
Saurav Dasfcdad072014-08-13 14:15:21 -07001390 "in MASTER role",
Brian O'Connorc67f9fa2014-08-07 18:17:46 -07001391 CounterType.ALWAYS_COUNT);
1392
1393 errorSameSwitchReactivated = // err
Saurav Dasfcdad072014-08-13 14:15:21 -07001394 debugCounters.registerCounter(
1395 prefix, "error-same-switch-reactivated",
1396 "A switch that was already in active state " +
Brian O'Connorc67f9fa2014-08-07 18:17:46 -07001397 "was activated again. This indicates a " +
1398 "controller defect",
Saurav Dasfcdad072014-08-13 14:15:21 -07001399 CounterType.ALWAYS_COUNT,
1400 IDebugCounterService.CTR_MDATA_ERROR);
Brian O'Connorc67f9fa2014-08-07 18:17:46 -07001401
1402 switchWithSameDpidActivated = // warn
Saurav Dasfcdad072014-08-13 14:15:21 -07001403 debugCounters.registerCounter(
1404 prefix, "switch-with-same-dpid-activated",
1405 "A switch with the same DPID as another switch " +
Brian O'Connorc67f9fa2014-08-07 18:17:46 -07001406 "connected to the controller. This can be " +
1407 "caused by multiple switches configured with " +
1408 "the same DPID or by a switch reconnecting very " +
1409 "quickly.",
Saurav Dasfcdad072014-08-13 14:15:21 -07001410 CounterType.COUNT_ON_DEMAND,
1411 IDebugCounterService.CTR_MDATA_WARN);
Brian O'Connorc67f9fa2014-08-07 18:17:46 -07001412
Saurav Dasfcdad072014-08-13 14:15:21 -07001413 newSwitchActivated = // new switch
1414 debugCounters.registerCounter(
1415 prefix, "new-switch-activated",
1416 "A new switch has completed the handshake as " +
Brian O'Connorc67f9fa2014-08-07 18:17:46 -07001417 "MASTER. The switch was not known to any other " +
1418 "controller in the cluster",
Saurav Dasfcdad072014-08-13 14:15:21 -07001419 CounterType.ALWAYS_COUNT);
Brian O'Connorc67f9fa2014-08-07 18:17:46 -07001420 syncedSwitchActivated =
Saurav Dasfcdad072014-08-13 14:15:21 -07001421 debugCounters.registerCounter(
Brian O'Connorc67f9fa2014-08-07 18:17:46 -07001422 prefix, "synced-switch-activated",
1423 "A switch has completed the handshake as " +
Saurav Dasfcdad072014-08-13 14:15:21 -07001424 "MASTER. The switch was known to another " +
1425 "controller in the cluster",
Brian O'Connorc67f9fa2014-08-07 18:17:46 -07001426 CounterType.ALWAYS_COUNT);
1427
1428 readyForReconcile =
Saurav Dasfcdad072014-08-13 14:15:21 -07001429 debugCounters.registerCounter(
Brian O'Connorc67f9fa2014-08-07 18:17:46 -07001430 prefix, "ready-for-reconcile",
1431 "Controller is ready for flow reconciliation " +
Saurav Dasfcdad072014-08-13 14:15:21 -07001432 "after Slave to Master transition. Either all " +
1433 "previously known switches are now active " +
1434 "or they have timed out and have been removed." +
1435 "This counter will be 0 or 1.",
Brian O'Connorc67f9fa2014-08-07 18:17:46 -07001436 CounterType.ALWAYS_COUNT);
1437
1438 newSwitchFromStore =
Saurav Dasfcdad072014-08-13 14:15:21 -07001439 debugCounters.registerCounter(
Brian O'Connorc67f9fa2014-08-07 18:17:46 -07001440 prefix, "new-switch-from-store",
1441 "A new switch has connected to another " +
Saurav Dasfcdad072014-08-13 14:15:21 -07001442 "another controller in the cluster. This " +
1443 "controller instance has received a sync store " +
1444 "notification for it.",
Brian O'Connorc67f9fa2014-08-07 18:17:46 -07001445 CounterType.ALWAYS_COUNT);
1446
1447 updatedSwitchFromStore =
Saurav Dasfcdad072014-08-13 14:15:21 -07001448 debugCounters.registerCounter(
Brian O'Connorc67f9fa2014-08-07 18:17:46 -07001449 prefix, "updated-switch-from-store",
1450 "Information about a switch connected to " +
Saurav Dasfcdad072014-08-13 14:15:21 -07001451 "another controller instance was updated in " +
1452 "the sync store. This controller instance has " +
1453 "received a notification for it",
Brian O'Connorc67f9fa2014-08-07 18:17:46 -07001454 CounterType.ALWAYS_COUNT);
1455
1456 switchDisconnected =
Saurav Dasfcdad072014-08-13 14:15:21 -07001457 debugCounters.registerCounter(
Brian O'Connorc67f9fa2014-08-07 18:17:46 -07001458 prefix, "switch-disconnected",
1459 "FIXME: switch has disconnected",
1460 CounterType.ALWAYS_COUNT);
1461
1462 syncedSwitchRemoved =
Saurav Dasfcdad072014-08-13 14:15:21 -07001463 debugCounters.registerCounter(
Brian O'Connorc67f9fa2014-08-07 18:17:46 -07001464 prefix, "synced-switch-removed",
1465 "A switch connected to another controller " +
Saurav Dasfcdad072014-08-13 14:15:21 -07001466 "instance has disconnected from the controller " +
1467 "cluster. This controller instance has " +
1468 "received a notification for it",
Brian O'Connorc67f9fa2014-08-07 18:17:46 -07001469 CounterType.ALWAYS_COUNT);
1470
1471 unknownSwitchRemovedFromStore =
Saurav Dasfcdad072014-08-13 14:15:21 -07001472 debugCounters.registerCounter(
Brian O'Connorc67f9fa2014-08-07 18:17:46 -07001473 prefix, "unknown-switch-removed-from-store",
1474 "This controller instances has received a sync " +
Saurav Dasfcdad072014-08-13 14:15:21 -07001475 "store notification that a switch has " +
1476 "disconnected but this controller instance " +
1477 "did not have the any information about the " +
1478 "switch", // might be less than warning
Brian O'Connorc67f9fa2014-08-07 18:17:46 -07001479 CounterType.ALWAYS_COUNT,
1480 IDebugCounterService.CTR_MDATA_WARN);
1481
1482 consolidateStoreRunCount =
Saurav Dasfcdad072014-08-13 14:15:21 -07001483 debugCounters.registerCounter(
Brian O'Connorc67f9fa2014-08-07 18:17:46 -07001484 prefix, "consolidate-store-run-count",
1485 "This controller has transitioned from SLAVE " +
Saurav Dasfcdad072014-08-13 14:15:21 -07001486 "to MASTER and waited for switches to reconnect. " +
1487 "The controller has finished waiting and has " +
1488 "reconciled switch entries in the sync store " +
1489 "with live state",
Brian O'Connorc67f9fa2014-08-07 18:17:46 -07001490 CounterType.ALWAYS_COUNT);
1491
1492 consolidateStoreInconsistencies =
1493 debugCounters.registerCounter(
Saurav Dasfcdad072014-08-13 14:15:21 -07001494 prefix, "consolidate-store-inconsistencies",
1495 "During switch sync store consolidation: " +
1496 "Number of switches that were in the store " +
1497 "but not otherwise known plus number of " +
1498 "switches that were in the store previously " +
1499 "but are now missing plus number of " +
1500 "connected switches that were absent from " +
1501 "the store although this controller has " +
1502 "written them. A non-zero count " +
1503 "indicates a brief split-brain dual MASTER " +
1504 "situation during fail-over",
1505 CounterType.ALWAYS_COUNT);
Brian O'Connorc67f9fa2014-08-07 18:17:46 -07001506
1507 storeSyncError =
Saurav Dasfcdad072014-08-13 14:15:21 -07001508 debugCounters.registerCounter(
Brian O'Connorc67f9fa2014-08-07 18:17:46 -07001509 prefix, "store-sync-error",
1510 "Number of times a sync store operation failed " +
Saurav Dasfcdad072014-08-13 14:15:21 -07001511 "due to a store sync exception or an entry in " +
1512 "in the store had invalid data.",
Brian O'Connorc67f9fa2014-08-07 18:17:46 -07001513 CounterType.ALWAYS_COUNT,
1514 IDebugCounterService.CTR_MDATA_ERROR);
1515
1516 switchesNotReconnectingToNewMaster =
Saurav Dasfcdad072014-08-13 14:15:21 -07001517 debugCounters.registerCounter(
Brian O'Connorc67f9fa2014-08-07 18:17:46 -07001518 prefix, "switches-not-reconnecting-to-new-master",
1519 "Switches that were connected to another " +
Saurav Dasfcdad072014-08-13 14:15:21 -07001520 "controller instance in the cluster but that " +
1521 "did not reconnect to this controller after it " +
1522 "transitioned to MASTER", // might be less
1523 // than warning
Brian O'Connorc67f9fa2014-08-07 18:17:46 -07001524 CounterType.ALWAYS_COUNT);
1525
1526 switchPortChanged =
Saurav Dasfcdad072014-08-13 14:15:21 -07001527 debugCounters.registerCounter(
Brian O'Connorc67f9fa2014-08-07 18:17:46 -07001528 prefix, "switch-port-changed",
1529 "Number of times switch ports have changed",
1530 CounterType.ALWAYS_COUNT);
1531 switchOtherChange =
Saurav Dasfcdad072014-08-13 14:15:21 -07001532 debugCounters.registerCounter(
Brian O'Connorc67f9fa2014-08-07 18:17:46 -07001533 prefix, "switch-other-change",
1534 "Number of times other information of a switch " +
Saurav Dasfcdad072014-08-13 14:15:21 -07001535 "has changed.",
Brian O'Connorc67f9fa2014-08-07 18:17:46 -07001536 CounterType.ALWAYS_COUNT);
1537
1538 dispatchMessageWhileSlave =
Saurav Dasfcdad072014-08-13 14:15:21 -07001539 debugCounters.registerCounter(
Brian O'Connorc67f9fa2014-08-07 18:17:46 -07001540 prefix, "dispatch-message-while-slave",
1541 "Number of times an OF message was received " +
Saurav Dasfcdad072014-08-13 14:15:21 -07001542 "and supposed to be dispatched but the " +
1543 "controller was in SLAVE role and the message " +
1544 "was not dispatched",
Brian O'Connorc67f9fa2014-08-07 18:17:46 -07001545 CounterType.ALWAYS_COUNT);
1546
Saurav Dasfcdad072014-08-13 14:15:21 -07001547 dispatchMessage = // does this cnt make sense? more specific?? per
1548 // type? count stops?
1549 debugCounters.registerCounter(
1550 prefix, "dispatch-message",
1551 "Number of times an OF message was dispatched " +
Brian O'Connorc67f9fa2014-08-07 18:17:46 -07001552 "to registered modules",
Saurav Dasfcdad072014-08-13 14:15:21 -07001553 CounterType.ALWAYS_COUNT);
Brian O'Connorc67f9fa2014-08-07 18:17:46 -07001554
1555 controllerNodeIpsChanged =
Saurav Dasfcdad072014-08-13 14:15:21 -07001556 debugCounters.registerCounter(
Brian O'Connorc67f9fa2014-08-07 18:17:46 -07001557 prefix, "controller-nodes-ips-changed",
1558 "IP addresses of controller nodes have changed",
1559 CounterType.ALWAYS_COUNT);
1560
Saurav Dasfcdad072014-08-13 14:15:21 -07001561 // ------------------------
1562 // channel handler counters. Factor them out ??
Brian O'Connorc67f9fa2014-08-07 18:17:46 -07001563 messageReceived =
Saurav Dasfcdad072014-08-13 14:15:21 -07001564 debugCounters.registerCounter(
Brian O'Connorc67f9fa2014-08-07 18:17:46 -07001565 prefix, "message-received",
1566 "Number of OpenFlow messages received. Some of " +
Saurav Dasfcdad072014-08-13 14:15:21 -07001567 "these might be throttled",
Brian O'Connorc67f9fa2014-08-07 18:17:46 -07001568 CounterType.ALWAYS_COUNT);
1569 messageInputThrottled =
Saurav Dasfcdad072014-08-13 14:15:21 -07001570 debugCounters.registerCounter(
Brian O'Connorc67f9fa2014-08-07 18:17:46 -07001571 prefix, "message-input-throttled",
1572 "Number of OpenFlow messages that were " +
Saurav Dasfcdad072014-08-13 14:15:21 -07001573 "throttled due to high load from the sender",
Brian O'Connorc67f9fa2014-08-07 18:17:46 -07001574 CounterType.ALWAYS_COUNT,
1575 IDebugCounterService.CTR_MDATA_WARN);
Saurav Dasfcdad072014-08-13 14:15:21 -07001576 // TODO: more counters in messageReceived ??
Brian O'Connorc67f9fa2014-08-07 18:17:46 -07001577
1578 switchDisconnectReadTimeout =
Saurav Dasfcdad072014-08-13 14:15:21 -07001579 debugCounters.registerCounter(
Brian O'Connorc67f9fa2014-08-07 18:17:46 -07001580 prefix, "switch-disconnect-read-timeout",
1581 "Number of times a switch was disconnected due " +
Saurav Dasfcdad072014-08-13 14:15:21 -07001582 "due the switch failing to send OpenFlow " +
1583 "messages or responding to OpenFlow ECHOs",
Brian O'Connorc67f9fa2014-08-07 18:17:46 -07001584 CounterType.ALWAYS_COUNT,
1585 IDebugCounterService.CTR_MDATA_ERROR);
1586 switchDisconnectHandshakeTimeout =
Saurav Dasfcdad072014-08-13 14:15:21 -07001587 debugCounters.registerCounter(
Brian O'Connorc67f9fa2014-08-07 18:17:46 -07001588 prefix, "switch-disconnect-handshake-timeout",
1589 "Number of times a switch was disconnected " +
Saurav Dasfcdad072014-08-13 14:15:21 -07001590 "because it failed to complete the handshake " +
1591 "in time.",
Brian O'Connorc67f9fa2014-08-07 18:17:46 -07001592 CounterType.ALWAYS_COUNT,
1593 IDebugCounterService.CTR_MDATA_ERROR);
1594 switchDisconnectIOError =
Saurav Dasfcdad072014-08-13 14:15:21 -07001595 debugCounters.registerCounter(
Brian O'Connorc67f9fa2014-08-07 18:17:46 -07001596 prefix, "switch-disconnect-io-error",
1597 "Number of times a switch was disconnected " +
Saurav Dasfcdad072014-08-13 14:15:21 -07001598 "due to IO errors on the switch connection.",
Brian O'Connorc67f9fa2014-08-07 18:17:46 -07001599 CounterType.ALWAYS_COUNT,
1600 IDebugCounterService.CTR_MDATA_ERROR);
1601 switchDisconnectParseError =
Saurav Dasfcdad072014-08-13 14:15:21 -07001602 debugCounters.registerCounter(
Brian O'Connorc67f9fa2014-08-07 18:17:46 -07001603 prefix, "switch-disconnect-parse-error",
Saurav Dasfcdad072014-08-13 14:15:21 -07001604 "Number of times a switch was disconnected " +
1605 "because it sent an invalid packet that could " +
1606 "not be parsed",
1607 CounterType.ALWAYS_COUNT,
1608 IDebugCounterService.CTR_MDATA_ERROR);
Brian O'Connorc67f9fa2014-08-07 18:17:46 -07001609
1610 switchDisconnectSwitchStateException =
Saurav Dasfcdad072014-08-13 14:15:21 -07001611 debugCounters.registerCounter(
Brian O'Connorc67f9fa2014-08-07 18:17:46 -07001612 prefix, "switch-disconnect-switch-state-exception",
1613 "Number of times a switch was disconnected " +
Saurav Dasfcdad072014-08-13 14:15:21 -07001614 "because it sent messages that were invalid " +
1615 "given the switch connection's state.",
Brian O'Connorc67f9fa2014-08-07 18:17:46 -07001616 CounterType.ALWAYS_COUNT,
1617 IDebugCounterService.CTR_MDATA_ERROR);
1618 rejectedExecutionException =
Saurav Dasfcdad072014-08-13 14:15:21 -07001619 debugCounters.registerCounter(
Brian O'Connorc67f9fa2014-08-07 18:17:46 -07001620 prefix, "rejected-execution-exception",
1621 "TODO",
1622 CounterType.ALWAYS_COUNT,
1623 IDebugCounterService.CTR_MDATA_ERROR);
1624
1625 switchDisconnectOtherException =
Saurav Dasfcdad072014-08-13 14:15:21 -07001626 debugCounters.registerCounter(
1627 prefix, "switch-disconnect-other-exception",
Brian O'Connorc67f9fa2014-08-07 18:17:46 -07001628 "Number of times a switch was disconnected " +
Saurav Dasfcdad072014-08-13 14:15:21 -07001629 "due to an exceptional situation not covered " +
1630 "by other counters",
Brian O'Connorc67f9fa2014-08-07 18:17:46 -07001631 CounterType.ALWAYS_COUNT,
1632 IDebugCounterService.CTR_MDATA_ERROR);
1633
1634 switchConnected =
Saurav Dasfcdad072014-08-13 14:15:21 -07001635 debugCounters.registerCounter(
Brian O'Connorc67f9fa2014-08-07 18:17:46 -07001636 prefix, "switch-connected",
1637 "Number of times a new switch connection was " +
Saurav Dasfcdad072014-08-13 14:15:21 -07001638 "established",
Brian O'Connorc67f9fa2014-08-07 18:17:46 -07001639 CounterType.ALWAYS_COUNT);
1640
1641 unhandledMessage =
Saurav Dasfcdad072014-08-13 14:15:21 -07001642 debugCounters.registerCounter(
Brian O'Connorc67f9fa2014-08-07 18:17:46 -07001643 prefix, "unhandled-message",
1644 "Number of times an OpenFlow message was " +
Saurav Dasfcdad072014-08-13 14:15:21 -07001645 "received that the controller ignored because " +
1646 "it was inapproriate given the switch " +
1647 "connection's state.",
Brian O'Connorc67f9fa2014-08-07 18:17:46 -07001648 CounterType.ALWAYS_COUNT,
1649 IDebugCounterService.CTR_MDATA_WARN);
Saurav Dasfcdad072014-08-13 14:15:21 -07001650 // might be less than warning
Brian O'Connorc67f9fa2014-08-07 18:17:46 -07001651
1652 packetInWhileSwitchIsSlave =
Saurav Dasfcdad072014-08-13 14:15:21 -07001653 debugCounters.registerCounter(
Brian O'Connorc67f9fa2014-08-07 18:17:46 -07001654 prefix, "packet-in-while-switch-is-slave",
1655 "Number of times a packet in was received " +
Saurav Dasfcdad072014-08-13 14:15:21 -07001656 "from a switch that was in SLAVE role. " +
1657 "Possibly inidicates inconsistent roles.",
Brian O'Connorc67f9fa2014-08-07 18:17:46 -07001658 CounterType.ALWAYS_COUNT);
1659 epermErrorWhileSwitchIsMaster =
Saurav Dasfcdad072014-08-13 14:15:21 -07001660 debugCounters.registerCounter(
Brian O'Connorc67f9fa2014-08-07 18:17:46 -07001661 prefix, "eperm-error-while-switch-is-master",
1662 "Number of times a permission error was " +
Saurav Dasfcdad072014-08-13 14:15:21 -07001663 "received while the switch was in MASTER role. " +
1664 "Possibly inidicates inconsistent roles.",
Brian O'Connorc67f9fa2014-08-07 18:17:46 -07001665 CounterType.ALWAYS_COUNT,
1666 IDebugCounterService.CTR_MDATA_WARN);
1667
1668 roleNotResentBecauseRolePending =
Saurav Dasfcdad072014-08-13 14:15:21 -07001669 debugCounters.registerCounter(
Brian O'Connorc67f9fa2014-08-07 18:17:46 -07001670 prefix, "role-not-resent-because-role-pending",
1671 "The controller tried to reestablish a role " +
Saurav Dasfcdad072014-08-13 14:15:21 -07001672 "with a switch but did not do so because a " +
1673 "previous role request was still pending",
Brian O'Connorc67f9fa2014-08-07 18:17:46 -07001674 CounterType.ALWAYS_COUNT);
1675 roleRequestSent =
Saurav Dasfcdad072014-08-13 14:15:21 -07001676 debugCounters.registerCounter(
Brian O'Connorc67f9fa2014-08-07 18:17:46 -07001677 prefix, "role-request-sent",
1678 "Number of times the controller sent a role " +
Saurav Dasfcdad072014-08-13 14:15:21 -07001679 "request to a switch.",
Brian O'Connorc67f9fa2014-08-07 18:17:46 -07001680 CounterType.ALWAYS_COUNT);
1681 roleReplyTimeout =
Saurav Dasfcdad072014-08-13 14:15:21 -07001682 debugCounters.registerCounter(
Brian O'Connorc67f9fa2014-08-07 18:17:46 -07001683 prefix, "role-reply-timeout",
1684 "Number of times a role request message did not " +
Saurav Dasfcdad072014-08-13 14:15:21 -07001685 "receive the expected reply from a switch",
Brian O'Connorc67f9fa2014-08-07 18:17:46 -07001686 CounterType.ALWAYS_COUNT,
1687 IDebugCounterService.CTR_MDATA_WARN);
1688
1689 roleReplyReceived = // expected RoleReply received
Saurav Dasfcdad072014-08-13 14:15:21 -07001690 debugCounters.registerCounter(
1691 prefix, "role-reply-received",
1692 "Number of times the controller received the " +
Brian O'Connorc67f9fa2014-08-07 18:17:46 -07001693 "expected role reply message from a switch",
Saurav Dasfcdad072014-08-13 14:15:21 -07001694 CounterType.ALWAYS_COUNT);
Brian O'Connorc67f9fa2014-08-07 18:17:46 -07001695
1696 roleReplyErrorUnsupported =
Saurav Dasfcdad072014-08-13 14:15:21 -07001697 debugCounters.registerCounter(
Brian O'Connorc67f9fa2014-08-07 18:17:46 -07001698 prefix, "role-reply-error-unsupported",
1699 "Number of times the controller received an " +
Saurav Dasfcdad072014-08-13 14:15:21 -07001700 "error from a switch in response to a role " +
1701 "request indicating that the switch does not " +
1702 "support roles.",
Brian O'Connorc67f9fa2014-08-07 18:17:46 -07001703 CounterType.ALWAYS_COUNT);
1704
1705 switchCounterRegistrationFailed =
1706 debugCounters.registerCounter(prefix,
Saurav Dasfcdad072014-08-13 14:15:21 -07001707 "switch-counter-registration-failed",
1708 "Number of times the controller failed to " +
1709 "register per-switch debug counters",
1710 CounterType.ALWAYS_COUNT,
1711 IDebugCounterService.CTR_MDATA_WARN);
Brian O'Connorc67f9fa2014-08-07 18:17:46 -07001712
1713 packetParsingError =
1714 debugCounters.registerCounter(prefix,
Saurav Dasfcdad072014-08-13 14:15:21 -07001715 "packet-parsing-error",
1716 "Number of times the packet parsing " +
1717 "encountered an error",
1718 CounterType.ALWAYS_COUNT,
1719 IDebugCounterService.CTR_MDATA_ERROR);
Brian O'Connorc67f9fa2014-08-07 18:17:46 -07001720 }
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -08001721 }
1722
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -08001723 @Override
Brian O'Connorc67f9fa2014-08-07 18:17:46 -07001724 public Counters getCounters() {
1725 return this.counters;
1726 }
1727
1728 // **************
1729 // debugEvent registrations
1730 // **************
1731
1732 private void registerControllerDebugEvents() throws FloodlightModuleException {
1733 if (debugEvents == null) {
1734 debugEvents = new NullDebugEvent();
1735 }
1736 try {
1737 evSwitch = debugEvents.registerEvent(
Saurav Dasfcdad072014-08-13 14:15:21 -07001738 Counters.prefix, "switchevent",
1739 "Switch connected, disconnected or port changed",
1740 EventType.ALWAYS_LOG, SwitchEvent.class, 100);
Brian O'Connorc67f9fa2014-08-07 18:17:46 -07001741 } catch (MaxEventsRegistered e) {
1742 throw new FloodlightModuleException("Max events registered", e);
1743 }
1744 }
1745
1746 public class SwitchEvent {
1747 @EventColumn(name = "dpid", description = EventFieldType.DPID)
1748 long dpid;
1749
1750 @EventColumn(name = "reason", description = EventFieldType.STRING)
1751 String reason;
1752
1753 public SwitchEvent(long dpid, String reason) {
1754 this.dpid = dpid;
1755 this.reason = reason;
1756 }
1757 }
1758
1759 // **************
1760 // Utility methods
1761 // **************
1762
1763 @Override
1764 public void setAlwaysClearFlowsOnSwActivate(boolean value) {
Saurav Dasfcdad072014-08-13 14:15:21 -07001765 // this.alwaysClearFlowsOnSwActivate = value;
Brian O'Connorc67f9fa2014-08-07 18:17:46 -07001766 // XXX S need to be a little more careful about this
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -08001767 }
1768
1769 @Override
Brian O'Connorc67f9fa2014-08-07 18:17:46 -07001770 public Map<String, Long> getMemory() {
1771 Map<String, Long> m = new HashMap<String, Long>();
1772 Runtime runtime = Runtime.getRuntime();
1773 m.put("total", runtime.totalMemory());
1774 m.put("free", runtime.freeMemory());
1775 return m;
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -08001776 }
Ray Milkey269ffb92014-04-03 14:43:30 -07001777
Brian O'Connorc67f9fa2014-08-07 18:17:46 -07001778 @Override
1779 public Long getUptime() {
1780 RuntimeMXBean rb = ManagementFactory.getRuntimeMXBean();
1781 return rb.getUptime();
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -08001782 }
Brian O'Connorc67f9fa2014-08-07 18:17:46 -07001783
1784 /**
1785 * Forward to the driver-manager to get an IOFSwitch instance.
Jonathan Hartcb34f382014-08-12 21:11:03 -07001786 *
Brian O'Connorc67f9fa2014-08-07 18:17:46 -07001787 * @param desc
1788 * @return
1789 */
1790 protected IOFSwitch getOFSwitchInstance(OFDescStatsReply desc, OFVersion ofv) {
1791 return DriverManager.getOFSwitchImpl(desc, ofv);
1792 }
1793
1794 protected IThreadPoolService getThreadPoolService() {
1795 return this.threadPool;
1796 }
1797
1798 /**
Saurav Dasfcdad072014-08-13 14:15:21 -07001799 * Part of the controller updates framework (see 'run()' method) Use this
1800 * method to add an IUpdate. A thread-pool will serve the update by
1801 * dispatching it to all listeners for that update.
Jonathan Hartcb34f382014-08-12 21:11:03 -07001802 *
Brian O'Connorc67f9fa2014-08-07 18:17:46 -07001803 * @param update
1804 */
Saurav Dasfcdad072014-08-13 14:15:21 -07001805 @LogMessageDoc(level = "WARN",
1806 message = "Failure adding update {} to queue",
1807 explanation = "The controller tried to add an internal notification" +
1808 " to its message queue but the add failed.",
1809 recommendation = LogMessageDoc.REPORT_CONTROLLER_BUG)
Brian O'Connorc67f9fa2014-08-07 18:17:46 -07001810 private void addUpdateToQueue(IUpdate update) {
1811 try {
1812 this.updates.put(update);
1813 } catch (InterruptedException e) {
1814 // This should never happen
1815 log.error("Failure adding update {} to queue.", update);
1816 }
1817 }
1818
1819 void flushAll() {
1820 // Flush all flow-mods/packet-out/stats generated from this "train"
1821 OFSwitchImplBase.flush_all();
1822 debugCounters.flushCounters();
1823 debugEvents.flushEvents();
1824 }
1825
1826 /**
1827 * flcontext_free - Free the context to the current thread
Jonathan Hartcb34f382014-08-12 21:11:03 -07001828 *
Brian O'Connorc67f9fa2014-08-07 18:17:46 -07001829 * @param flcontext
1830 */
1831 protected void flcontext_free(FloodlightContext flcontext) {
1832 flcontext.getStorage().clear();
1833 flcontext_cache.get().push(flcontext);
1834 }
1835
1836 @LogMessageDoc(message = "Calling System.exit",
1837 explanation = "The controller is terminating")
1838 private synchronized void terminate() {
1839 log.info("Calling System.exit");
1840 System.exit(1);
1841 }
1842
Brian O'Connorc67f9fa2014-08-07 18:17:46 -07001843 // ***************
1844 // Floodlight context related
1845 // ***************
1846
1847 /**
1848 * flcontext_cache - Keep a thread local stack of contexts
1849 */
1850 protected static final ThreadLocal<Stack<FloodlightContext>> flcontext_cache =
1851 new ThreadLocal<Stack<FloodlightContext>>() {
1852 @Override
1853 protected Stack<FloodlightContext> initialValue() {
1854 return new Stack<FloodlightContext>();
1855 }
1856 };
1857
1858 /**
Saurav Dasfcdad072014-08-13 14:15:21 -07001859 * flcontext_alloc - pop a context off the stack, if required create a new
1860 * one
Jonathan Hartcb34f382014-08-12 21:11:03 -07001861 *
Brian O'Connorc67f9fa2014-08-07 18:17:46 -07001862 * @return FloodlightContext
1863 */
1864 protected static FloodlightContext flcontext_alloc() {
1865 FloodlightContext flcontext = null;
1866
1867 if (flcontext_cache.get().empty()) {
1868 flcontext = new FloodlightContext();
1869 } else {
1870 flcontext = flcontext_cache.get().pop();
1871 }
1872
1873 return flcontext;
1874 }
1875
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -08001876}