blob: 1f0b36db4b43072755c66e6a999f6d84e67b4d81 [file] [log] [blame]
alshabib1f44e8e2014-08-14 15:19:57 -07001/**
2 * 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 **/
17
tom9ccd7812014-08-25 22:43:19 -070018package org.onlab.onos.of.controller.impl.internal;
alshabib1f44e8e2014-08-14 15:19:57 -070019
20import java.lang.management.ManagementFactory;
21import java.lang.management.RuntimeMXBean;
22import java.net.InetSocketAddress;
23import java.net.UnknownHostException;
24import java.util.Collections;
25import java.util.HashMap;
26import java.util.HashSet;
27import java.util.Map;
28import java.util.Set;
29import java.util.concurrent.ConcurrentHashMap;
30import java.util.concurrent.Executors;
31
tom9ccd7812014-08-25 22:43:19 -070032import org.onlab.onos.of.controller.impl.IOFSwitchManager;
33import org.onlab.onos.of.controller.impl.Role;
34import org.onlab.onos.of.controller.impl.annotations.LogMessageDoc;
35import org.onlab.onos.of.controller.impl.annotations.LogMessageDocs;
36import org.onlab.onos.of.controller.impl.debugcounter.DebugCounter;
37import org.onlab.onos.of.controller.impl.debugcounter.IDebugCounter;
38import org.onlab.onos.of.controller.impl.debugcounter.IDebugCounterService;
39import org.onlab.onos.of.controller.impl.debugcounter.IDebugCounterService.CounterException;
40import org.onlab.onos.of.controller.impl.debugcounter.IDebugCounterService.CounterType;
41import org.onlab.onos.of.controller.impl.internal.OFChannelHandler.RoleRecvStatus;
42import org.onlab.onos.of.controller.impl.registry.IControllerRegistry;
43import org.onlab.onos.of.controller.impl.registry.RegistryException;
44import org.onlab.onos.of.controller.impl.registry.IControllerRegistry.ControlChangeCallback;
45import org.onlab.onos.of.controller.impl.util.Dpid;
46import org.onlab.onos.of.controller.impl.util.DummySwitchForTesting;
47import org.onlab.onos.of.controller.impl.util.InstanceId;
48import org.onlab.onos.of.controller.impl.IOFSwitch;
49import org.onlab.onos.of.controller.impl.IOFSwitch.PortChangeType;
alshabib1f44e8e2014-08-14 15:19:57 -070050
51import org.apache.felix.scr.annotations.Activate;
52import org.apache.felix.scr.annotations.Component;
53import org.jboss.netty.bootstrap.ServerBootstrap;
54import org.jboss.netty.channel.ChannelPipelineFactory;
55import org.jboss.netty.channel.group.ChannelGroup;
56import org.jboss.netty.channel.group.DefaultChannelGroup;
57import org.jboss.netty.channel.socket.nio.NioServerSocketChannelFactory;
58import org.projectfloodlight.openflow.protocol.OFDescStatsReply;
59import org.projectfloodlight.openflow.protocol.OFFactories;
60import org.projectfloodlight.openflow.protocol.OFFactory;
61import org.projectfloodlight.openflow.protocol.OFPortDesc;
62import org.projectfloodlight.openflow.protocol.OFVersion;
63import org.projectfloodlight.openflow.util.HexString;
64import org.slf4j.Logger;
65import org.slf4j.LoggerFactory;
66
67
68/**
69 * The main controller class. Handles all setup and network listeners
70 * - Distributed ownership control of switch through IControllerRegistryService
71 */
72@Component(immediate = true)
73public class Controller {
74
75 protected static final Logger log = LoggerFactory.getLogger(Controller.class);
76 static final String ERROR_DATABASE =
77 "The controller could not communicate with the system database.";
78 protected static final OFFactory FACTORY13 = OFFactories.getFactory(OFVersion.OF_13);
79 protected static final OFFactory FACTORY10 = OFFactories.getFactory(OFVersion.OF_10);
80
81 // connectedSwitches cache contains all connected switch's channelHandlers
82 // including ones where this controller is a master/equal/slave controller
83 // as well as ones that have not been activated yet
84 protected ConcurrentHashMap<Long, OFChannelHandler> connectedSwitches;
85 // These caches contains only those switches that are active
86 protected ConcurrentHashMap<Long, IOFSwitch> activeMasterSwitches;
87 protected ConcurrentHashMap<Long, IOFSwitch> activeEqualSwitches;
88 // lock to synchronize on, when manipulating multiple caches above
89 private Object multiCacheLock;
90
91 // The controllerNodeIPsCache maps Controller IDs to their IP address.
92 // It's only used by handleControllerNodeIPsChanged
93 protected HashMap<String, String> controllerNodeIPsCache;
94
95 // Module dependencies
96
97 protected IControllerRegistry registryService;
98 protected IDebugCounterService debugCounters;
99
100
101 private IOFSwitchManager switchManager;
102
103 // Configuration options
104 protected int openFlowPort = 6633;
105 protected int workerThreads = 0;
106
107 // defined counters
108 private Counters counters;
109
110 // Start time of the controller
111 protected long systemStartTime;
112
113 // Flag to always flush flow table on switch reconnect (HA or otherwise)
114 protected boolean alwaysClearFlowsOnSwAdd = false;
115 private InstanceId instanceId;
116
117 // Perf. related configuration
118 protected static final int SEND_BUFFER_SIZE = 4 * 1024 * 1024;
119 protected static final int BATCH_MAX_SIZE = 100;
120 protected static final boolean ALWAYS_DECODE_ETH = true;
121
122 protected boolean addConnectedSwitch(long dpid, OFChannelHandler h) {
123 if (connectedSwitches.get(dpid) != null) {
124 log.error("Trying to add connectedSwitch but found a previous "
125 + "value for dpid: {}", dpid);
126 return false;
127 } else {
128 log.error("Added switch {}", dpid);
129 connectedSwitches.put(dpid, h);
130 return true;
131 }
132 }
133
134 private boolean validActivation(long dpid) {
135 if (connectedSwitches.get(dpid) == null) {
136 log.error("Trying to activate switch but is not in "
137 + "connected switches: dpid {}. Aborting ..",
138 HexString.toHexString(dpid));
139 return false;
140 }
141 if (activeMasterSwitches.get(dpid) != null ||
142 activeEqualSwitches.get(dpid) != null) {
143 log.error("Trying to activate switch but it is already "
144 + "activated: dpid {}. Found in activeMaster: {} "
145 + "Found in activeEqual: {}. Aborting ..", new Object[] {
146 HexString.toHexString(dpid),
alshabib3b554cf2014-08-18 11:19:50 -0500147 (activeMasterSwitches.get(dpid) == null) ? 'N' : 'Y',
148 (activeEqualSwitches.get(dpid) == null) ? 'N' : 'Y'});
alshabib1f44e8e2014-08-14 15:19:57 -0700149 counters.switchWithSameDpidActivated.updateCounterWithFlush();
150 return false;
151 }
152 return true;
153 }
154
155 /**
156 * Called when a switch is activated, with this controller's role as MASTER.
157 */
158 protected boolean addActivatedMasterSwitch(long dpid, IOFSwitch sw) {
159 synchronized (multiCacheLock) {
160 if (!validActivation(dpid)) {
161 return false;
162 }
163 activeMasterSwitches.put(dpid, sw);
164 }
165 //update counters and events
166 counters.switchActivated.updateCounterWithFlush();
167
168 return true;
169 }
170
171 /**
172 * Called when a switch is activated, with this controller's role as EQUAL.
173 */
174 protected boolean addActivatedEqualSwitch(long dpid, IOFSwitch sw) {
175 synchronized (multiCacheLock) {
176 if (!validActivation(dpid)) {
177 return false;
178 }
179 activeEqualSwitches.put(dpid, sw);
180 }
181 //update counters and events
182 counters.switchActivated.updateCounterWithFlush();
183 return true;
184 }
185
186 /**
187 * Called when this controller's role for a switch transitions from equal
188 * to master. For 1.0 switches, we internally refer to the role 'slave' as
189 * 'equal' - so this transition is equivalent to 'addActivatedMasterSwitch'.
190 */
191 protected void transitionToMasterSwitch(long dpid) {
192 synchronized (multiCacheLock) {
193 IOFSwitch sw = activeEqualSwitches.remove(dpid);
194 if (sw == null) {
195 log.error("Transition to master called on sw {}, but switch "
196 + "was not found in controller-cache", dpid);
197 return;
198 }
199 activeMasterSwitches.put(dpid, sw);
200 }
201 }
202
203
204 /**
205 * Called when this controller's role for a switch transitions to equal.
206 * For 1.0 switches, we internally refer to the role 'slave' as
207 * 'equal'.
208 */
209 protected void transitionToEqualSwitch(long dpid) {
210 synchronized (multiCacheLock) {
211 IOFSwitch sw = activeMasterSwitches.remove(dpid);
212 if (sw == null) {
213 log.error("Transition to equal called on sw {}, but switch "
214 + "was not found in controller-cache", dpid);
215 return;
216 }
217 activeEqualSwitches.put(dpid, sw);
218 }
219
220 }
221
222 /**
223 * Clear all state in controller switch maps for a switch that has
224 * disconnected from the local controller. Also release control for
225 * that switch from the global repository. Notify switch listeners.
226 */
227 protected void removeConnectedSwitch(long dpid) {
228 releaseRegistryControl(dpid);
229 connectedSwitches.remove(dpid);
230 IOFSwitch sw = activeMasterSwitches.remove(dpid);
231 if (sw == null) {
232 sw = activeEqualSwitches.remove(dpid);
233 }
234 if (sw != null) {
235 sw.cancelAllStatisticsReplies();
236 sw.setConnected(false); // do we need this?
237 }
238 counters.switchDisconnected.updateCounterWithFlush();
239
240 }
241
242 /**
243 * Indicates that ports on the given switch have changed. Enqueue a
244 * switch update.
tom9ccd7812014-08-25 22:43:19 -0700245 * @param dpid
246 * @param port
247 * @param changeType
alshabib1f44e8e2014-08-14 15:19:57 -0700248 */
249 protected void notifyPortChanged(long dpid, OFPortDesc port,
250 PortChangeType changeType) {
251 if (port == null || changeType == null) {
252 String msg = String.format("Switch port or changetType must not "
253 + "be null in port change notification");
254 throw new NullPointerException(msg);
255 }
256 if (connectedSwitches.get(dpid) == null || getSwitch(dpid) == null) {
257 log.warn("Port change update on switch {} not connected or activated "
258 + "... Aborting.", HexString.toHexString(dpid));
259 return;
260 }
261
262 }
263
264 // ***************
265 // Getters/Setters
266 // ***************
267
268
269 public synchronized void setIOFSwitchManager(IOFSwitchManager swManager) {
270 this.switchManager = swManager;
271 this.registryService = swManager.getRegistry();
272 }
273
274
275 public void setDebugCounter(IDebugCounterService dcs) {
276 this.debugCounters = dcs;
277 }
278
279 IDebugCounterService getDebugCounter() {
280 return this.debugCounters;
281 }
282
283 // **********************
284 // Role Handling
285 // **********************
286
287 /**
288 * created by ONOS - works with registry service.
289 */
290 protected class RoleChangeCallback implements ControlChangeCallback {
291 @Override
292 public void controlChanged(long dpidLong, boolean hasControl) {
293 Dpid dpid = new Dpid(dpidLong);
294 log.info("Role change callback for switch {}, hasControl {}",
295 dpid, hasControl);
296
297 Role role = null;
298
299 /*
300 * issue #229
301 * Cannot rely on sw.getRole() as it can be behind due to pending
302 * role changes in the queue. Just submit it and late the
303 * RoleChanger handle duplicates.
304 */
305
306 if (hasControl) {
307 role = Role.MASTER;
308 } else {
309 role = Role.EQUAL; // treat the same as Role.SLAVE
310 }
311
312 OFChannelHandler swCh = connectedSwitches.get(dpid.value());
313 if (swCh == null) {
314 log.warn("Switch {} not found in connected switches", dpid);
315 return;
316 }
317
318 log.debug("Sending role request {} msg to {}", role, dpid);
319 swCh.sendRoleRequest(role, RoleRecvStatus.MATCHED_SET_ROLE);
320 }
321 }
322
323 /**
324 * Submit request to the registry service for mastership of the
325 * switch.
326 * @param dpid this datapath to get role for
327 */
328 public synchronized void submitRegistryRequest(long dpid) {
329 if (registryService == null) {
330 /*
331 * If we have no registry then simply assign
332 * mastership to this controller.
333 */
334 new RoleChangeCallback().controlChanged(dpid, true);
335 return;
336 }
337 OFChannelHandler h = connectedSwitches.get(dpid);
338 if (h == null) {
339 log.error("Trying to request registry control for switch {} "
340 + "not in connected switches. Aborting.. ",
341 HexString.toHexString(dpid));
342 connectedSwitches.get(dpid).disconnectSwitch();
343 return;
344 }
345 //Request control of the switch from the global registry
346 try {
347 h.controlRequested = Boolean.TRUE;
348 registryService.requestControl(dpid, new RoleChangeCallback());
349 } catch (RegistryException e) {
350 log.debug("Registry error: {}", e.getMessage());
351 h.controlRequested = Boolean.FALSE;
352 }
353 if (!h.controlRequested) { // XXX what is being attempted here?
354 // yield to allow other thread(s) to release control
355 // TODO AAS: this is awful and needs to be fixed
356 Thread.yield();
357 // safer to bounce the switch to reconnect here than proceeding further
358 // XXX S why? can't we just try again a little later?
359 log.debug("Closing sw:{} because we weren't able to request control " +
360 "successfully" + dpid);
361 connectedSwitches.get(dpid).disconnectSwitch();
362 }
363 }
364
365 /**
366 * Relinquish role for the switch.
367 * @param dpidLong the controlled datapath
368 */
369 public synchronized void releaseRegistryControl(long dpidLong) {
370 OFChannelHandler h = connectedSwitches.get(dpidLong);
371 if (h == null) {
372 log.error("Trying to release registry control for switch {} "
373 + "not in connected switches. Aborting.. ",
374 HexString.toHexString(dpidLong));
375 return;
376 }
alshabib3b554cf2014-08-18 11:19:50 -0500377 if (registryService != null && h.controlRequested) {
378 //TODO the above is not good for testing need to change controlrequest to method call.
alshabib1f44e8e2014-08-14 15:19:57 -0700379 registryService.releaseControl(dpidLong);
380 }
381 }
382
383
alshabib1f44e8e2014-08-14 15:19:57 -0700384 // FIXME: remove this method
385 public Map<Long, IOFSwitch> getSwitches() {
386 return getMasterSwitches();
387 }
388
389 // FIXME: remove this method
390 public Map<Long, IOFSwitch> getMasterSwitches() {
391 return Collections.unmodifiableMap(activeMasterSwitches);
392 }
393
394
395
396 public Set<Long> getAllSwitchDpids() {
397 Set<Long> dpids = new HashSet<Long>();
398 dpids.addAll(activeMasterSwitches.keySet());
399 dpids.addAll(activeEqualSwitches.keySet());
400 return dpids;
401 }
402
403
404 public Set<Long> getAllMasterSwitchDpids() {
405 Set<Long> dpids = new HashSet<Long>();
406 dpids.addAll(activeMasterSwitches.keySet());
407 return dpids;
408 }
409
410
411 public Set<Long> getAllEqualSwitchDpids() {
412 Set<Long> dpids = new HashSet<Long>();
413 dpids.addAll(activeEqualSwitches.keySet());
414 return dpids;
415 }
416
417
418 public IOFSwitch getSwitch(long dpid) {
419 IOFSwitch sw = null;
420 sw = activeMasterSwitches.get(dpid);
421 if (sw != null) {
422 return sw;
423 }
424 sw = activeEqualSwitches.get(dpid);
425 if (sw != null) {
426 return sw;
427 }
428 return sw;
429 }
430
431
432 public IOFSwitch getMasterSwitch(long dpid) {
433 return activeMasterSwitches.get(dpid);
434 }
435
436
437 public IOFSwitch getEqualSwitch(long dpid) {
438 return activeEqualSwitches.get(dpid);
439 }
440
441
442
443
444
445 public OFFactory getOFMessageFactory10() {
446 return FACTORY10;
447 }
448
449
450 public OFFactory getOFMessageFactory13() {
451 return FACTORY13;
452 }
453
454
455
456 public Map<String, String> getControllerNodeIPs() {
457 // We return a copy of the mapping so we can guarantee that
458 // the mapping return is the same as one that will be (or was)
459 // dispatched to IHAListeners
460 HashMap<String, String> retval = new HashMap<String, String>();
461 synchronized (controllerNodeIPsCache) {
462 retval.putAll(controllerNodeIPsCache);
463 }
464 return retval;
465 }
466
467
468 public long getSystemStartTime() {
469 return (this.systemStartTime);
470 }
471
472
alshabib1f44e8e2014-08-14 15:19:57 -0700473 public InstanceId getInstanceId() {
474 return instanceId;
475 }
476
477
478 // **************
479 // Initialization
480 // **************
481
482 /**
483 * Tell controller that we're ready to accept switches loop.
alshabib1f44e8e2014-08-14 15:19:57 -0700484 */
485 @LogMessageDocs({
486 @LogMessageDoc(message = "Listening for switch connections on {address}",
487 explanation = "The controller is ready and listening for new" +
488 " switch connections"),
489 @LogMessageDoc(message = "Storage exception in controller " +
490 "updates loop; terminating process",
491 explanation = ERROR_DATABASE,
492 recommendation = LogMessageDoc.CHECK_CONTROLLER),
493 @LogMessageDoc(level = "ERROR",
494 message = "Exception in controller updates loop",
495 explanation = "Failed to dispatch controller event",
496 recommendation = LogMessageDoc.GENERIC_ACTION)
497 })
498 public void run() {
499
500 try {
501 final ServerBootstrap bootstrap = createServerBootStrap();
502
503 bootstrap.setOption("reuseAddr", true);
504 bootstrap.setOption("child.keepAlive", true);
505 bootstrap.setOption("child.tcpNoDelay", true);
506 bootstrap.setOption("child.sendBufferSize", Controller.SEND_BUFFER_SIZE);
507
508 ChannelPipelineFactory pfact =
509 new OpenflowPipelineFactory(this, null);
510 bootstrap.setPipelineFactory(pfact);
511 InetSocketAddress sa = new InetSocketAddress(openFlowPort);
512 final ChannelGroup cg = new DefaultChannelGroup();
513 cg.add(bootstrap.bind(sa));
514
515 log.info("Listening for switch connections on {}", sa);
516 } catch (Exception e) {
517 throw new RuntimeException(e);
518 }
519
520 }
521
522 private ServerBootstrap createServerBootStrap() {
523 if (workerThreads == 0) {
524 return new ServerBootstrap(
525 new NioServerSocketChannelFactory(
526 Executors.newCachedThreadPool(),
527 Executors.newCachedThreadPool()));
528 } else {
529 return new ServerBootstrap(
530 new NioServerSocketChannelFactory(
531 Executors.newCachedThreadPool(),
532 Executors.newCachedThreadPool(), workerThreads));
533 }
534 }
535
536 public void setConfigParams(Map<String, String> configParams) {
537 String ofPort = configParams.get("openflowport");
538 if (ofPort != null) {
539 this.openFlowPort = Integer.parseInt(ofPort);
540 }
541 log.debug("OpenFlow port set to {}", this.openFlowPort);
542 String threads = configParams.get("workerthreads");
543 if (threads != null) {
544 this.workerThreads = Integer.parseInt(threads);
545 }
546 log.debug("Number of worker threads set to {}", this.workerThreads);
547 String controllerId = configParams.get("controllerid");
548 if (controllerId != null) {
549 this.instanceId = new InstanceId(controllerId);
550 } else {
551 //Try to get the hostname of the machine and use that for controller ID
552 try {
553 String hostname = java.net.InetAddress.getLocalHost().getHostName();
554 this.instanceId = new InstanceId(hostname);
555 } catch (UnknownHostException e) {
556 log.warn("Can't get hostname, using the default");
557 }
558 }
559
560 log.debug("ControllerId set to {}", this.instanceId);
561 }
562
563
564 /**
565 * Initialize internal data structures.
566 */
567 public void init(Map<String, String> configParams) {
568 // These data structures are initialized here because other
569 // module's startUp() might be called before ours
570 this.activeMasterSwitches = new ConcurrentHashMap<Long, IOFSwitch>();
571 this.activeEqualSwitches = new ConcurrentHashMap<Long, IOFSwitch>();
572 this.connectedSwitches = new ConcurrentHashMap<Long, OFChannelHandler>();
573 this.controllerNodeIPsCache = new HashMap<String, String>();
574
575 setConfigParams(configParams);
576 this.systemStartTime = System.currentTimeMillis();
577 this.setDebugCounter(new DebugCounter());
578 this.counters = new Counters();
579 this.multiCacheLock = new Object();
580
alshabib1f44e8e2014-08-14 15:19:57 -0700581 }
582
583 /**
584 * Startup all of the controller's components.
585 */
586 @LogMessageDoc(message = "Waiting for storage source",
587 explanation = "The system database is not yet ready",
588 recommendation = "If this message persists, this indicates " +
589 "that the system database has failed to start. " +
590 LogMessageDoc.CHECK_CONTROLLER)
591 public synchronized void startupComponents() {
592 try {
593 if (registryService != null) {
594 registryService.registerController(instanceId.toString());
595 }
596 } catch (RegistryException e) {
597 log.warn("Registry service error: {}", e.getMessage());
598 }
599
600 // register counters and events
601 try {
602 this.counters.createCounters(debugCounters);
603 } catch (CounterException e) {
604 log.warn("Counters unavailable: {}", e.getMessage());
605 }
606 }
607
608 // **************
609 // debugCounter registrations
610 // **************
611
612 public static class Counters {
613 public static final String PREFIX = "controller";
614 public IDebugCounter switchActivated;
615 public IDebugCounter switchWithSameDpidActivated; // warn
616 public IDebugCounter switchDisconnected;
617 public IDebugCounter messageReceived;
618 public IDebugCounter switchDisconnectReadTimeout;
619 public IDebugCounter switchDisconnectHandshakeTimeout;
620 public IDebugCounter switchDisconnectIOError;
621 public IDebugCounter switchDisconnectParseError;
622 public IDebugCounter switchDisconnectSwitchStateException;
623 public IDebugCounter rejectedExecutionException;
624 public IDebugCounter switchDisconnectOtherException;
625 public IDebugCounter switchConnected;
626 public IDebugCounter unhandledMessage;
627 public IDebugCounter packetInWhileSwitchIsSlave;
628 public IDebugCounter epermErrorWhileSwitchIsMaster;
629 public IDebugCounter roleReplyTimeout;
630 public IDebugCounter roleReplyReceived; // expected RoleReply received
631 public IDebugCounter roleReplyErrorUnsupported;
632 public IDebugCounter switchCounterRegistrationFailed;
633
634 void createCounters(IDebugCounterService debugCounters) throws CounterException {
635
636 switchActivated =
637 debugCounters.registerCounter(
638 PREFIX, "switch-activated",
639 "A switch connected to this controller is now " +
640 "in MASTER role",
641 CounterType.ALWAYS_COUNT);
642
643 switchWithSameDpidActivated = // warn
644 debugCounters.registerCounter(
645 PREFIX, "switch-with-same-dpid-activated",
646 "A switch with the same DPID as another switch " +
647 "connected to the controller. This can be " +
648 "caused by multiple switches configured with " +
649 "the same DPID or by a switch reconnecting very " +
650 "quickly.",
651 CounterType.COUNT_ON_DEMAND,
652 IDebugCounterService.CTR_MDATA_WARN);
653
654 switchDisconnected =
655 debugCounters.registerCounter(
656 PREFIX, "switch-disconnected",
657 "FIXME: switch has disconnected",
658 CounterType.ALWAYS_COUNT);
659
660 //------------------------
661 // channel handler counters. Factor them out ??
662 messageReceived =
663 debugCounters.registerCounter(
664 PREFIX, "message-received",
665 "Number of OpenFlow messages received. Some of " +
666 "these might be throttled",
667 CounterType.ALWAYS_COUNT);
668
669 switchDisconnectReadTimeout =
670 debugCounters.registerCounter(
671 PREFIX, "switch-disconnect-read-timeout",
672 "Number of times a switch was disconnected due " +
673 "due the switch failing to send OpenFlow " +
674 "messages or responding to OpenFlow ECHOs",
675 CounterType.ALWAYS_COUNT,
676 IDebugCounterService.CTR_MDATA_ERROR);
677 switchDisconnectHandshakeTimeout =
678 debugCounters.registerCounter(
679 PREFIX, "switch-disconnect-handshake-timeout",
680 "Number of times a switch was disconnected " +
681 "because it failed to complete the handshake " +
682 "in time.",
683 CounterType.ALWAYS_COUNT,
684 IDebugCounterService.CTR_MDATA_ERROR);
685 switchDisconnectIOError =
686 debugCounters.registerCounter(
687 PREFIX, "switch-disconnect-io-error",
688 "Number of times a switch was disconnected " +
689 "due to IO errors on the switch connection.",
690 CounterType.ALWAYS_COUNT,
691 IDebugCounterService.CTR_MDATA_ERROR);
692 switchDisconnectParseError =
693 debugCounters.registerCounter(
694 PREFIX, "switch-disconnect-parse-error",
695 "Number of times a switch was disconnected " +
696 "because it sent an invalid packet that could " +
697 "not be parsed",
698 CounterType.ALWAYS_COUNT,
699 IDebugCounterService.CTR_MDATA_ERROR);
700
701 switchDisconnectSwitchStateException =
702 debugCounters.registerCounter(
703 PREFIX, "switch-disconnect-switch-state-exception",
704 "Number of times a switch was disconnected " +
705 "because it sent messages that were invalid " +
706 "given the switch connection's state.",
707 CounterType.ALWAYS_COUNT,
708 IDebugCounterService.CTR_MDATA_ERROR);
709 rejectedExecutionException =
710 debugCounters.registerCounter(
711 PREFIX, "rejected-execution-exception",
712 "TODO",
713 CounterType.ALWAYS_COUNT,
714 IDebugCounterService.CTR_MDATA_ERROR);
715
716 switchDisconnectOtherException =
717 debugCounters.registerCounter(
718 PREFIX, "switch-disconnect-other-exception",
719 "Number of times a switch was disconnected " +
720 "due to an exceptional situation not covered " +
721 "by other counters",
722 CounterType.ALWAYS_COUNT,
723 IDebugCounterService.CTR_MDATA_ERROR);
724
725 switchConnected =
726 debugCounters.registerCounter(
727 PREFIX, "switch-connected",
728 "Number of times a new switch connection was " +
729 "established",
730 CounterType.ALWAYS_COUNT);
731
732 unhandledMessage =
733 debugCounters.registerCounter(
734 PREFIX, "unhandled-message",
735 "Number of times an OpenFlow message was " +
736 "received that the controller ignored because " +
737 "it was inapproriate given the switch " +
738 "connection's state.",
739 CounterType.ALWAYS_COUNT,
740 IDebugCounterService.CTR_MDATA_WARN);
741 // might be less than warning
742
743 packetInWhileSwitchIsSlave =
744 debugCounters.registerCounter(
745 PREFIX, "packet-in-while-switch-is-slave",
746 "Number of times a packet in was received " +
747 "from a switch that was in SLAVE role. " +
748 "Possibly inidicates inconsistent roles.",
749 CounterType.ALWAYS_COUNT);
750 epermErrorWhileSwitchIsMaster =
751 debugCounters.registerCounter(
752 PREFIX, "eperm-error-while-switch-is-master",
753 "Number of times a permission error was " +
754 "received while the switch was in MASTER role. " +
755 "Possibly inidicates inconsistent roles.",
756 CounterType.ALWAYS_COUNT,
757 IDebugCounterService.CTR_MDATA_WARN);
758
759 roleReplyTimeout =
760 debugCounters.registerCounter(
761 PREFIX, "role-reply-timeout",
762 "Number of times a role request message did not " +
763 "receive the expected reply from a switch",
764 CounterType.ALWAYS_COUNT,
765 IDebugCounterService.CTR_MDATA_WARN);
766
767 roleReplyReceived = // expected RoleReply received
768 debugCounters.registerCounter(
769 PREFIX, "role-reply-received",
770 "Number of times the controller received the " +
771 "expected role reply message from a switch",
772 CounterType.ALWAYS_COUNT);
773
774 roleReplyErrorUnsupported =
775 debugCounters.registerCounter(
776 PREFIX, "role-reply-error-unsupported",
777 "Number of times the controller received an " +
778 "error from a switch in response to a role " +
779 "request indicating that the switch does not " +
780 "support roles.",
781 CounterType.ALWAYS_COUNT);
782
783 switchCounterRegistrationFailed =
784 debugCounters.registerCounter(PREFIX,
785 "switch-counter-registration-failed",
786 "Number of times the controller failed to " +
787 "register per-switch debug counters",
788 CounterType.ALWAYS_COUNT,
789 IDebugCounterService.CTR_MDATA_WARN);
790
791
792 }
793 }
794
795 public Counters getCounters() {
796 return this.counters;
797 }
798
799
800 // **************
801 // Utility methods
802 // **************
803
alshabib1f44e8e2014-08-14 15:19:57 -0700804 public Map<String, Long> getMemory() {
805 Map<String, Long> m = new HashMap<String, Long>();
806 Runtime runtime = Runtime.getRuntime();
807 m.put("total", runtime.totalMemory());
808 m.put("free", runtime.freeMemory());
809 return m;
810 }
811
812
813 public Long getUptime() {
814 RuntimeMXBean rb = ManagementFactory.getRuntimeMXBean();
815 return rb.getUptime();
816 }
817
818 /**
819 * Forward to the driver-manager to get an IOFSwitch instance.
820 * @param desc
tom9ccd7812014-08-25 22:43:19 -0700821 * @return switch instance
alshabib1f44e8e2014-08-14 15:19:57 -0700822 */
823 protected IOFSwitch getOFSwitchInstance(OFDescStatsReply desc, OFVersion ofv) {
824 if (switchManager == null) {
825 return new DummySwitchForTesting();
826 }
827 return switchManager.getSwitchImpl(desc.getMfrDesc(), desc.getHwDesc(),
828 desc.getSwDesc(), ofv);
829 }
830
831 @Activate
832 public void activate() {
833 log.info("Initialising OpenFlow Lib and IO");
834 this.init(new HashMap<String, String>());
835 this.startupComponents();
836 this.run();
837 }
838
839}