2 * Copyright (c) 2013 Cisco Systems, Inc. and others. All rights reserved.
4 * This program and the accompanying materials are made available under the
5 * terms of the Eclipse Public License v1.0 which accompanies this distribution,
6 * and is available at http://www.eclipse.org/legal/epl-v10.html
9 package org.opendaylight.controller.protocol_plugin.openflow.core.internal;
11 import java.io.IOException;
12 import java.nio.channels.SelectionKey;
13 import java.nio.channels.Selector;
14 import java.nio.channels.ServerSocketChannel;
15 import java.nio.channels.SocketChannel;
16 import java.util.Date;
17 import java.util.Iterator;
19 import java.util.Map.Entry;
21 import java.util.concurrent.BlockingQueue;
22 import java.util.concurrent.ConcurrentHashMap;
23 import java.util.concurrent.ConcurrentMap;
24 import java.util.concurrent.LinkedBlockingQueue;
25 import java.util.concurrent.atomic.AtomicInteger;
27 import org.eclipse.osgi.framework.console.CommandInterpreter;
28 import org.eclipse.osgi.framework.console.CommandProvider;
29 import org.opendaylight.controller.protocol_plugin.openflow.core.IController;
30 import org.opendaylight.controller.protocol_plugin.openflow.core.IMessageListener;
31 import org.opendaylight.controller.protocol_plugin.openflow.core.ISwitch;
32 import org.opendaylight.controller.protocol_plugin.openflow.core.ISwitchStateListener;
33 import org.openflow.protocol.OFMessage;
34 import org.openflow.protocol.OFType;
35 import org.openflow.util.HexString;
36 import org.osgi.framework.BundleContext;
37 import org.osgi.framework.FrameworkUtil;
38 import org.slf4j.Logger;
39 import org.slf4j.LoggerFactory;
41 public class Controller implements IController, CommandProvider {
42 private static final Logger logger = LoggerFactory
43 .getLogger(Controller.class);
44 private ControllerIO controllerIO;
45 private Thread switchEventThread;
46 private ConcurrentHashMap<Long, ISwitch> switches;
47 private BlockingQueue<SwitchEvent> switchEvents;
48 // only 1 message listener per OFType
49 private ConcurrentMap<OFType, IMessageListener> messageListeners;
50 // only 1 switch state listener
51 private ISwitchStateListener switchStateListener;
52 private AtomicInteger switchInstanceNumber;
53 private int MAXQUEUESIZE = 50000;
56 * this thread monitors the switchEvents queue for new incoming events from
59 private class EventHandler implements Runnable {
65 SwitchEvent ev = switchEvents.take();
66 SwitchEvent.SwitchEventType eType = ev.getEventType();
67 ISwitch sw = ev.getSwitch();
70 Long sid = sw.getId();
71 ISwitch existingSwitch = switches.get(sid);
72 if (existingSwitch != null) {
73 logger.info("Replacing existing {} with New {}",
75 disconnectSwitch(existingSwitch);
77 switches.put(sid, sw);
78 notifySwitchAdded(sw);
87 OFMessage msg = ev.getMsg();
89 IMessageListener listener = messageListeners
91 if (listener != null) {
92 listener.receive(sw, msg);
97 logger.error("Unknown switch event {}", eType.ordinal());
99 } catch (InterruptedException e) {
100 switchEvents.clear();
109 * Function called by the dependency manager when all the required
110 * dependencies are satisfied
114 logger.debug("Initializing!");
115 this.switches = new ConcurrentHashMap<Long, ISwitch>();
116 this.switchEvents = new LinkedBlockingQueue<SwitchEvent>(MAXQUEUESIZE);
117 this.messageListeners = new ConcurrentHashMap<OFType, IMessageListener>();
118 this.switchStateListener = null;
119 this.switchInstanceNumber = new AtomicInteger(0);
120 registerWithOSGIConsole();
124 * Function called by dependency manager after "init ()" is called and after
125 * the services provided by the class are registered in the service registry
128 public void start() {
129 logger.debug("Starting!");
131 * start a thread to handle event coming from the switch
133 switchEventThread = new Thread(new EventHandler(), "SwitchEvent Thread");
134 switchEventThread.start();
136 // spawn a thread to start to listen on the open flow port
137 controllerIO = new ControllerIO(this);
139 controllerIO.start();
140 } catch (IOException ex) {
141 logger.error("Caught exception while starting:", ex);
146 * Function called by the dependency manager before the services exported by
147 * the component are unregistered, this will be followed by a "destroy ()"
152 for (Iterator<Entry<Long, ISwitch>> it = switches.entrySet().iterator(); it
154 Entry<Long, ISwitch> entry = it.next();
155 ((SwitchHandler) entry.getValue()).stop();
158 switchEventThread.interrupt();
160 controllerIO.shutDown();
161 } catch (IOException ex) {
162 logger.error("Caught exception while stopping:", ex);
167 * Function called by the dependency manager when at least one dependency
168 * become unsatisfied or when the component is shutting down because for
169 * example bundle is being stopped.
172 public void destroy() {
176 public void addMessageListener(OFType type, IMessageListener listener) {
177 IMessageListener currentListener = this.messageListeners.get(type);
178 if (currentListener != null) {
179 logger.warn("{} is already listened by {}", type,
182 this.messageListeners.put(type, listener);
183 logger.debug("{} is now listened by {}", type, listener);
187 public void removeMessageListener(OFType type, IMessageListener listener) {
188 IMessageListener currentListener = this.messageListeners.get(type);
189 if ((currentListener != null) && (currentListener == listener)) {
190 logger.debug("{} listener {} is Removed", type, listener);
191 this.messageListeners.remove(type);
196 public void addSwitchStateListener(ISwitchStateListener listener) {
197 if (this.switchStateListener != null) {
198 logger.warn("Switch events are already listened by {}",
199 this.switchStateListener);
201 this.switchStateListener = listener;
202 logger.debug("Switch events are now listened by {}", listener);
206 public void removeSwitchStateListener(ISwitchStateListener listener) {
207 if ((this.switchStateListener != null)
208 && (this.switchStateListener == listener)) {
209 logger.debug("SwitchStateListener {} is Removed", listener);
210 this.switchStateListener = null;
214 public void handleNewConnection(Selector selector,
215 SelectionKey serverSelectionKey) {
216 ServerSocketChannel ssc = (ServerSocketChannel) serverSelectionKey
218 SocketChannel sc = null;
222 int i = this.switchInstanceNumber.addAndGet(1);
223 String instanceName = "SwitchHandler-" + i;
224 SwitchHandler switchHandler = new SwitchHandler(this, sc,
226 switchHandler.start();
227 if (sc.isConnected()) {
228 logger.info("Switch:{} is connected to the Controller",
229 sc.socket().getRemoteSocketAddress()
230 .toString().split("/")[1]);
233 } catch (IOException e) {
238 private void disconnectSwitch(ISwitch sw) {
239 if (((SwitchHandler) sw).isOperational()) {
240 Long sid = sw.getId();
241 if (this.switches.remove(sid, sw)) {
242 logger.warn("{} is Disconnected", sw);
243 notifySwitchDeleted(sw);
246 ((SwitchHandler) sw).stop();
250 private void notifySwitchAdded(ISwitch sw) {
251 if (switchStateListener != null) {
252 switchStateListener.switchAdded(sw);
256 private void notifySwitchDeleted(ISwitch sw) {
257 if (switchStateListener != null) {
258 switchStateListener.switchDeleted(sw);
262 private synchronized void addSwitchEvent(SwitchEvent event) {
264 this.switchEvents.put(event);
265 } catch (InterruptedException e) {
266 logger.debug("SwitchEvent caught Interrupt Exception");
270 public void takeSwitchEventAdd(ISwitch sw) {
271 SwitchEvent ev = new SwitchEvent(
272 SwitchEvent.SwitchEventType.SWITCH_ADD, sw, null);
276 public void takeSwitchEventDelete(ISwitch sw) {
277 SwitchEvent ev = new SwitchEvent(
278 SwitchEvent.SwitchEventType.SWITCH_DELETE, sw, null);
282 public void takeSwitchEventError(ISwitch sw) {
283 SwitchEvent ev = new SwitchEvent(
284 SwitchEvent.SwitchEventType.SWITCH_ERROR, sw, null);
288 public void takeSwitchEventMsg(ISwitch sw, OFMessage msg) {
289 if (messageListeners.get(msg.getType()) != null) {
290 SwitchEvent ev = new SwitchEvent(
291 SwitchEvent.SwitchEventType.SWITCH_MESSAGE, sw, msg);
297 public Map<Long, ISwitch> getSwitches() {
298 return this.switches;
302 public ISwitch getSwitch(Long switchId) {
303 return this.switches.get(switchId);
306 public void _controllerShowSwitches(CommandInterpreter ci) {
307 Set<Long> sids = switches.keySet();
308 StringBuffer s = new StringBuffer();
309 int size = sids.size();
311 ci.print("switches: empty");
314 Iterator<Long> iter = sids.iterator();
315 s.append("Total: " + size + " switches\n");
316 while (iter.hasNext()) {
317 Long sid = iter.next();
318 Date date = switches.get(sid).getConnectedDate();
319 String switchInstanceName = ((SwitchHandler) switches.get(sid))
321 s.append(switchInstanceName + "/" + HexString.toHexString(sid)
322 + " connected since " + date.toString() + "\n");
324 ci.print(s.toString());
328 public void _controllerReset(CommandInterpreter ci) {
329 ci.print("...Disconnecting the communication to all switches...\n");
333 } catch (InterruptedException ie) {
335 ci.print("...start to accept connections from switches...\n");
340 public void _controllerShowConnConfig(CommandInterpreter ci) {
341 String str = System.getProperty("secureChannelEnabled");
342 if ((str != null) && (str.trim().equalsIgnoreCase("true"))) {
343 ci.print("The Controller and Switch should communicate through TLS connetion.\n");
345 String keyStoreFile = System.getProperty("controllerKeyStore");
346 String trustStoreFile = System.getProperty("controllerTrustStore");
347 if ((keyStoreFile == null) || keyStoreFile.trim().isEmpty()) {
348 ci.print("controllerKeyStore not specified in ./configuration/config.ini\n");
350 ci.print("controllerKeyStore=" + keyStoreFile + "\n");
352 if ((trustStoreFile == null) || trustStoreFile.trim().isEmpty()) {
353 ci.print("controllerTrustStore not specified in ./configuration/config.ini\n");
355 ci.print("controllerTrustStore=" + trustStoreFile + "\n");
358 ci.print("The Controller and Switch should communicate through TCP connetion.\n");
362 private void registerWithOSGIConsole() {
363 BundleContext bundleContext = FrameworkUtil.getBundle(this.getClass())
365 bundleContext.registerService(CommandProvider.class.getName(), this,
370 public String getHelp() {
371 StringBuffer help = new StringBuffer();
372 help.append("---Open Flow Controller---\n");
373 help.append("\t controllerShowSwitches\n");
374 help.append("\t controllerReset\n");
375 help.append("\t controllerShowConnConfig\n");
376 return help.toString();