blob: 8c7c58994c735493a2ce2ea024a8c7f69a9b7670 [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.
177 *
178 * 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.
186 *
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)
Saurav Dasfcdad072014-08-13 14:15:21 -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.
450 *
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.
Saurav Dasfcdad072014-08-13 14:15:21 -0700603 *
604 * We only dispatch messages to listeners if the controller's role is
605 * MASTER.
606 *
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
Saurav Dasfcdad072014-08-13 14:15:21 -0700612 *
613 * 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.
Saurav Dasfcdad072014-08-13 14:15:21 -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.
Saurav Dasfcdad072014-08-13 14:15:21 -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.
1031 *
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
Saurav Dasfcdad072014-08-13 14:15:21 -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 }
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -08001220 }
Ray Milkey269ffb92014-04-03 14:43:30 -07001221
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -08001222 /**
1223 * Startup all of the controller's components
Saurav Dasfcdad072014-08-13 14:15:21 -07001224 *
Brian O'Connorc67f9fa2014-08-07 18:17:46 -07001225 * @throws FloodlightModuleException
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -08001226 */
Ray Milkey269ffb92014-04-03 14:43:30 -07001227 @LogMessageDoc(message = "Waiting for storage source",
1228 explanation = "The system database is not yet ready",
1229 recommendation = "If this message persists, this indicates " +
1230 "that the system database has failed to start. " +
1231 LogMessageDoc.CHECK_CONTROLLER)
Brian O'Connorc67f9fa2014-08-07 18:17:46 -07001232 public void startupComponents() throws FloodlightModuleException {
Ray Milkey269ffb92014-04-03 14:43:30 -07001233 try {
Pavlin Radoslavov53b208a2014-07-28 13:16:11 -07001234 registryService.registerController(onosInstanceId.toString());
Ray Milkey269ffb92014-04-03 14:43:30 -07001235 } catch (RegistryException e) {
1236 log.warn("Registry service error: {}", e.getMessage());
1237 }
1238
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -08001239 // Add our REST API
1240 restApi.addRestletRoutable(new CoreWebRoutable());
Ray Milkey269ffb92014-04-03 14:43:30 -07001241
Brian O'Connorc67f9fa2014-08-07 18:17:46 -07001242 // Startup load monitoring
1243 if (overload_drop) {
1244 this.loadmonitor.startMonitoring(
Saurav Dasfcdad072014-08-13 14:15:21 -07001245 this.threadPool.getScheduledExecutor());
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -08001246 }
Brian O'Connorc67f9fa2014-08-07 18:17:46 -07001247
1248 // register counters and events
1249 try {
1250 this.counters.createCounters(debugCounters);
1251 } catch (CounterException e) {
1252 throw new FloodlightModuleException(e.getMessage());
1253 }
1254 registerControllerDebugEvents();
1255 }
1256
1257 // **************
1258 // debugCounter registrations
1259 // **************
1260
1261 public static class Counters {
1262 public static final String prefix = "controller";
1263 public IDebugCounter setRoleEqual;
1264 public IDebugCounter setSameRole;
1265 public IDebugCounter setRoleMaster;
1266 public IDebugCounter remoteStoreNotification;
1267 public IDebugCounter invalidPortsChanged;
1268 public IDebugCounter invalidSwitchActivatedWhileSlave;
1269 public IDebugCounter invalidStoreEventWhileMaster;
1270 public IDebugCounter switchDisconnectedWhileSlave;
1271 public IDebugCounter switchActivated;
1272 public IDebugCounter errorSameSwitchReactivated; // err
1273 public IDebugCounter switchWithSameDpidActivated; // warn
Saurav Dasfcdad072014-08-13 14:15:21 -07001274 public IDebugCounter newSwitchActivated; // new switch
Brian O'Connorc67f9fa2014-08-07 18:17:46 -07001275 public IDebugCounter syncedSwitchActivated;
1276 public IDebugCounter readyForReconcile;
1277 public IDebugCounter newSwitchFromStore;
1278 public IDebugCounter updatedSwitchFromStore;
1279 public IDebugCounter switchDisconnected;
1280 public IDebugCounter syncedSwitchRemoved;
1281 public IDebugCounter unknownSwitchRemovedFromStore;
1282 public IDebugCounter consolidateStoreRunCount;
1283 public IDebugCounter consolidateStoreInconsistencies;
1284 public IDebugCounter storeSyncError;
1285 public IDebugCounter switchesNotReconnectingToNewMaster;
1286 public IDebugCounter switchPortChanged;
1287 public IDebugCounter switchOtherChange;
1288 public IDebugCounter dispatchMessageWhileSlave;
Saurav Dasfcdad072014-08-13 14:15:21 -07001289 public IDebugCounter dispatchMessage; // does this cnt make sense? more
1290 // specific?? per type? count
1291 // stops?
Brian O'Connorc67f9fa2014-08-07 18:17:46 -07001292 public IDebugCounter controllerNodeIpsChanged;
1293 public IDebugCounter messageReceived;
1294 public IDebugCounter messageInputThrottled;
1295 public IDebugCounter switchDisconnectReadTimeout;
1296 public IDebugCounter switchDisconnectHandshakeTimeout;
1297 public IDebugCounter switchDisconnectIOError;
1298 public IDebugCounter switchDisconnectParseError;
1299 public IDebugCounter switchDisconnectSwitchStateException;
1300 public IDebugCounter rejectedExecutionException;
1301 public IDebugCounter switchDisconnectOtherException;
1302 public IDebugCounter switchConnected;
1303 public IDebugCounter unhandledMessage;
1304 public IDebugCounter packetInWhileSwitchIsSlave;
1305 public IDebugCounter epermErrorWhileSwitchIsMaster;
1306 public IDebugCounter roleNotResentBecauseRolePending;
1307 public IDebugCounter roleRequestSent;
1308 public IDebugCounter roleReplyTimeout;
1309 public IDebugCounter roleReplyReceived; // expected RoleReply received
1310 public IDebugCounter roleReplyErrorUnsupported;
1311 public IDebugCounter switchCounterRegistrationFailed;
1312 public IDebugCounter packetParsingError;
1313
1314 void createCounters(IDebugCounterService debugCounters) throws CounterException {
1315 setRoleEqual =
Saurav Dasfcdad072014-08-13 14:15:21 -07001316 debugCounters.registerCounter(
Brian O'Connorc67f9fa2014-08-07 18:17:46 -07001317 prefix, "set-role-equal",
Saurav Dasfcdad072014-08-13 14:15:21 -07001318 "Controller received a role request with role of " +
1319 "EQUAL which is unusual",
Brian O'Connorc67f9fa2014-08-07 18:17:46 -07001320 CounterType.ALWAYS_COUNT);
1321 setSameRole =
Saurav Dasfcdad072014-08-13 14:15:21 -07001322 debugCounters.registerCounter(
Brian O'Connorc67f9fa2014-08-07 18:17:46 -07001323 prefix, "set-same-role",
1324 "Controller received a role request for the same " +
Saurav Dasfcdad072014-08-13 14:15:21 -07001325 "role the controller already had",
Brian O'Connorc67f9fa2014-08-07 18:17:46 -07001326 CounterType.ALWAYS_COUNT,
1327 IDebugCounterService.CTR_MDATA_WARN);
1328
1329 setRoleMaster =
Saurav Dasfcdad072014-08-13 14:15:21 -07001330 debugCounters.registerCounter(
Brian O'Connorc67f9fa2014-08-07 18:17:46 -07001331 prefix, "set-role-master",
1332 "Controller received a role request with role of " +
Saurav Dasfcdad072014-08-13 14:15:21 -07001333 "MASTER. This counter can be at most 1.",
Brian O'Connorc67f9fa2014-08-07 18:17:46 -07001334 CounterType.ALWAYS_COUNT);
1335
1336 remoteStoreNotification =
Saurav Dasfcdad072014-08-13 14:15:21 -07001337 debugCounters.registerCounter(
Brian O'Connorc67f9fa2014-08-07 18:17:46 -07001338 prefix, "remote-store-notification",
1339 "Received a notification from the sync service " +
Saurav Dasfcdad072014-08-13 14:15:21 -07001340 "indicating that switch information has changed",
Brian O'Connorc67f9fa2014-08-07 18:17:46 -07001341 CounterType.ALWAYS_COUNT);
1342
1343 invalidPortsChanged =
Saurav Dasfcdad072014-08-13 14:15:21 -07001344 debugCounters.registerCounter(
Brian O'Connorc67f9fa2014-08-07 18:17:46 -07001345 prefix, "invalid-ports-changed",
1346 "Received an unexpected ports changed " +
Saurav Dasfcdad072014-08-13 14:15:21 -07001347 "notification while the controller was in " +
1348 "SLAVE role.",
Brian O'Connorc67f9fa2014-08-07 18:17:46 -07001349 CounterType.ALWAYS_COUNT,
1350 IDebugCounterService.CTR_MDATA_WARN);
1351
1352 invalidSwitchActivatedWhileSlave =
Saurav Dasfcdad072014-08-13 14:15:21 -07001353 debugCounters.registerCounter(
Brian O'Connorc67f9fa2014-08-07 18:17:46 -07001354 prefix, "invalid-switch-activated-while-slave",
1355 "Received an unexpected switchActivated " +
Saurav Dasfcdad072014-08-13 14:15:21 -07001356 "notification while the controller was in " +
1357 "SLAVE role.",
Brian O'Connorc67f9fa2014-08-07 18:17:46 -07001358 CounterType.ALWAYS_COUNT,
1359 IDebugCounterService.CTR_MDATA_WARN);
1360
1361 invalidStoreEventWhileMaster =
Saurav Dasfcdad072014-08-13 14:15:21 -07001362 debugCounters.registerCounter(
Brian O'Connorc67f9fa2014-08-07 18:17:46 -07001363 prefix, "invalid-store-event-while-master",
1364 "Received an unexpected notification from " +
Saurav Dasfcdad072014-08-13 14:15:21 -07001365 "the sync store while the controller was in " +
1366 "MASTER role.",
Brian O'Connorc67f9fa2014-08-07 18:17:46 -07001367 CounterType.ALWAYS_COUNT,
1368 IDebugCounterService.CTR_MDATA_WARN);
1369
1370 switchDisconnectedWhileSlave =
Saurav Dasfcdad072014-08-13 14:15:21 -07001371 debugCounters.registerCounter(
Brian O'Connorc67f9fa2014-08-07 18:17:46 -07001372 prefix, "switch-disconnected-while-slave",
1373 "A switch disconnected and the controller was " +
Saurav Dasfcdad072014-08-13 14:15:21 -07001374 "in SLAVE role.",
Brian O'Connorc67f9fa2014-08-07 18:17:46 -07001375 CounterType.ALWAYS_COUNT,
1376 IDebugCounterService.CTR_MDATA_WARN);
1377
1378 switchActivated =
Saurav Dasfcdad072014-08-13 14:15:21 -07001379 debugCounters.registerCounter(
Brian O'Connorc67f9fa2014-08-07 18:17:46 -07001380 prefix, "switch-activated",
1381 "A switch connected to this controller is now " +
Saurav Dasfcdad072014-08-13 14:15:21 -07001382 "in MASTER role",
Brian O'Connorc67f9fa2014-08-07 18:17:46 -07001383 CounterType.ALWAYS_COUNT);
1384
1385 errorSameSwitchReactivated = // err
Saurav Dasfcdad072014-08-13 14:15:21 -07001386 debugCounters.registerCounter(
1387 prefix, "error-same-switch-reactivated",
1388 "A switch that was already in active state " +
Brian O'Connorc67f9fa2014-08-07 18:17:46 -07001389 "was activated again. This indicates a " +
1390 "controller defect",
Saurav Dasfcdad072014-08-13 14:15:21 -07001391 CounterType.ALWAYS_COUNT,
1392 IDebugCounterService.CTR_MDATA_ERROR);
Brian O'Connorc67f9fa2014-08-07 18:17:46 -07001393
1394 switchWithSameDpidActivated = // warn
Saurav Dasfcdad072014-08-13 14:15:21 -07001395 debugCounters.registerCounter(
1396 prefix, "switch-with-same-dpid-activated",
1397 "A switch with the same DPID as another switch " +
Brian O'Connorc67f9fa2014-08-07 18:17:46 -07001398 "connected to the controller. This can be " +
1399 "caused by multiple switches configured with " +
1400 "the same DPID or by a switch reconnecting very " +
1401 "quickly.",
Saurav Dasfcdad072014-08-13 14:15:21 -07001402 CounterType.COUNT_ON_DEMAND,
1403 IDebugCounterService.CTR_MDATA_WARN);
Brian O'Connorc67f9fa2014-08-07 18:17:46 -07001404
Saurav Dasfcdad072014-08-13 14:15:21 -07001405 newSwitchActivated = // new switch
1406 debugCounters.registerCounter(
1407 prefix, "new-switch-activated",
1408 "A new switch has completed the handshake as " +
Brian O'Connorc67f9fa2014-08-07 18:17:46 -07001409 "MASTER. The switch was not known to any other " +
1410 "controller in the cluster",
Saurav Dasfcdad072014-08-13 14:15:21 -07001411 CounterType.ALWAYS_COUNT);
Brian O'Connorc67f9fa2014-08-07 18:17:46 -07001412 syncedSwitchActivated =
Saurav Dasfcdad072014-08-13 14:15:21 -07001413 debugCounters.registerCounter(
Brian O'Connorc67f9fa2014-08-07 18:17:46 -07001414 prefix, "synced-switch-activated",
1415 "A switch has completed the handshake as " +
Saurav Dasfcdad072014-08-13 14:15:21 -07001416 "MASTER. The switch was known to another " +
1417 "controller in the cluster",
Brian O'Connorc67f9fa2014-08-07 18:17:46 -07001418 CounterType.ALWAYS_COUNT);
1419
1420 readyForReconcile =
Saurav Dasfcdad072014-08-13 14:15:21 -07001421 debugCounters.registerCounter(
Brian O'Connorc67f9fa2014-08-07 18:17:46 -07001422 prefix, "ready-for-reconcile",
1423 "Controller is ready for flow reconciliation " +
Saurav Dasfcdad072014-08-13 14:15:21 -07001424 "after Slave to Master transition. Either all " +
1425 "previously known switches are now active " +
1426 "or they have timed out and have been removed." +
1427 "This counter will be 0 or 1.",
Brian O'Connorc67f9fa2014-08-07 18:17:46 -07001428 CounterType.ALWAYS_COUNT);
1429
1430 newSwitchFromStore =
Saurav Dasfcdad072014-08-13 14:15:21 -07001431 debugCounters.registerCounter(
Brian O'Connorc67f9fa2014-08-07 18:17:46 -07001432 prefix, "new-switch-from-store",
1433 "A new switch has connected to another " +
Saurav Dasfcdad072014-08-13 14:15:21 -07001434 "another controller in the cluster. This " +
1435 "controller instance has received a sync store " +
1436 "notification for it.",
Brian O'Connorc67f9fa2014-08-07 18:17:46 -07001437 CounterType.ALWAYS_COUNT);
1438
1439 updatedSwitchFromStore =
Saurav Dasfcdad072014-08-13 14:15:21 -07001440 debugCounters.registerCounter(
Brian O'Connorc67f9fa2014-08-07 18:17:46 -07001441 prefix, "updated-switch-from-store",
1442 "Information about a switch connected to " +
Saurav Dasfcdad072014-08-13 14:15:21 -07001443 "another controller instance was updated in " +
1444 "the sync store. This controller instance has " +
1445 "received a notification for it",
Brian O'Connorc67f9fa2014-08-07 18:17:46 -07001446 CounterType.ALWAYS_COUNT);
1447
1448 switchDisconnected =
Saurav Dasfcdad072014-08-13 14:15:21 -07001449 debugCounters.registerCounter(
Brian O'Connorc67f9fa2014-08-07 18:17:46 -07001450 prefix, "switch-disconnected",
1451 "FIXME: switch has disconnected",
1452 CounterType.ALWAYS_COUNT);
1453
1454 syncedSwitchRemoved =
Saurav Dasfcdad072014-08-13 14:15:21 -07001455 debugCounters.registerCounter(
Brian O'Connorc67f9fa2014-08-07 18:17:46 -07001456 prefix, "synced-switch-removed",
1457 "A switch connected to another controller " +
Saurav Dasfcdad072014-08-13 14:15:21 -07001458 "instance has disconnected from the controller " +
1459 "cluster. This controller instance has " +
1460 "received a notification for it",
Brian O'Connorc67f9fa2014-08-07 18:17:46 -07001461 CounterType.ALWAYS_COUNT);
1462
1463 unknownSwitchRemovedFromStore =
Saurav Dasfcdad072014-08-13 14:15:21 -07001464 debugCounters.registerCounter(
Brian O'Connorc67f9fa2014-08-07 18:17:46 -07001465 prefix, "unknown-switch-removed-from-store",
1466 "This controller instances has received a sync " +
Saurav Dasfcdad072014-08-13 14:15:21 -07001467 "store notification that a switch has " +
1468 "disconnected but this controller instance " +
1469 "did not have the any information about the " +
1470 "switch", // might be less than warning
Brian O'Connorc67f9fa2014-08-07 18:17:46 -07001471 CounterType.ALWAYS_COUNT,
1472 IDebugCounterService.CTR_MDATA_WARN);
1473
1474 consolidateStoreRunCount =
Saurav Dasfcdad072014-08-13 14:15:21 -07001475 debugCounters.registerCounter(
Brian O'Connorc67f9fa2014-08-07 18:17:46 -07001476 prefix, "consolidate-store-run-count",
1477 "This controller has transitioned from SLAVE " +
Saurav Dasfcdad072014-08-13 14:15:21 -07001478 "to MASTER and waited for switches to reconnect. " +
1479 "The controller has finished waiting and has " +
1480 "reconciled switch entries in the sync store " +
1481 "with live state",
Brian O'Connorc67f9fa2014-08-07 18:17:46 -07001482 CounterType.ALWAYS_COUNT);
1483
1484 consolidateStoreInconsistencies =
1485 debugCounters.registerCounter(
Saurav Dasfcdad072014-08-13 14:15:21 -07001486 prefix, "consolidate-store-inconsistencies",
1487 "During switch sync store consolidation: " +
1488 "Number of switches that were in the store " +
1489 "but not otherwise known plus number of " +
1490 "switches that were in the store previously " +
1491 "but are now missing plus number of " +
1492 "connected switches that were absent from " +
1493 "the store although this controller has " +
1494 "written them. A non-zero count " +
1495 "indicates a brief split-brain dual MASTER " +
1496 "situation during fail-over",
1497 CounterType.ALWAYS_COUNT);
Brian O'Connorc67f9fa2014-08-07 18:17:46 -07001498
1499 storeSyncError =
Saurav Dasfcdad072014-08-13 14:15:21 -07001500 debugCounters.registerCounter(
Brian O'Connorc67f9fa2014-08-07 18:17:46 -07001501 prefix, "store-sync-error",
1502 "Number of times a sync store operation failed " +
Saurav Dasfcdad072014-08-13 14:15:21 -07001503 "due to a store sync exception or an entry in " +
1504 "in the store had invalid data.",
Brian O'Connorc67f9fa2014-08-07 18:17:46 -07001505 CounterType.ALWAYS_COUNT,
1506 IDebugCounterService.CTR_MDATA_ERROR);
1507
1508 switchesNotReconnectingToNewMaster =
Saurav Dasfcdad072014-08-13 14:15:21 -07001509 debugCounters.registerCounter(
Brian O'Connorc67f9fa2014-08-07 18:17:46 -07001510 prefix, "switches-not-reconnecting-to-new-master",
1511 "Switches that were connected to another " +
Saurav Dasfcdad072014-08-13 14:15:21 -07001512 "controller instance in the cluster but that " +
1513 "did not reconnect to this controller after it " +
1514 "transitioned to MASTER", // might be less
1515 // than warning
Brian O'Connorc67f9fa2014-08-07 18:17:46 -07001516 CounterType.ALWAYS_COUNT);
1517
1518 switchPortChanged =
Saurav Dasfcdad072014-08-13 14:15:21 -07001519 debugCounters.registerCounter(
Brian O'Connorc67f9fa2014-08-07 18:17:46 -07001520 prefix, "switch-port-changed",
1521 "Number of times switch ports have changed",
1522 CounterType.ALWAYS_COUNT);
1523 switchOtherChange =
Saurav Dasfcdad072014-08-13 14:15:21 -07001524 debugCounters.registerCounter(
Brian O'Connorc67f9fa2014-08-07 18:17:46 -07001525 prefix, "switch-other-change",
1526 "Number of times other information of a switch " +
Saurav Dasfcdad072014-08-13 14:15:21 -07001527 "has changed.",
Brian O'Connorc67f9fa2014-08-07 18:17:46 -07001528 CounterType.ALWAYS_COUNT);
1529
1530 dispatchMessageWhileSlave =
Saurav Dasfcdad072014-08-13 14:15:21 -07001531 debugCounters.registerCounter(
Brian O'Connorc67f9fa2014-08-07 18:17:46 -07001532 prefix, "dispatch-message-while-slave",
1533 "Number of times an OF message was received " +
Saurav Dasfcdad072014-08-13 14:15:21 -07001534 "and supposed to be dispatched but the " +
1535 "controller was in SLAVE role and the message " +
1536 "was not dispatched",
Brian O'Connorc67f9fa2014-08-07 18:17:46 -07001537 CounterType.ALWAYS_COUNT);
1538
Saurav Dasfcdad072014-08-13 14:15:21 -07001539 dispatchMessage = // does this cnt make sense? more specific?? per
1540 // type? count stops?
1541 debugCounters.registerCounter(
1542 prefix, "dispatch-message",
1543 "Number of times an OF message was dispatched " +
Brian O'Connorc67f9fa2014-08-07 18:17:46 -07001544 "to registered modules",
Saurav Dasfcdad072014-08-13 14:15:21 -07001545 CounterType.ALWAYS_COUNT);
Brian O'Connorc67f9fa2014-08-07 18:17:46 -07001546
1547 controllerNodeIpsChanged =
Saurav Dasfcdad072014-08-13 14:15:21 -07001548 debugCounters.registerCounter(
Brian O'Connorc67f9fa2014-08-07 18:17:46 -07001549 prefix, "controller-nodes-ips-changed",
1550 "IP addresses of controller nodes have changed",
1551 CounterType.ALWAYS_COUNT);
1552
Saurav Dasfcdad072014-08-13 14:15:21 -07001553 // ------------------------
1554 // channel handler counters. Factor them out ??
Brian O'Connorc67f9fa2014-08-07 18:17:46 -07001555 messageReceived =
Saurav Dasfcdad072014-08-13 14:15:21 -07001556 debugCounters.registerCounter(
Brian O'Connorc67f9fa2014-08-07 18:17:46 -07001557 prefix, "message-received",
1558 "Number of OpenFlow messages received. Some of " +
Saurav Dasfcdad072014-08-13 14:15:21 -07001559 "these might be throttled",
Brian O'Connorc67f9fa2014-08-07 18:17:46 -07001560 CounterType.ALWAYS_COUNT);
1561 messageInputThrottled =
Saurav Dasfcdad072014-08-13 14:15:21 -07001562 debugCounters.registerCounter(
Brian O'Connorc67f9fa2014-08-07 18:17:46 -07001563 prefix, "message-input-throttled",
1564 "Number of OpenFlow messages that were " +
Saurav Dasfcdad072014-08-13 14:15:21 -07001565 "throttled due to high load from the sender",
Brian O'Connorc67f9fa2014-08-07 18:17:46 -07001566 CounterType.ALWAYS_COUNT,
1567 IDebugCounterService.CTR_MDATA_WARN);
Saurav Dasfcdad072014-08-13 14:15:21 -07001568 // TODO: more counters in messageReceived ??
Brian O'Connorc67f9fa2014-08-07 18:17:46 -07001569
1570 switchDisconnectReadTimeout =
Saurav Dasfcdad072014-08-13 14:15:21 -07001571 debugCounters.registerCounter(
Brian O'Connorc67f9fa2014-08-07 18:17:46 -07001572 prefix, "switch-disconnect-read-timeout",
1573 "Number of times a switch was disconnected due " +
Saurav Dasfcdad072014-08-13 14:15:21 -07001574 "due the switch failing to send OpenFlow " +
1575 "messages or responding to OpenFlow ECHOs",
Brian O'Connorc67f9fa2014-08-07 18:17:46 -07001576 CounterType.ALWAYS_COUNT,
1577 IDebugCounterService.CTR_MDATA_ERROR);
1578 switchDisconnectHandshakeTimeout =
Saurav Dasfcdad072014-08-13 14:15:21 -07001579 debugCounters.registerCounter(
Brian O'Connorc67f9fa2014-08-07 18:17:46 -07001580 prefix, "switch-disconnect-handshake-timeout",
1581 "Number of times a switch was disconnected " +
Saurav Dasfcdad072014-08-13 14:15:21 -07001582 "because it failed to complete the handshake " +
1583 "in time.",
Brian O'Connorc67f9fa2014-08-07 18:17:46 -07001584 CounterType.ALWAYS_COUNT,
1585 IDebugCounterService.CTR_MDATA_ERROR);
1586 switchDisconnectIOError =
Saurav Dasfcdad072014-08-13 14:15:21 -07001587 debugCounters.registerCounter(
Brian O'Connorc67f9fa2014-08-07 18:17:46 -07001588 prefix, "switch-disconnect-io-error",
1589 "Number of times a switch was disconnected " +
Saurav Dasfcdad072014-08-13 14:15:21 -07001590 "due to IO errors on the switch connection.",
Brian O'Connorc67f9fa2014-08-07 18:17:46 -07001591 CounterType.ALWAYS_COUNT,
1592 IDebugCounterService.CTR_MDATA_ERROR);
1593 switchDisconnectParseError =
Saurav Dasfcdad072014-08-13 14:15:21 -07001594 debugCounters.registerCounter(
Brian O'Connorc67f9fa2014-08-07 18:17:46 -07001595 prefix, "switch-disconnect-parse-error",
Saurav Dasfcdad072014-08-13 14:15:21 -07001596 "Number of times a switch was disconnected " +
1597 "because it sent an invalid packet that could " +
1598 "not be parsed",
1599 CounterType.ALWAYS_COUNT,
1600 IDebugCounterService.CTR_MDATA_ERROR);
Brian O'Connorc67f9fa2014-08-07 18:17:46 -07001601
1602 switchDisconnectSwitchStateException =
Saurav Dasfcdad072014-08-13 14:15:21 -07001603 debugCounters.registerCounter(
Brian O'Connorc67f9fa2014-08-07 18:17:46 -07001604 prefix, "switch-disconnect-switch-state-exception",
1605 "Number of times a switch was disconnected " +
Saurav Dasfcdad072014-08-13 14:15:21 -07001606 "because it sent messages that were invalid " +
1607 "given the switch connection's state.",
Brian O'Connorc67f9fa2014-08-07 18:17:46 -07001608 CounterType.ALWAYS_COUNT,
1609 IDebugCounterService.CTR_MDATA_ERROR);
1610 rejectedExecutionException =
Saurav Dasfcdad072014-08-13 14:15:21 -07001611 debugCounters.registerCounter(
Brian O'Connorc67f9fa2014-08-07 18:17:46 -07001612 prefix, "rejected-execution-exception",
1613 "TODO",
1614 CounterType.ALWAYS_COUNT,
1615 IDebugCounterService.CTR_MDATA_ERROR);
1616
1617 switchDisconnectOtherException =
Saurav Dasfcdad072014-08-13 14:15:21 -07001618 debugCounters.registerCounter(
1619 prefix, "switch-disconnect-other-exception",
Brian O'Connorc67f9fa2014-08-07 18:17:46 -07001620 "Number of times a switch was disconnected " +
Saurav Dasfcdad072014-08-13 14:15:21 -07001621 "due to an exceptional situation not covered " +
1622 "by other counters",
Brian O'Connorc67f9fa2014-08-07 18:17:46 -07001623 CounterType.ALWAYS_COUNT,
1624 IDebugCounterService.CTR_MDATA_ERROR);
1625
1626 switchConnected =
Saurav Dasfcdad072014-08-13 14:15:21 -07001627 debugCounters.registerCounter(
Brian O'Connorc67f9fa2014-08-07 18:17:46 -07001628 prefix, "switch-connected",
1629 "Number of times a new switch connection was " +
Saurav Dasfcdad072014-08-13 14:15:21 -07001630 "established",
Brian O'Connorc67f9fa2014-08-07 18:17:46 -07001631 CounterType.ALWAYS_COUNT);
1632
1633 unhandledMessage =
Saurav Dasfcdad072014-08-13 14:15:21 -07001634 debugCounters.registerCounter(
Brian O'Connorc67f9fa2014-08-07 18:17:46 -07001635 prefix, "unhandled-message",
1636 "Number of times an OpenFlow message was " +
Saurav Dasfcdad072014-08-13 14:15:21 -07001637 "received that the controller ignored because " +
1638 "it was inapproriate given the switch " +
1639 "connection's state.",
Brian O'Connorc67f9fa2014-08-07 18:17:46 -07001640 CounterType.ALWAYS_COUNT,
1641 IDebugCounterService.CTR_MDATA_WARN);
Saurav Dasfcdad072014-08-13 14:15:21 -07001642 // might be less than warning
Brian O'Connorc67f9fa2014-08-07 18:17:46 -07001643
1644 packetInWhileSwitchIsSlave =
Saurav Dasfcdad072014-08-13 14:15:21 -07001645 debugCounters.registerCounter(
Brian O'Connorc67f9fa2014-08-07 18:17:46 -07001646 prefix, "packet-in-while-switch-is-slave",
1647 "Number of times a packet in was received " +
Saurav Dasfcdad072014-08-13 14:15:21 -07001648 "from a switch that was in SLAVE role. " +
1649 "Possibly inidicates inconsistent roles.",
Brian O'Connorc67f9fa2014-08-07 18:17:46 -07001650 CounterType.ALWAYS_COUNT);
1651 epermErrorWhileSwitchIsMaster =
Saurav Dasfcdad072014-08-13 14:15:21 -07001652 debugCounters.registerCounter(
Brian O'Connorc67f9fa2014-08-07 18:17:46 -07001653 prefix, "eperm-error-while-switch-is-master",
1654 "Number of times a permission error was " +
Saurav Dasfcdad072014-08-13 14:15:21 -07001655 "received while the switch was in MASTER role. " +
1656 "Possibly inidicates inconsistent roles.",
Brian O'Connorc67f9fa2014-08-07 18:17:46 -07001657 CounterType.ALWAYS_COUNT,
1658 IDebugCounterService.CTR_MDATA_WARN);
1659
1660 roleNotResentBecauseRolePending =
Saurav Dasfcdad072014-08-13 14:15:21 -07001661 debugCounters.registerCounter(
Brian O'Connorc67f9fa2014-08-07 18:17:46 -07001662 prefix, "role-not-resent-because-role-pending",
1663 "The controller tried to reestablish a role " +
Saurav Dasfcdad072014-08-13 14:15:21 -07001664 "with a switch but did not do so because a " +
1665 "previous role request was still pending",
Brian O'Connorc67f9fa2014-08-07 18:17:46 -07001666 CounterType.ALWAYS_COUNT);
1667 roleRequestSent =
Saurav Dasfcdad072014-08-13 14:15:21 -07001668 debugCounters.registerCounter(
Brian O'Connorc67f9fa2014-08-07 18:17:46 -07001669 prefix, "role-request-sent",
1670 "Number of times the controller sent a role " +
Saurav Dasfcdad072014-08-13 14:15:21 -07001671 "request to a switch.",
Brian O'Connorc67f9fa2014-08-07 18:17:46 -07001672 CounterType.ALWAYS_COUNT);
1673 roleReplyTimeout =
Saurav Dasfcdad072014-08-13 14:15:21 -07001674 debugCounters.registerCounter(
Brian O'Connorc67f9fa2014-08-07 18:17:46 -07001675 prefix, "role-reply-timeout",
1676 "Number of times a role request message did not " +
Saurav Dasfcdad072014-08-13 14:15:21 -07001677 "receive the expected reply from a switch",
Brian O'Connorc67f9fa2014-08-07 18:17:46 -07001678 CounterType.ALWAYS_COUNT,
1679 IDebugCounterService.CTR_MDATA_WARN);
1680
1681 roleReplyReceived = // expected RoleReply received
Saurav Dasfcdad072014-08-13 14:15:21 -07001682 debugCounters.registerCounter(
1683 prefix, "role-reply-received",
1684 "Number of times the controller received the " +
Brian O'Connorc67f9fa2014-08-07 18:17:46 -07001685 "expected role reply message from a switch",
Saurav Dasfcdad072014-08-13 14:15:21 -07001686 CounterType.ALWAYS_COUNT);
Brian O'Connorc67f9fa2014-08-07 18:17:46 -07001687
1688 roleReplyErrorUnsupported =
Saurav Dasfcdad072014-08-13 14:15:21 -07001689 debugCounters.registerCounter(
Brian O'Connorc67f9fa2014-08-07 18:17:46 -07001690 prefix, "role-reply-error-unsupported",
1691 "Number of times the controller received an " +
Saurav Dasfcdad072014-08-13 14:15:21 -07001692 "error from a switch in response to a role " +
1693 "request indicating that the switch does not " +
1694 "support roles.",
Brian O'Connorc67f9fa2014-08-07 18:17:46 -07001695 CounterType.ALWAYS_COUNT);
1696
1697 switchCounterRegistrationFailed =
1698 debugCounters.registerCounter(prefix,
Saurav Dasfcdad072014-08-13 14:15:21 -07001699 "switch-counter-registration-failed",
1700 "Number of times the controller failed to " +
1701 "register per-switch debug counters",
1702 CounterType.ALWAYS_COUNT,
1703 IDebugCounterService.CTR_MDATA_WARN);
Brian O'Connorc67f9fa2014-08-07 18:17:46 -07001704
1705 packetParsingError =
1706 debugCounters.registerCounter(prefix,
Saurav Dasfcdad072014-08-13 14:15:21 -07001707 "packet-parsing-error",
1708 "Number of times the packet parsing " +
1709 "encountered an error",
1710 CounterType.ALWAYS_COUNT,
1711 IDebugCounterService.CTR_MDATA_ERROR);
Brian O'Connorc67f9fa2014-08-07 18:17:46 -07001712 }
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -08001713 }
1714
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -08001715 @Override
Brian O'Connorc67f9fa2014-08-07 18:17:46 -07001716 public Counters getCounters() {
1717 return this.counters;
1718 }
1719
1720 // **************
1721 // debugEvent registrations
1722 // **************
1723
1724 private void registerControllerDebugEvents() throws FloodlightModuleException {
1725 if (debugEvents == null) {
1726 debugEvents = new NullDebugEvent();
1727 }
1728 try {
1729 evSwitch = debugEvents.registerEvent(
Saurav Dasfcdad072014-08-13 14:15:21 -07001730 Counters.prefix, "switchevent",
1731 "Switch connected, disconnected or port changed",
1732 EventType.ALWAYS_LOG, SwitchEvent.class, 100);
Brian O'Connorc67f9fa2014-08-07 18:17:46 -07001733 } catch (MaxEventsRegistered e) {
1734 throw new FloodlightModuleException("Max events registered", e);
1735 }
1736 }
1737
1738 public class SwitchEvent {
1739 @EventColumn(name = "dpid", description = EventFieldType.DPID)
1740 long dpid;
1741
1742 @EventColumn(name = "reason", description = EventFieldType.STRING)
1743 String reason;
1744
1745 public SwitchEvent(long dpid, String reason) {
1746 this.dpid = dpid;
1747 this.reason = reason;
1748 }
1749 }
1750
1751 // **************
1752 // Utility methods
1753 // **************
1754
1755 @Override
1756 public void setAlwaysClearFlowsOnSwActivate(boolean value) {
Saurav Dasfcdad072014-08-13 14:15:21 -07001757 // this.alwaysClearFlowsOnSwActivate = value;
Brian O'Connorc67f9fa2014-08-07 18:17:46 -07001758 // XXX S need to be a little more careful about this
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -08001759 }
1760
1761 @Override
Brian O'Connorc67f9fa2014-08-07 18:17:46 -07001762 public Map<String, Long> getMemory() {
1763 Map<String, Long> m = new HashMap<String, Long>();
1764 Runtime runtime = Runtime.getRuntime();
1765 m.put("total", runtime.totalMemory());
1766 m.put("free", runtime.freeMemory());
1767 return m;
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -08001768 }
Ray Milkey269ffb92014-04-03 14:43:30 -07001769
Brian O'Connorc67f9fa2014-08-07 18:17:46 -07001770 @Override
1771 public Long getUptime() {
1772 RuntimeMXBean rb = ManagementFactory.getRuntimeMXBean();
1773 return rb.getUptime();
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -08001774 }
Brian O'Connorc67f9fa2014-08-07 18:17:46 -07001775
1776 /**
1777 * Forward to the driver-manager to get an IOFSwitch instance.
Saurav Dasfcdad072014-08-13 14:15:21 -07001778 *
Brian O'Connorc67f9fa2014-08-07 18:17:46 -07001779 * @param desc
1780 * @return
1781 */
1782 protected IOFSwitch getOFSwitchInstance(OFDescStatsReply desc, OFVersion ofv) {
1783 return DriverManager.getOFSwitchImpl(desc, ofv);
1784 }
1785
1786 protected IThreadPoolService getThreadPoolService() {
1787 return this.threadPool;
1788 }
1789
1790 /**
Saurav Dasfcdad072014-08-13 14:15:21 -07001791 * Part of the controller updates framework (see 'run()' method) Use this
1792 * method to add an IUpdate. A thread-pool will serve the update by
1793 * dispatching it to all listeners for that update.
1794 *
Brian O'Connorc67f9fa2014-08-07 18:17:46 -07001795 * @param update
1796 */
Saurav Dasfcdad072014-08-13 14:15:21 -07001797 @LogMessageDoc(level = "WARN",
1798 message = "Failure adding update {} to queue",
1799 explanation = "The controller tried to add an internal notification" +
1800 " to its message queue but the add failed.",
1801 recommendation = LogMessageDoc.REPORT_CONTROLLER_BUG)
Brian O'Connorc67f9fa2014-08-07 18:17:46 -07001802 private void addUpdateToQueue(IUpdate update) {
1803 try {
1804 this.updates.put(update);
1805 } catch (InterruptedException e) {
1806 // This should never happen
1807 log.error("Failure adding update {} to queue.", update);
1808 }
1809 }
1810
1811 void flushAll() {
1812 // Flush all flow-mods/packet-out/stats generated from this "train"
1813 OFSwitchImplBase.flush_all();
1814 debugCounters.flushCounters();
1815 debugEvents.flushEvents();
1816 }
1817
1818 /**
1819 * flcontext_free - Free the context to the current thread
Saurav Dasfcdad072014-08-13 14:15:21 -07001820 *
Brian O'Connorc67f9fa2014-08-07 18:17:46 -07001821 * @param flcontext
1822 */
1823 protected void flcontext_free(FloodlightContext flcontext) {
1824 flcontext.getStorage().clear();
1825 flcontext_cache.get().push(flcontext);
1826 }
1827
1828 @LogMessageDoc(message = "Calling System.exit",
1829 explanation = "The controller is terminating")
1830 private synchronized void terminate() {
1831 log.info("Calling System.exit");
1832 System.exit(1);
1833 }
1834
Brian O'Connorc67f9fa2014-08-07 18:17:46 -07001835 // ***************
1836 // Floodlight context related
1837 // ***************
1838
1839 /**
1840 * flcontext_cache - Keep a thread local stack of contexts
1841 */
1842 protected static final ThreadLocal<Stack<FloodlightContext>> flcontext_cache =
1843 new ThreadLocal<Stack<FloodlightContext>>() {
1844 @Override
1845 protected Stack<FloodlightContext> initialValue() {
1846 return new Stack<FloodlightContext>();
1847 }
1848 };
1849
1850 /**
Saurav Dasfcdad072014-08-13 14:15:21 -07001851 * flcontext_alloc - pop a context off the stack, if required create a new
1852 * one
1853 *
Brian O'Connorc67f9fa2014-08-07 18:17:46 -07001854 * @return FloodlightContext
1855 */
1856 protected static FloodlightContext flcontext_alloc() {
1857 FloodlightContext flcontext = null;
1858
1859 if (flcontext_cache.get().empty()) {
1860 flcontext = new FloodlightContext();
1861 } else {
1862 flcontext = flcontext_cache.get().pop();
1863 }
1864
1865 return flcontext;
1866 }
1867
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -08001868}