Logging and Code clean-up for protocol_plugins.core
[controller.git] / opendaylight / protocol_plugins / openflow / src / main / java / org / opendaylight / controller / protocol_plugin / openflow / core / internal / Controller.java
1 /*
2  * Copyright (c) 2013 Cisco Systems, Inc. and others.  All rights reserved.
3  *
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
7  */
8
9 package org.opendaylight.controller.protocol_plugin.openflow.core.internal;
10
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;
18 import java.util.Map;
19 import java.util.Map.Entry;
20 import java.util.Set;
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;
26
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;
40
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
54     /*
55      * this thread monitors the switchEvents queue for new incoming events from
56      * switch
57      */
58     private class EventHandler implements Runnable {
59         @Override
60         public void run() {
61
62             while (true) {
63                 try {
64                     SwitchEvent ev = switchEvents.take();
65                     SwitchEvent.SwitchEventType eType = ev.getEventType();
66                     ISwitch sw = ev.getSwitch();
67                     switch (eType) {
68                     case SWITCH_ADD:
69                         Long sid = sw.getId();
70                         ISwitch existingSwitch = switches.get(sid);
71                         if (existingSwitch != null) {
72                             logger.info("Replacing existing {} with New {}",
73                                     existingSwitch.toString(), sw.toString());
74                             disconnectSwitch(existingSwitch);
75                         }
76                         switches.put(sid, sw);
77                         notifySwitchAdded(sw);
78                         break;
79                     case SWITCH_DELETE:
80                         disconnectSwitch(sw);
81                         break;
82                     case SWITCH_ERROR:
83                         disconnectSwitch(sw);
84                         break;
85                     case SWITCH_MESSAGE:
86                         OFMessage msg = ev.getMsg();
87                         if (msg != null) {
88                             IMessageListener listener = messageListeners
89                                     .get(msg.getType());
90                             if (listener != null) {
91                                 listener.receive(sw, msg);
92                             }
93                         }
94                         break;
95                     default:
96                         logger.error("Unknown switch event {}", eType.ordinal());
97                     }
98                 } catch (InterruptedException e) {
99                     switchEvents.clear();
100                     return;
101                 }
102             }
103         }
104
105     }
106
107     /**
108      * Function called by the dependency manager when all the required
109      * dependencies are satisfied
110      * 
111      */
112     public void init() {
113         logger.debug("Initializing!");
114         this.switches = new ConcurrentHashMap<Long, ISwitch>();
115         this.switchEvents = new LinkedBlockingQueue<SwitchEvent>();
116         this.messageListeners = new ConcurrentHashMap<OFType, IMessageListener>();
117         this.switchStateListener = null;
118         this.switchInstanceNumber = new AtomicInteger(0);
119         registerWithOSGIConsole();
120     }
121
122     /**
123      * Function called by dependency manager after "init ()" is called and after
124      * the services provided by the class are registered in the service registry
125      * 
126      */
127     public void start() {
128         logger.debug("Starting!");
129         /*
130          * start a thread to handle event coming from the switch
131          */
132         switchEventThread = new Thread(new EventHandler(), "SwitchEvent Thread");
133         switchEventThread.start();
134
135         // spawn a thread to start to listen on the open flow port
136         controllerIO = new ControllerIO(this);
137         try {
138             controllerIO.start();
139         } catch (IOException ex) {
140             logger.error("Caught exception while starting:", ex);
141         }
142     }
143
144     /**
145      * Function called by the dependency manager before the services exported by
146      * the component are unregistered, this will be followed by a "destroy ()"
147      * calls
148      * 
149      */
150     public void stop() {
151         for (Iterator<Entry<Long, ISwitch>> it = switches.entrySet().iterator(); it
152                 .hasNext();) {
153             Entry<Long, ISwitch> entry = it.next();
154             ((SwitchHandler) entry.getValue()).stop();
155             it.remove();
156         }
157         switchEventThread.interrupt();
158         try {
159             controllerIO.shutDown();
160         } catch (IOException ex) {
161             logger.error("Caught exception while stopping:", ex);
162         }
163     }
164
165     /**
166      * Function called by the dependency manager when at least one dependency
167      * become unsatisfied or when the component is shutting down because for
168      * example bundle is being stopped.
169      * 
170      */
171     public void destroy() {
172     }
173
174     @Override
175     public void addMessageListener(OFType type, IMessageListener listener) {
176         IMessageListener currentListener = this.messageListeners.get(type);
177         if (currentListener != null) {
178             logger.warn("{} is already listened by {}", type.toString(),
179                     currentListener.toString());
180         }
181         this.messageListeners.put(type, listener);
182         logger.debug("{} is now listened by {}", type.toString(),
183                 listener.toString());
184     }
185
186     @Override
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.toString(),
191                     listener.toString());
192             this.messageListeners.remove(type);
193         }
194     }
195
196     @Override
197     public void addSwitchStateListener(ISwitchStateListener listener) {
198         if (this.switchStateListener != null) {
199             logger.warn("Switch events are already listened by {}",
200                     this.switchStateListener.toString());
201         }
202         this.switchStateListener = listener;
203         logger.debug("Switch events are now listened by {}",
204                 listener.toString());
205     }
206
207     @Override
208     public void removeSwitchStateListener(ISwitchStateListener listener) {
209         if ((this.switchStateListener != null)
210                 && (this.switchStateListener == listener)) {
211             logger.debug("SwitchStateListener {} is Removed",
212                     listener.toString());
213             this.switchStateListener = null;
214         }
215     }
216
217     public void handleNewConnection(Selector selector,
218             SelectionKey serverSelectionKey) {
219         ServerSocketChannel ssc = (ServerSocketChannel) serverSelectionKey
220                 .channel();
221         SocketChannel sc = null;
222         try {
223             sc = ssc.accept();
224             // create new switch
225             int i = this.switchInstanceNumber.addAndGet(1);
226             String instanceName = "SwitchHandler-" + i;
227             SwitchHandler switchHandler = new SwitchHandler(this, sc,
228                     instanceName);
229             switchHandler.start();
230             if (sc.isConnected()) {
231                 logger.info("Switch:{} is connected to the Controller", sc
232                         .getRemoteAddress().toString().split("/")[1]);
233             }
234
235         } catch (IOException e) {
236             return;
237         }
238     }
239
240     private void disconnectSwitch(ISwitch sw) {
241         if (((SwitchHandler) sw).isOperational()) {
242             Long sid = sw.getId();
243             if (this.switches.remove(sid, sw)) {
244                 logger.warn("{} is Disconnected", sw.toString());
245                 notifySwitchDeleted(sw);
246             }
247         }
248         ((SwitchHandler) sw).stop();
249         sw = null;
250     }
251
252     private void notifySwitchAdded(ISwitch sw) {
253         if (switchStateListener != null) {
254             switchStateListener.switchAdded(sw);
255         }
256     }
257
258     private void notifySwitchDeleted(ISwitch sw) {
259         if (switchStateListener != null) {
260             switchStateListener.switchDeleted(sw);
261         }
262     }
263
264     private synchronized void addSwitchEvent(SwitchEvent event) {
265         try {
266             this.switchEvents.put(event);
267         } catch (InterruptedException e) {
268             logger.debug("SwitchEvent caught Interrupt Exception");
269         }
270     }
271
272     public void takeSwitchEventAdd(ISwitch sw) {
273         SwitchEvent ev = new SwitchEvent(
274                 SwitchEvent.SwitchEventType.SWITCH_ADD, sw, null);
275         addSwitchEvent(ev);
276     }
277
278     public void takeSwitchEventDelete(ISwitch sw) {
279         SwitchEvent ev = new SwitchEvent(
280                 SwitchEvent.SwitchEventType.SWITCH_DELETE, sw, null);
281         addSwitchEvent(ev);
282     }
283
284     public void takeSwitchEventError(ISwitch sw) {
285         SwitchEvent ev = new SwitchEvent(
286                 SwitchEvent.SwitchEventType.SWITCH_ERROR, sw, null);
287         addSwitchEvent(ev);
288     }
289
290     public void takeSwitchEventMsg(ISwitch sw, OFMessage msg) {
291         if (messageListeners.get(msg.getType()) != null) {
292             SwitchEvent ev = new SwitchEvent(
293                     SwitchEvent.SwitchEventType.SWITCH_MESSAGE, sw, msg);
294             addSwitchEvent(ev);
295         }
296     }
297
298     @Override
299     public Map<Long, ISwitch> getSwitches() {
300         return this.switches;
301     }
302
303     @Override
304     public ISwitch getSwitch(Long switchId) {
305         return this.switches.get(switchId);
306     }
307
308     public void _controllerShowSwitches(CommandInterpreter ci) {
309         Set<Long> sids = switches.keySet();
310         StringBuffer s = new StringBuffer();
311         int size = sids.size();
312         if (size == 0) {
313             ci.print("switches: empty");
314             return;
315         }
316         Iterator<Long> iter = sids.iterator();
317         s.append("Total: " + size + " switches\n");
318         while (iter.hasNext()) {
319             Long sid = iter.next();
320             Date date = switches.get(sid).getConnectedDate();
321             String switchInstanceName = ((SwitchHandler) switches.get(sid))
322                     .getInstanceName();
323             s.append(switchInstanceName + "/" + HexString.toHexString(sid)
324                     + " connected since " + date.toString() + "\n");
325         }
326         ci.print(s.toString());
327         return;
328     }
329
330     public void _controllerReset(CommandInterpreter ci) {
331         ci.print("...Disconnecting the communication to all switches...\n");
332         stop();
333         try {
334             Thread.sleep(1000);
335         } catch (InterruptedException ie) {
336         } finally {
337             ci.print("...start to accept connections from switches...\n");
338             start();
339         }
340     }
341
342     public void _controllerShowConnConfig(CommandInterpreter ci) {
343         String str = System.getProperty("secureChannelEnabled");
344         if ((str != null) && (str.trim().equalsIgnoreCase("true"))) {
345             ci.print("The Controller and Switch should communicate through TLS connetion.\n");
346
347             String keyStoreFile = System.getProperty("controllerKeyStore");
348             String trustStoreFile = System.getProperty("controllerTrustStore");
349             if ((keyStoreFile == null) || keyStoreFile.trim().isEmpty()) {
350                 ci.print("controllerKeyStore not specified in ./configuration/config.ini\n");
351             } else {
352                 ci.print("controllerKeyStore=" + keyStoreFile + "\n");
353             }
354             if ((trustStoreFile == null) || trustStoreFile.trim().isEmpty()) {
355                 ci.print("controllerTrustStore not specified in ./configuration/config.ini\n");
356             } else {
357                 ci.print("controllerTrustStore=" + trustStoreFile + "\n");
358             }
359         } else {
360             ci.print("The Controller and Switch should communicate through TCP connetion.\n");
361         }
362     }
363
364     private void registerWithOSGIConsole() {
365         BundleContext bundleContext = FrameworkUtil.getBundle(this.getClass())
366                 .getBundleContext();
367         bundleContext.registerService(CommandProvider.class.getName(), this,
368                 null);
369     }
370
371     @Override
372     public String getHelp() {
373         StringBuffer help = new StringBuffer();
374         help.append("---Open Flow Controller---\n");
375         help.append("\t controllerShowSwitches\n");
376         help.append("\t controllerReset\n");
377         help.append("\t controllerShowConnConfig\n");
378         return help.toString();
379     }
380 }