blob: a323726620b525f80659f4736ea643d77ac8a46b [file] [log] [blame]
Jonathan Hart062a2e82014-02-03 09:41:57 -08001package net.onrc.onos.ofcontroller.networkgraph;
2
Yuta HIGUCHI1c700102014-02-12 16:30:52 -08003import java.net.InetAddress;
Pavlin Radoslavov018d5332014-02-19 23:08:35 -08004import java.nio.ByteBuffer;
Yuta HIGUCHI8d762e92014-02-12 14:10:25 -08005import java.util.ArrayList;
Pavlin Radoslavov721a2e02014-02-14 23:40:14 -08006import java.util.Collection;
Pavlin Radoslavov018d5332014-02-19 23:08:35 -08007import java.util.HashMap;
Yuta HIGUCHI8d762e92014-02-12 14:10:25 -08008import java.util.HashSet;
Pavlin Radoslavov721a2e02014-02-14 23:40:14 -08009import java.util.LinkedList;
Yuta HIGUCHI8d762e92014-02-12 14:10:25 -080010import java.util.List;
Pavlin Radoslavov018d5332014-02-19 23:08:35 -080011import java.util.Map;
Yuta HIGUCHI8d762e92014-02-12 14:10:25 -080012import java.util.Set;
Pavlin Radoslavov721a2e02014-02-14 23:40:14 -080013import java.util.concurrent.BlockingQueue;
Yuta HIGUCHIa536e762014-02-17 21:47:28 -080014import java.util.concurrent.CopyOnWriteArrayList;
Pavlin Radoslavov721a2e02014-02-14 23:40:14 -080015import java.util.concurrent.LinkedBlockingQueue;
Yuta HIGUCHI8d762e92014-02-12 14:10:25 -080016
Pavlin Radoslavov721a2e02014-02-14 23:40:14 -080017import net.onrc.onos.datagrid.IDatagridService;
18import net.onrc.onos.datagrid.IEventChannel;
19import net.onrc.onos.datagrid.IEventChannelListener;
Yuta HIGUCHI66ca1bf2014-03-12 18:34:09 -070020import net.onrc.onos.datastore.topology.KVLink;
21import net.onrc.onos.datastore.topology.KVPort;
22import net.onrc.onos.datastore.topology.KVSwitch;
Yuta HIGUCHI8d762e92014-02-12 14:10:25 -080023import net.onrc.onos.ofcontroller.networkgraph.PortEvent.SwitchPort;
Pavlin Radoslavov721a2e02014-02-14 23:40:14 -080024import net.onrc.onos.ofcontroller.util.EventEntry;
Yuta HIGUCHI170229f2014-02-17 15:47:54 -080025import net.onrc.onos.registry.controller.IControllerRegistryService;
Jonathan Hart062a2e82014-02-03 09:41:57 -080026
27import org.slf4j.Logger;
28import org.slf4j.LoggerFactory;
29
Yuta HIGUCHI181d34d2014-02-05 15:05:46 -080030/**
31 * The "NB" read-only Network Map.
32 *
Yuta HIGUCHI4bfdd532014-02-07 13:47:36 -080033 * - Maintain Invariant/Relationships between Topology Objects.
34 *
Yuta HIGUCHI765cd0d2014-02-06 12:46:41 -080035 * TODO To be synchronized based on TopologyEvent Notification.
Yuta HIGUCHI181d34d2014-02-05 15:05:46 -080036 *
Yuta HIGUCHIcb951982014-02-11 13:31:44 -080037 * TODO TBD: Caller is expected to maintain parent/child calling order. Parent
Yuta HIGUCHI1c700102014-02-12 16:30:52 -080038 * Object must exist before adding sub component(Add Switch -> Port).
Yuta HIGUCHIcb951982014-02-11 13:31:44 -080039 *
Yuta HIGUCHI4bfdd532014-02-07 13:47:36 -080040 * TODO TBD: This class may delay the requested change to handle event
41 * re-ordering. e.g.) Link Add came in, but Switch was not there.
Yuta HIGUCHIcb951982014-02-11 13:31:44 -080042 *
Yuta HIGUCHI181d34d2014-02-05 15:05:46 -080043 */
Pavlin Radoslavov87dcc262014-02-19 21:13:23 -080044public class TopologyManager implements NetworkGraphDiscoveryInterface {
Jonathan Hart062a2e82014-02-03 09:41:57 -080045
Yuta HIGUCHI80829d12014-02-05 20:16:56 -080046 private static final Logger log = LoggerFactory
Pavlin Radoslavovdb7dbb22014-02-18 14:45:10 -080047 .getLogger(TopologyManager.class);
Yuta HIGUCHIcd922f42014-02-11 18:59:11 -080048
Pavlin Radoslavov721a2e02014-02-14 23:40:14 -080049 private IEventChannel<byte[], TopologyEvent> eventChannel;
Jonathan Hart10a7e2b2014-02-21 18:30:08 -080050 public static final String EVENT_CHANNEL_NAME = "onos.topology";
Pavlin Radoslavov721a2e02014-02-14 23:40:14 -080051 private EventHandler eventHandler = new EventHandler();
52
Jonathan Hart22eb9882014-02-11 15:52:59 -080053 private final NetworkGraphDatastore datastore;
Pavlin Radoslavov6d224ee2014-02-18 16:43:15 -080054 private final NetworkGraphImpl networkGraph = new NetworkGraphImpl();
Yuta HIGUCHI170229f2014-02-17 15:47:54 -080055 private final IControllerRegistryService registryService;
Yuta HIGUCHIa536e762014-02-17 21:47:28 -080056 private CopyOnWriteArrayList<INetworkGraphListener> networkGraphListeners;
Yuta HIGUCHI181d34d2014-02-05 15:05:46 -080057
Pavlin Radoslavov706add22014-02-20 12:15:59 -080058 //
59 // Local state for keeping track of reordered events.
60 // NOTE: Switch Events are not affected by the event reordering.
61 //
62 private Map<ByteBuffer, PortEvent> reorderedAddedPortEvents =
Pavlin Radoslavov018d5332014-02-19 23:08:35 -080063 new HashMap<ByteBuffer, PortEvent>();
Pavlin Radoslavov706add22014-02-20 12:15:59 -080064 private Map<ByteBuffer, LinkEvent> reorderedAddedLinkEvents =
Pavlin Radoslavov018d5332014-02-19 23:08:35 -080065 new HashMap<ByteBuffer, LinkEvent>();
Pavlin Radoslavov706add22014-02-20 12:15:59 -080066 private Map<ByteBuffer, DeviceEvent> reorderedAddedDeviceEvents =
Pavlin Radoslavov018d5332014-02-19 23:08:35 -080067 new HashMap<ByteBuffer, DeviceEvent>();
68
Pavlin Radoslavov74986ce2014-02-20 13:17:20 -080069 //
Pavlin Radoslavov26d83402014-02-20 15:24:30 -080070 // Local state for keeping track of locally discovered events so we can
71 // cleanup properly when a Switch or Port is removed.
72 //
73 // We keep all Port, Link and Device events per Switch DPID:
74 // - If a switch goes down, we remove all corresponding Port, Link and
75 // Device events.
76 // - If a port on a switch goes down, we remove all corresponding Link
77 // and Device events.
78 //
79 private Map<Long, Map<ByteBuffer, PortEvent>> discoveredAddedPortEvents =
80 new HashMap<>();
81 private Map<Long, Map<ByteBuffer, LinkEvent>> discoveredAddedLinkEvents =
82 new HashMap<>();
83 private Map<Long, Map<ByteBuffer, DeviceEvent>> discoveredAddedDeviceEvents =
84 new HashMap<>();
85
86 //
Pavlin Radoslavov74986ce2014-02-20 13:17:20 -080087 // Local state for keeping track of the application event notifications
88 //
89 List<SwitchEvent> apiAddedSwitchEvents = new LinkedList<SwitchEvent>();
90 List<SwitchEvent> apiRemovedSwitchEvents = new LinkedList<SwitchEvent>();
91 List<PortEvent> apiAddedPortEvents = new LinkedList<PortEvent>();
92 List<PortEvent> apiRemovedPortEvents = new LinkedList<PortEvent>();
93 List<LinkEvent> apiAddedLinkEvents = new LinkedList<LinkEvent>();
94 List<LinkEvent> apiRemovedLinkEvents = new LinkedList<LinkEvent>();
95 List<DeviceEvent> apiAddedDeviceEvents = new LinkedList<DeviceEvent>();
96 List<DeviceEvent> apiRemovedDeviceEvents = new LinkedList<DeviceEvent>();
97
Pavlin Radoslavovc1cfde52014-02-19 11:35:29 -080098 /**
99 * Constructor.
100 *
101 * @param registryService the Registry Service to use.
102 * @param networkGraphListeners the collection of Network Graph Listeners
103 * to use.
104 */
105 public TopologyManager(IControllerRegistryService registryService,
106 CopyOnWriteArrayList<INetworkGraphListener> networkGraphListeners) {
Jonathan Hartdaea86f2014-02-19 15:28:42 -0800107 datastore = new NetworkGraphDatastore();
Yuta HIGUCHI170229f2014-02-17 15:47:54 -0800108 this.registryService = registryService;
Yuta HIGUCHIa536e762014-02-17 21:47:28 -0800109 this.networkGraphListeners = networkGraphListeners;
Yuta HIGUCHI80829d12014-02-05 20:16:56 -0800110 }
Yuta HIGUCHI181d34d2014-02-05 15:05:46 -0800111
Pavlin Radoslavovc1cfde52014-02-19 11:35:29 -0800112 /**
113 * Get the Network Graph.
114 *
115 * @return the Network Graph.
116 */
Pavlin Radoslavov6d224ee2014-02-18 16:43:15 -0800117 NetworkGraph getNetworkGraph() {
118 return networkGraph;
119 }
120
Yuta HIGUCHI4bfdd532014-02-07 13:47:36 -0800121 /**
Pavlin Radoslavov721a2e02014-02-14 23:40:14 -0800122 * Event handler class.
123 */
124 private class EventHandler extends Thread implements
125 IEventChannelListener<byte[], TopologyEvent> {
126 private BlockingQueue<EventEntry<TopologyEvent>> topologyEvents =
127 new LinkedBlockingQueue<EventEntry<TopologyEvent>>();
128
129 /**
130 * Startup processing.
131 */
132 private void startup() {
133 //
Pavlin Radoslavov018d5332014-02-19 23:08:35 -0800134 // TODO: Read all state from the database:
135 //
136 // Collection<EventEntry<TopologyEvent>> collection =
137 // readWholeTopologyFromDB();
138 //
Pavlin Radoslavov721a2e02014-02-14 23:40:14 -0800139 // For now, as a shortcut we read it from the datagrid
140 //
141 Collection<TopologyEvent> topologyEvents =
142 eventChannel.getAllEntries();
143 Collection<EventEntry<TopologyEvent>> collection =
144 new LinkedList<EventEntry<TopologyEvent>>();
145
146 for (TopologyEvent topologyEvent : topologyEvents) {
147 EventEntry<TopologyEvent> eventEntry =
148 new EventEntry<TopologyEvent>(EventEntry.Type.ENTRY_ADD,
149 topologyEvent);
150 collection.add(eventEntry);
151 }
152 processEvents(collection);
153 }
154
155 /**
156 * Run the thread.
157 */
Yuta HIGUCHI240bf072014-02-17 10:55:21 -0800158 @Override
Pavlin Radoslavov721a2e02014-02-14 23:40:14 -0800159 public void run() {
160 Collection<EventEntry<TopologyEvent>> collection =
161 new LinkedList<EventEntry<TopologyEvent>>();
162
Pavlin Radoslavovdb7dbb22014-02-18 14:45:10 -0800163 this.setName("TopologyManager.EventHandler " + this.getId());
Pavlin Radoslavov721a2e02014-02-14 23:40:14 -0800164 startup();
165
166 //
167 // The main loop
168 //
169 try {
170 while (true) {
171 EventEntry<TopologyEvent> eventEntry = topologyEvents.take();
172 collection.add(eventEntry);
173 topologyEvents.drainTo(collection);
174
175 processEvents(collection);
176 collection.clear();
177 }
178 } catch (Exception exception) {
179 log.debug("Exception processing Topology Events: ", exception);
180 }
181 }
182
183 /**
184 * Process all topology events.
185 *
186 * @param events the events to process.
187 */
188 private void processEvents(Collection<EventEntry<TopologyEvent>> events) {
Pavlin Radoslavov706add22014-02-20 12:15:59 -0800189 // Local state for computing the final set of events
Pavlin Radoslavov26d83402014-02-20 15:24:30 -0800190 Map<ByteBuffer, SwitchEvent> addedSwitchEvents = new HashMap<>();
191 Map<ByteBuffer, SwitchEvent> removedSwitchEvents = new HashMap<>();
192 Map<ByteBuffer, PortEvent> addedPortEvents = new HashMap<>();
193 Map<ByteBuffer, PortEvent> removedPortEvents = new HashMap<>();
194 Map<ByteBuffer, LinkEvent> addedLinkEvents = new HashMap<>();
195 Map<ByteBuffer, LinkEvent> removedLinkEvents = new HashMap<>();
196 Map<ByteBuffer, DeviceEvent> addedDeviceEvents = new HashMap<>();
197 Map<ByteBuffer, DeviceEvent> removedDeviceEvents = new HashMap<>();
Pavlin Radoslavov3c9cc552014-02-20 09:58:38 -0800198
199 //
200 // Classify and suppress matching events
201 //
Pavlin Radoslavov721a2e02014-02-14 23:40:14 -0800202 for (EventEntry<TopologyEvent> event : events) {
203 TopologyEvent topologyEvent = event.eventData();
Pavlin Radoslavov018d5332014-02-19 23:08:35 -0800204 SwitchEvent switchEvent = topologyEvent.switchEvent;
205 PortEvent portEvent = topologyEvent.portEvent;
206 LinkEvent linkEvent = topologyEvent.linkEvent;
207 DeviceEvent deviceEvent = topologyEvent.deviceEvent;
208
209 //
Pavlin Radoslavov3c9cc552014-02-20 09:58:38 -0800210 // Extract the events
Pavlin Radoslavov018d5332014-02-19 23:08:35 -0800211 //
Pavlin Radoslavov721a2e02014-02-14 23:40:14 -0800212 switch (event.eventType()) {
213 case ENTRY_ADD:
214 log.debug("Topology event ENTRY_ADD: {}", topologyEvent);
Pavlin Radoslavov018d5332014-02-19 23:08:35 -0800215 if (switchEvent != null) {
Yuta HIGUCHIa341b112014-02-23 15:42:00 -0800216 ByteBuffer id = switchEvent.getIDasByteBuffer();
Pavlin Radoslavov018d5332014-02-19 23:08:35 -0800217 addedSwitchEvents.put(id, switchEvent);
218 removedSwitchEvents.remove(id);
Pavlin Radoslavov706add22014-02-20 12:15:59 -0800219 // Switch Events are not affected by event reordering
Pavlin Radoslavov018d5332014-02-19 23:08:35 -0800220 }
221 if (portEvent != null) {
Yuta HIGUCHIa341b112014-02-23 15:42:00 -0800222 ByteBuffer id = portEvent.getIDasByteBuffer();
Pavlin Radoslavov018d5332014-02-19 23:08:35 -0800223 addedPortEvents.put(id, portEvent);
224 removedPortEvents.remove(id);
Pavlin Radoslavov706add22014-02-20 12:15:59 -0800225 reorderedAddedPortEvents.remove(id);
Pavlin Radoslavov018d5332014-02-19 23:08:35 -0800226 }
227 if (linkEvent != null) {
Yuta HIGUCHIa341b112014-02-23 15:42:00 -0800228 ByteBuffer id = linkEvent.getIDasByteBuffer();
Pavlin Radoslavov018d5332014-02-19 23:08:35 -0800229 addedLinkEvents.put(id, linkEvent);
230 removedLinkEvents.remove(id);
Pavlin Radoslavov706add22014-02-20 12:15:59 -0800231 reorderedAddedLinkEvents.remove(id);
Pavlin Radoslavov018d5332014-02-19 23:08:35 -0800232 }
233 if (deviceEvent != null) {
Yuta HIGUCHIa341b112014-02-23 15:42:00 -0800234 ByteBuffer id = deviceEvent.getIDasByteBuffer();
Pavlin Radoslavov018d5332014-02-19 23:08:35 -0800235 addedDeviceEvents.put(id, deviceEvent);
236 removedDeviceEvents.remove(id);
Pavlin Radoslavov706add22014-02-20 12:15:59 -0800237 reorderedAddedDeviceEvents.remove(id);
Pavlin Radoslavov018d5332014-02-19 23:08:35 -0800238 }
Pavlin Radoslavov721a2e02014-02-14 23:40:14 -0800239 break;
240 case ENTRY_REMOVE:
241 log.debug("Topology event ENTRY_REMOVE: {}", topologyEvent);
Pavlin Radoslavov018d5332014-02-19 23:08:35 -0800242 if (switchEvent != null) {
Yuta HIGUCHIa341b112014-02-23 15:42:00 -0800243 ByteBuffer id = switchEvent.getIDasByteBuffer();
Pavlin Radoslavov018d5332014-02-19 23:08:35 -0800244 addedSwitchEvents.remove(id);
245 removedSwitchEvents.put(id, switchEvent);
Pavlin Radoslavov706add22014-02-20 12:15:59 -0800246 // Switch Events are not affected by event reordering
Pavlin Radoslavov018d5332014-02-19 23:08:35 -0800247 }
248 if (portEvent != null) {
Yuta HIGUCHIa341b112014-02-23 15:42:00 -0800249 ByteBuffer id = portEvent.getIDasByteBuffer();
Pavlin Radoslavov018d5332014-02-19 23:08:35 -0800250 addedPortEvents.remove(id);
251 removedPortEvents.put(id, portEvent);
Pavlin Radoslavov706add22014-02-20 12:15:59 -0800252 reorderedAddedPortEvents.remove(id);
Pavlin Radoslavov018d5332014-02-19 23:08:35 -0800253 }
254 if (linkEvent != null) {
Yuta HIGUCHIa341b112014-02-23 15:42:00 -0800255 ByteBuffer id = linkEvent.getIDasByteBuffer();
Pavlin Radoslavov018d5332014-02-19 23:08:35 -0800256 addedLinkEvents.remove(id);
257 removedLinkEvents.put(id, linkEvent);
Pavlin Radoslavov706add22014-02-20 12:15:59 -0800258 reorderedAddedLinkEvents.remove(id);
Pavlin Radoslavov018d5332014-02-19 23:08:35 -0800259 }
260 if (deviceEvent != null) {
Yuta HIGUCHIa341b112014-02-23 15:42:00 -0800261 ByteBuffer id = deviceEvent.getIDasByteBuffer();
Pavlin Radoslavov018d5332014-02-19 23:08:35 -0800262 addedDeviceEvents.remove(id);
263 removedDeviceEvents.put(id, deviceEvent);
Pavlin Radoslavov706add22014-02-20 12:15:59 -0800264 reorderedAddedDeviceEvents.remove(id);
Pavlin Radoslavov018d5332014-02-19 23:08:35 -0800265 }
Pavlin Radoslavov721a2e02014-02-14 23:40:14 -0800266 break;
267 }
268 }
Pavlin Radoslavov3c9cc552014-02-20 09:58:38 -0800269
270 //
Pavlin Radoslavov8ffb8bf2014-02-20 15:34:26 -0800271 // Lock the Network Graph while it is modified
272 //
273 networkGraph.acquireWriteLock();
274
Jonathan Hart26241692014-02-20 16:31:11 -0800275 try {
276 //
277 // Apply the classified events.
278 //
279 // Apply the "add" events in the proper order:
280 // switch, port, link, device
281 //
282 for (SwitchEvent switchEvent : addedSwitchEvents.values())
283 addSwitch(switchEvent);
284 for (PortEvent portEvent : addedPortEvents.values())
285 addPort(portEvent);
286 for (LinkEvent linkEvent : addedLinkEvents.values())
287 addLink(linkEvent);
288 for (DeviceEvent deviceEvent : addedDeviceEvents.values())
289 addDevice(deviceEvent);
290 //
291 // Apply the "remove" events in the reverse order:
292 // device, link, port, switch
293 //
294 for (DeviceEvent deviceEvent : removedDeviceEvents.values())
295 removeDevice(deviceEvent);
296 for (LinkEvent linkEvent : removedLinkEvents.values())
297 removeLink(linkEvent);
298 for (PortEvent portEvent : removedPortEvents.values())
299 removePort(portEvent);
300 for (SwitchEvent switchEvent : removedSwitchEvents.values())
301 removeSwitch(switchEvent);
Yuta HIGUCHI3aca81a2014-02-23 12:41:19 -0800302
Jonathan Hart26241692014-02-20 16:31:11 -0800303 //
304 // Apply reordered events
305 //
306 applyReorderedEvents(! addedSwitchEvents.isEmpty(),
307 ! addedPortEvents.isEmpty());
Yuta HIGUCHI3aca81a2014-02-23 12:41:19 -0800308
Jonathan Hart26241692014-02-20 16:31:11 -0800309 }
310 finally {
311 //
312 // Network Graph modifications completed: Release the lock
313 //
314 networkGraph.releaseWriteLock();
315 }
Yuta HIGUCHI3aca81a2014-02-23 12:41:19 -0800316
Pavlin Radoslavov8ffb8bf2014-02-20 15:34:26 -0800317 //
Pavlin Radoslavov74986ce2014-02-20 13:17:20 -0800318 // Dispatch the Topology Notification Events to the applications
319 //
320 dispatchNetworkGraphEvents();
Pavlin Radoslavov721a2e02014-02-14 23:40:14 -0800321 }
322
323 /**
324 * Receive a notification that an entry is added.
325 *
326 * @param value the value for the entry.
327 */
328 @Override
329 public void entryAdded(TopologyEvent value) {
330 EventEntry<TopologyEvent> eventEntry =
331 new EventEntry<TopologyEvent>(EventEntry.Type.ENTRY_ADD,
332 value);
333 topologyEvents.add(eventEntry);
334 }
335
336 /**
337 * Receive a notification that an entry is removed.
338 *
339 * @param value the value for the entry.
340 */
341 @Override
342 public void entryRemoved(TopologyEvent value) {
343 EventEntry<TopologyEvent> eventEntry =
344 new EventEntry<TopologyEvent>(EventEntry.Type.ENTRY_REMOVE,
345 value);
346 topologyEvents.add(eventEntry);
347 }
348
349 /**
350 * Receive a notification that an entry is updated.
351 *
352 * @param value the value for the entry.
353 */
354 @Override
355 public void entryUpdated(TopologyEvent value) {
356 // NOTE: The ADD and UPDATE events are processed in same way
357 entryAdded(value);
358 }
359 }
360
361 /**
362 * Startup processing.
363 *
364 * @param datagridService the datagrid service to use.
365 */
366 void startup(IDatagridService datagridService) {
367 eventChannel = datagridService.addListener(EVENT_CHANNEL_NAME,
368 eventHandler,
369 byte[].class,
370 TopologyEvent.class);
371 eventHandler.start();
372 }
373
Pavlin Radoslavov74986ce2014-02-20 13:17:20 -0800374 /**
375 * Dispatch Network Graph Events to the listeners.
376 */
377 private void dispatchNetworkGraphEvents() {
378 if (apiAddedSwitchEvents.isEmpty() &&
379 apiRemovedSwitchEvents.isEmpty() &&
380 apiAddedPortEvents.isEmpty() &&
381 apiRemovedPortEvents.isEmpty() &&
382 apiAddedLinkEvents.isEmpty() &&
383 apiRemovedLinkEvents.isEmpty() &&
384 apiAddedDeviceEvents.isEmpty() &&
385 apiRemovedDeviceEvents.isEmpty()) {
386 return; // No events to dispatch
387 }
388
Yuta HIGUCHI3aca81a2014-02-23 12:41:19 -0800389 if (log.isDebugEnabled()) {
390 //
391 // Debug statements
392 // TODO: Those statements should be removed in the future
393 //
394 for (SwitchEvent switchEvent : apiAddedSwitchEvents)
395 log.debug("Dispatch Network Graph Event: ADDED {}", switchEvent);
396 for (SwitchEvent switchEvent : apiRemovedSwitchEvents)
397 log.debug("Dispatch Network Graph Event: REMOVED {}", switchEvent);
398 for (PortEvent portEvent : apiAddedPortEvents)
399 log.debug("Dispatch Network Graph Event: ADDED {}", portEvent);
400 for (PortEvent portEvent : apiRemovedPortEvents)
401 log.debug("Dispatch Network Graph Event: REMOVED {}", portEvent);
402 for (LinkEvent linkEvent : apiAddedLinkEvents)
403 log.debug("Dispatch Network Graph Event: ADDED {}", linkEvent);
404 for (LinkEvent linkEvent : apiRemovedLinkEvents)
405 log.debug("Dispatch Network Graph Event: REMOVED {}", linkEvent);
406 for (DeviceEvent deviceEvent : apiAddedDeviceEvents)
407 log.debug("Dispatch Network Graph Event: ADDED {}", deviceEvent);
408 for (DeviceEvent deviceEvent : apiRemovedDeviceEvents)
409 log.debug("Dispatch Network Graph Event: REMOVED {}", deviceEvent);
410 }
adminbc181552014-02-21 18:36:42 -0800411
Pavlin Radoslavov74986ce2014-02-20 13:17:20 -0800412 // Deliver the events
413 for (INetworkGraphListener listener : this.networkGraphListeners) {
414 // TODO: Should copy before handing them over to listener?
415 listener.networkGraphEvents(apiAddedSwitchEvents,
416 apiRemovedSwitchEvents,
417 apiAddedPortEvents,
418 apiRemovedPortEvents,
419 apiAddedLinkEvents,
420 apiRemovedLinkEvents,
421 apiAddedDeviceEvents,
422 apiRemovedDeviceEvents);
423 }
424
425 //
426 // Cleanup
427 //
428 apiAddedSwitchEvents.clear();
429 apiRemovedSwitchEvents.clear();
430 apiAddedPortEvents.clear();
431 apiRemovedPortEvents.clear();
432 apiAddedLinkEvents.clear();
433 apiRemovedLinkEvents.clear();
434 apiAddedDeviceEvents.clear();
435 apiRemovedDeviceEvents.clear();
436 }
437
438 /**
439 * Apply reordered events.
440 *
441 * @param hasAddedSwitchEvents true if there were Added Switch Events.
442 * @param hasAddedPortEvents true if there were Added Port Events.
443 */
444 private void applyReorderedEvents(boolean hasAddedSwitchEvents,
445 boolean hasAddedPortEvents) {
446 if (! (hasAddedSwitchEvents || hasAddedPortEvents))
447 return; // Nothing to do
448
449 //
450 // Try to apply the reordered events.
451 //
452 // NOTE: For simplicity we try to apply all events of a particular
453 // type if any "parent" type event was processed:
454 // - Apply reordered Port Events if Switches were added
455 // - Apply reordered Link and Device Events if Switches or Ports
456 // were added
457 //
adminbc181552014-02-21 18:36:42 -0800458
Pavlin Radoslavov74986ce2014-02-20 13:17:20 -0800459 //
460 // Apply reordered Port Events if Switches were added
461 //
462 if (hasAddedSwitchEvents) {
adminbc181552014-02-21 18:36:42 -0800463 Map<ByteBuffer, PortEvent> portEvents = reorderedAddedPortEvents;
464 reorderedAddedPortEvents = new HashMap<>();
Pavlin Radoslavov74986ce2014-02-20 13:17:20 -0800465 for (PortEvent portEvent : portEvents.values())
466 addPort(portEvent);
467 }
468 //
469 // Apply reordered Link and Device Events if Switches or Ports
470 // were added.
471 //
adminbc181552014-02-21 18:36:42 -0800472 Map<ByteBuffer, LinkEvent> linkEvents = reorderedAddedLinkEvents;
473 reorderedAddedLinkEvents = new HashMap<>();
Pavlin Radoslavov74986ce2014-02-20 13:17:20 -0800474 for (LinkEvent linkEvent : linkEvents.values())
475 addLink(linkEvent);
adminbc181552014-02-21 18:36:42 -0800476 //
477 Map<ByteBuffer, DeviceEvent> deviceEvents = reorderedAddedDeviceEvents;
478 reorderedAddedDeviceEvents = new HashMap<>();
Pavlin Radoslavov74986ce2014-02-20 13:17:20 -0800479 for (DeviceEvent deviceEvent : deviceEvents.values())
480 addDevice(deviceEvent);
481 }
482
Pavlin Radoslavov734ff5a2014-02-26 10:20:43 -0800483 /**
484 * Switch discovered event.
485 *
486 * @param switchEvent the switch event.
487 * @param portEvents the corresponding port events for the switch.
488 */
Pavlin Radoslavovc1cfde52014-02-19 11:35:29 -0800489 @Override
Pavlin Radoslavov018d5332014-02-19 23:08:35 -0800490 public void putSwitchDiscoveryEvent(SwitchEvent switchEvent,
491 Collection<PortEvent> portEvents) {
492 if (datastore.addSwitch(switchEvent, portEvents)) {
Pavlin Radoslavovc1cfde52014-02-19 11:35:29 -0800493 // Send out notification
Pavlin Radoslavov87dcc262014-02-19 21:13:23 -0800494 TopologyEvent topologyEvent = new TopologyEvent(switchEvent);
Pavlin Radoslavovc1cfde52014-02-19 11:35:29 -0800495 eventChannel.addEntry(topologyEvent.getID(), topologyEvent);
Pavlin Radoslavov018d5332014-02-19 23:08:35 -0800496
Pavlin Radoslavov26d83402014-02-20 15:24:30 -0800497 // Send out notification for each port
Pavlin Radoslavov018d5332014-02-19 23:08:35 -0800498 for (PortEvent portEvent : portEvents) {
499 topologyEvent = new TopologyEvent(portEvent);
500 eventChannel.addEntry(topologyEvent.getID(), topologyEvent);
501 }
Pavlin Radoslavov26d83402014-02-20 15:24:30 -0800502
503 //
504 // Keep track of the added ports
505 //
506 // Get the old Port Events
507 Map<ByteBuffer, PortEvent> oldPortEvents =
508 discoveredAddedPortEvents.get(switchEvent.getDpid());
509 if (oldPortEvents == null)
510 oldPortEvents = new HashMap<>();
511
512 // Store the new Port Events in the local cache
513 Map<ByteBuffer, PortEvent> newPortEvents = new HashMap<>();
514 for (PortEvent portEvent : portEvents) {
Yuta HIGUCHIa341b112014-02-23 15:42:00 -0800515 ByteBuffer id = portEvent.getIDasByteBuffer();
Pavlin Radoslavov26d83402014-02-20 15:24:30 -0800516 newPortEvents.put(id, portEvent);
517 }
518 discoveredAddedPortEvents.put(switchEvent.getDpid(),
519 newPortEvents);
520
521 //
522 // Extract the removed ports
523 //
524 List<PortEvent> removedPortEvents = new LinkedList<>();
525 for (Map.Entry<ByteBuffer, PortEvent> entry : oldPortEvents.entrySet()) {
526 ByteBuffer key = entry.getKey();
527 PortEvent portEvent = entry.getValue();
528 if (! newPortEvents.containsKey(key))
529 removedPortEvents.add(portEvent);
530 }
531
532 // Cleanup old removed ports
533 for (PortEvent portEvent : removedPortEvents)
534 removePortDiscoveryEvent(portEvent);
Pavlin Radoslavovc1cfde52014-02-19 11:35:29 -0800535 }
Pavlin Radoslavovc1cfde52014-02-19 11:35:29 -0800536 }
537
Pavlin Radoslavov734ff5a2014-02-26 10:20:43 -0800538 /**
539 * Switch removed event.
540 *
541 * @param switchEvent the switch event.
542 */
Pavlin Radoslavovc1cfde52014-02-19 11:35:29 -0800543 @Override
Pavlin Radoslavov6ea84a42014-02-19 15:50:01 -0800544 public void removeSwitchDiscoveryEvent(SwitchEvent switchEvent) {
Pavlin Radoslavov26d83402014-02-20 15:24:30 -0800545 // Get the old Port Events
546 Map<ByteBuffer, PortEvent> oldPortEvents =
547 discoveredAddedPortEvents.get(switchEvent.getDpid());
548 if (oldPortEvents == null)
549 oldPortEvents = new HashMap<>();
Pavlin Radoslavov018d5332014-02-19 23:08:35 -0800550
Pavlin Radoslavov26d83402014-02-20 15:24:30 -0800551 if (datastore.deactivateSwitch(switchEvent, oldPortEvents.values())) {
Pavlin Radoslavovc1cfde52014-02-19 11:35:29 -0800552 // Send out notification
553 eventChannel.removeEntry(switchEvent.getID());
Pavlin Radoslavov018d5332014-02-19 23:08:35 -0800554
Pavlin Radoslavov6f870a12014-02-24 14:25:54 -0800555 //
556 // Send out notification for each port.
557 //
558 // NOTE: We don't use removePortDiscoveryEvent() for the cleanup,
559 // because it will attempt to remove the port from the database,
560 // and the deactiveSwitch() call above already removed all ports.
561 //
Pavlin Radoslavov26d83402014-02-20 15:24:30 -0800562 for (PortEvent portEvent : oldPortEvents.values())
Pavlin Radoslavov018d5332014-02-19 23:08:35 -0800563 eventChannel.removeEntry(portEvent.getID());
Pavlin Radoslavov26d83402014-02-20 15:24:30 -0800564 discoveredAddedPortEvents.remove(switchEvent.getDpid());
565
566 // Cleanup for each link
567 Map<ByteBuffer, LinkEvent> oldLinkEvents =
568 discoveredAddedLinkEvents.get(switchEvent.getDpid());
569 if (oldLinkEvents != null) {
Yuta HIGUCHI95b20352014-02-24 12:06:27 -0800570 for (LinkEvent linkEvent : new ArrayList<>(oldLinkEvents.values())) {
Pavlin Radoslavov26d83402014-02-20 15:24:30 -0800571 removeLinkDiscoveryEvent(linkEvent);
Yuta HIGUCHI95b20352014-02-24 12:06:27 -0800572 }
Pavlin Radoslavov26d83402014-02-20 15:24:30 -0800573 discoveredAddedLinkEvents.remove(switchEvent.getDpid());
574 }
575
576 // Cleanup for each device
577 Map<ByteBuffer, DeviceEvent> oldDeviceEvents =
578 discoveredAddedDeviceEvents.get(switchEvent.getDpid());
579 if (oldDeviceEvents != null) {
Yuta HIGUCHI95b20352014-02-24 12:06:27 -0800580 for (DeviceEvent deviceEvent : new ArrayList<>(oldDeviceEvents.values())) {
Pavlin Radoslavov26d83402014-02-20 15:24:30 -0800581 removeDeviceDiscoveryEvent(deviceEvent);
Yuta HIGUCHI95b20352014-02-24 12:06:27 -0800582 }
Pavlin Radoslavov26d83402014-02-20 15:24:30 -0800583 discoveredAddedDeviceEvents.remove(switchEvent.getDpid());
Pavlin Radoslavov018d5332014-02-19 23:08:35 -0800584 }
Pavlin Radoslavovc1cfde52014-02-19 11:35:29 -0800585 }
Pavlin Radoslavovc1cfde52014-02-19 11:35:29 -0800586 }
587
Pavlin Radoslavov734ff5a2014-02-26 10:20:43 -0800588 /**
589 * Port discovered event.
590 *
591 * @param portEvent the port event.
592 */
Pavlin Radoslavovc1cfde52014-02-19 11:35:29 -0800593 @Override
Pavlin Radoslavov6ea84a42014-02-19 15:50:01 -0800594 public void putPortDiscoveryEvent(PortEvent portEvent) {
Pavlin Radoslavov50cd1482014-02-19 16:57:03 -0800595 if (datastore.addPort(portEvent)) {
Pavlin Radoslavovc1cfde52014-02-19 11:35:29 -0800596 // Send out notification
Pavlin Radoslavov87dcc262014-02-19 21:13:23 -0800597 TopologyEvent topologyEvent = new TopologyEvent(portEvent);
Pavlin Radoslavov018d5332014-02-19 23:08:35 -0800598 eventChannel.addEntry(topologyEvent.getID(), topologyEvent);
Pavlin Radoslavov26d83402014-02-20 15:24:30 -0800599
600 // Store the new Port Event in the local cache
601 Map<ByteBuffer, PortEvent> oldPortEvents =
602 discoveredAddedPortEvents.get(portEvent.getDpid());
603 if (oldPortEvents == null) {
604 oldPortEvents = new HashMap<>();
605 discoveredAddedPortEvents.put(portEvent.getDpid(),
606 oldPortEvents);
607 }
Yuta HIGUCHIa341b112014-02-23 15:42:00 -0800608 ByteBuffer id = portEvent.getIDasByteBuffer();
Pavlin Radoslavov26d83402014-02-20 15:24:30 -0800609 oldPortEvents.put(id, portEvent);
Pavlin Radoslavovc1cfde52014-02-19 11:35:29 -0800610 }
Pavlin Radoslavovc1cfde52014-02-19 11:35:29 -0800611 }
612
Pavlin Radoslavov734ff5a2014-02-26 10:20:43 -0800613 /**
614 * Port removed event.
615 *
616 * @param portEvent the port event.
617 */
Pavlin Radoslavovc1cfde52014-02-19 11:35:29 -0800618 @Override
Pavlin Radoslavov6ea84a42014-02-19 15:50:01 -0800619 public void removePortDiscoveryEvent(PortEvent portEvent) {
Pavlin Radoslavov50cd1482014-02-19 16:57:03 -0800620 if (datastore.deactivatePort(portEvent)) {
Pavlin Radoslavovc1cfde52014-02-19 11:35:29 -0800621 // Send out notification
622 eventChannel.removeEntry(portEvent.getID());
Pavlin Radoslavov26d83402014-02-20 15:24:30 -0800623
624 // Cleanup the Port Event from the local cache
625 Map<ByteBuffer, PortEvent> oldPortEvents =
626 discoveredAddedPortEvents.get(portEvent.getDpid());
627 if (oldPortEvents != null) {
Yuta HIGUCHIa341b112014-02-23 15:42:00 -0800628 ByteBuffer id = portEvent.getIDasByteBuffer();
Pavlin Radoslavov26d83402014-02-20 15:24:30 -0800629 oldPortEvents.remove(id);
630 }
631
632 // Cleanup for the incoming link
633 Map<ByteBuffer, LinkEvent> oldLinkEvents =
634 discoveredAddedLinkEvents.get(portEvent.getDpid());
635 if (oldLinkEvents != null) {
Pavlin Radoslavov6f870a12014-02-24 14:25:54 -0800636 for (LinkEvent linkEvent : new ArrayList<>(oldLinkEvents.values())) {
Pavlin Radoslavov26d83402014-02-20 15:24:30 -0800637 if (linkEvent.getDst().equals(portEvent.id)) {
638 removeLinkDiscoveryEvent(linkEvent);
Yuta HIGUCHI95b20352014-02-24 12:06:27 -0800639 // XXX If we change our model to allow multiple Link on
640 // a Port, this loop must be fixed to allow continuing.
Pavlin Radoslavov26d83402014-02-20 15:24:30 -0800641 break;
642 }
643 }
644 }
645
646 // Cleanup for the connected devices
647 // TODO: The implementation below is probably wrong
648 List<DeviceEvent> removedDeviceEvents = new LinkedList<>();
649 Map<ByteBuffer, DeviceEvent> oldDeviceEvents =
650 discoveredAddedDeviceEvents.get(portEvent.getDpid());
651 if (oldDeviceEvents != null) {
Yuta HIGUCHI95b20352014-02-24 12:06:27 -0800652 for (DeviceEvent deviceEvent : new ArrayList<>(oldDeviceEvents.values())) {
Pavlin Radoslavov26d83402014-02-20 15:24:30 -0800653 for (SwitchPort swp : deviceEvent.getAttachmentPoints()) {
654 if (swp.equals(portEvent.id)) {
655 removedDeviceEvents.add(deviceEvent);
Pavlin Radoslavov26d83402014-02-20 15:24:30 -0800656 }
657 }
658 }
659 for (DeviceEvent deviceEvent : removedDeviceEvents)
660 removeDeviceDiscoveryEvent(deviceEvent);
661 }
Pavlin Radoslavovc1cfde52014-02-19 11:35:29 -0800662 }
Pavlin Radoslavovc1cfde52014-02-19 11:35:29 -0800663 }
664
Pavlin Radoslavov734ff5a2014-02-26 10:20:43 -0800665 /**
666 * Link discovered event.
667 *
668 * @param linkEvent the link event.
669 */
Pavlin Radoslavovc1cfde52014-02-19 11:35:29 -0800670 @Override
Pavlin Radoslavov6ea84a42014-02-19 15:50:01 -0800671 public void putLinkDiscoveryEvent(LinkEvent linkEvent) {
Pavlin Radoslavov50cd1482014-02-19 16:57:03 -0800672 if (datastore.addLink(linkEvent)) {
Pavlin Radoslavovc1cfde52014-02-19 11:35:29 -0800673 // Send out notification
Pavlin Radoslavov87dcc262014-02-19 21:13:23 -0800674 TopologyEvent topologyEvent = new TopologyEvent(linkEvent);
Pavlin Radoslavovc1cfde52014-02-19 11:35:29 -0800675 eventChannel.addEntry(topologyEvent.getID(), topologyEvent);
Pavlin Radoslavov26d83402014-02-20 15:24:30 -0800676
677 // Store the new Link Event in the local cache
678 Map<ByteBuffer, LinkEvent> oldLinkEvents =
679 discoveredAddedLinkEvents.get(linkEvent.getDst().getDpid());
680 if (oldLinkEvents == null) {
681 oldLinkEvents = new HashMap<>();
682 discoveredAddedLinkEvents.put(linkEvent.getDst().getDpid(),
683 oldLinkEvents);
684 }
Yuta HIGUCHIa341b112014-02-23 15:42:00 -0800685 ByteBuffer id = linkEvent.getIDasByteBuffer();
Pavlin Radoslavov26d83402014-02-20 15:24:30 -0800686 oldLinkEvents.put(id, linkEvent);
Pavlin Radoslavovc1cfde52014-02-19 11:35:29 -0800687 }
Pavlin Radoslavovc1cfde52014-02-19 11:35:29 -0800688 }
689
Pavlin Radoslavov734ff5a2014-02-26 10:20:43 -0800690 /**
691 * Link removed event.
692 *
693 * @param linkEvent the link event.
694 */
Pavlin Radoslavovc1cfde52014-02-19 11:35:29 -0800695 @Override
Pavlin Radoslavov6ea84a42014-02-19 15:50:01 -0800696 public void removeLinkDiscoveryEvent(LinkEvent linkEvent) {
Pavlin Radoslavov50cd1482014-02-19 16:57:03 -0800697 if (datastore.removeLink(linkEvent)) {
Pavlin Radoslavovc1cfde52014-02-19 11:35:29 -0800698 // Send out notification
699 eventChannel.removeEntry(linkEvent.getID());
Pavlin Radoslavov26d83402014-02-20 15:24:30 -0800700
701 // Cleanup the Link Event from the local cache
702 Map<ByteBuffer, LinkEvent> oldLinkEvents =
703 discoveredAddedLinkEvents.get(linkEvent.getDst().getDpid());
704 if (oldLinkEvents != null) {
Yuta HIGUCHIa341b112014-02-23 15:42:00 -0800705 ByteBuffer id = linkEvent.getIDasByteBuffer();
Pavlin Radoslavov26d83402014-02-20 15:24:30 -0800706 oldLinkEvents.remove(id);
707 }
Jonathan Hart22eb9882014-02-11 15:52:59 -0800708 }
Pavlin Radoslavovc1cfde52014-02-19 11:35:29 -0800709 }
Jonathan Hart22eb9882014-02-11 15:52:59 -0800710
Pavlin Radoslavov734ff5a2014-02-26 10:20:43 -0800711 /**
712 * Device discovered event.
713 *
714 * @param deviceEvent the device event.
715 */
Pavlin Radoslavovc1cfde52014-02-19 11:35:29 -0800716 @Override
Pavlin Radoslavov6ea84a42014-02-19 15:50:01 -0800717 public void putDeviceDiscoveryEvent(DeviceEvent deviceEvent) {
Pavlin Radoslavov50cd1482014-02-19 16:57:03 -0800718 if (datastore.addDevice(deviceEvent)) {
Pavlin Radoslavovc1cfde52014-02-19 11:35:29 -0800719 // Send out notification
Pavlin Radoslavov87dcc262014-02-19 21:13:23 -0800720 TopologyEvent topologyEvent = new TopologyEvent(deviceEvent);
Pavlin Radoslavov50cd1482014-02-19 16:57:03 -0800721 eventChannel.addEntry(topologyEvent.getID(), topologyEvent);
Pavlin Radoslavov26d83402014-02-20 15:24:30 -0800722
723 // Store the new Device Event in the local cache
724 // TODO: The implementation below is probably wrong
725 for (SwitchPort swp : deviceEvent.getAttachmentPoints()) {
726 Map<ByteBuffer, DeviceEvent> oldDeviceEvents =
727 discoveredAddedDeviceEvents.get(swp.getDpid());
728 if (oldDeviceEvents == null) {
729 oldDeviceEvents = new HashMap<>();
730 discoveredAddedDeviceEvents.put(swp.getDpid(),
731 oldDeviceEvents);
732 }
Yuta HIGUCHIa341b112014-02-23 15:42:00 -0800733 ByteBuffer id = deviceEvent.getIDasByteBuffer();
Pavlin Radoslavov26d83402014-02-20 15:24:30 -0800734 oldDeviceEvents.put(id, deviceEvent);
735 }
Jonathan Hart22eb9882014-02-11 15:52:59 -0800736 }
Pavlin Radoslavovc1cfde52014-02-19 11:35:29 -0800737 }
Jonathan Hart22eb9882014-02-11 15:52:59 -0800738
Pavlin Radoslavov734ff5a2014-02-26 10:20:43 -0800739 /**
740 * Device removed event.
741 *
742 * @param deviceEvent the device event.
743 */
Pavlin Radoslavovc1cfde52014-02-19 11:35:29 -0800744 @Override
Pavlin Radoslavov6ea84a42014-02-19 15:50:01 -0800745 public void removeDeviceDiscoveryEvent(DeviceEvent deviceEvent) {
Pavlin Radoslavov50cd1482014-02-19 16:57:03 -0800746 if (datastore.removeDevice(deviceEvent)) {
Pavlin Radoslavovc1cfde52014-02-19 11:35:29 -0800747 // Send out notification
748 eventChannel.removeEntry(deviceEvent.getID());
Pavlin Radoslavov26d83402014-02-20 15:24:30 -0800749
750 // Cleanup the Device Event from the local cache
751 // TODO: The implementation below is probably wrong
752 ByteBuffer id = ByteBuffer.wrap(deviceEvent.getID());
753 for (SwitchPort swp : deviceEvent.getAttachmentPoints()) {
754 Map<ByteBuffer, DeviceEvent> oldDeviceEvents =
755 discoveredAddedDeviceEvents.get(swp.getDpid());
756 if (oldDeviceEvents != null) {
757 oldDeviceEvents.remove(id);
758 }
759 }
Jonathan Hart22eb9882014-02-11 15:52:59 -0800760 }
Pavlin Radoslavovc1cfde52014-02-19 11:35:29 -0800761 }
Jonathan Hart22eb9882014-02-11 15:52:59 -0800762
Pavlin Radoslavov734ff5a2014-02-26 10:20:43 -0800763 /**
764 * Add a switch to the Network Graph.
765 *
766 * @param switchEvent the Switch Event with the switch to add.
767 */
Pavlin Radoslavov74986ce2014-02-20 13:17:20 -0800768 private void addSwitch(SwitchEvent switchEvent) {
769 Switch sw = networkGraph.getSwitch(switchEvent.getDpid());
Pavlin Radoslavov3c9cc552014-02-20 09:58:38 -0800770 if (sw == null) {
Pavlin Radoslavov74986ce2014-02-20 13:17:20 -0800771 sw = new SwitchImpl(networkGraph, switchEvent.getDpid());
Pavlin Radoslavov3c9cc552014-02-20 09:58:38 -0800772 networkGraph.putSwitch(sw);
773 } else {
774 // TODO: Update the switch attributes
775 // TODO: Nothing to do for now
776 }
Pavlin Radoslavov74986ce2014-02-20 13:17:20 -0800777 apiAddedSwitchEvents.add(switchEvent);
Pavlin Radoslavov3c9cc552014-02-20 09:58:38 -0800778 }
779
Pavlin Radoslavov734ff5a2014-02-26 10:20:43 -0800780 /**
781 * Remove a switch from the Network Graph.
782 *
783 * @param switchEvent the Switch Event with the switch to remove.
784 */
Pavlin Radoslavov74986ce2014-02-20 13:17:20 -0800785 private void removeSwitch(SwitchEvent switchEvent) {
786 Switch sw = networkGraph.getSwitch(switchEvent.getDpid());
Pavlin Radoslavov3c9cc552014-02-20 09:58:38 -0800787 if (sw == null) {
Pavlin Radoslavov74986ce2014-02-20 13:17:20 -0800788 log.warn("Switch {} already removed, ignoring", switchEvent);
Pavlin Radoslavov3c9cc552014-02-20 09:58:38 -0800789 return;
790 }
791
792 //
793 // Remove all Ports on the Switch
794 //
795 ArrayList<PortEvent> portsToRemove = new ArrayList<>();
796 for (Port port : sw.getPorts()) {
797 log.warn("Port {} on Switch {} should be removed prior to removing Switch. Removing Port now.",
Pavlin Radoslavov74986ce2014-02-20 13:17:20 -0800798 port, switchEvent);
Pavlin Radoslavov3c9cc552014-02-20 09:58:38 -0800799 PortEvent portEvent = new PortEvent(port.getDpid(),
800 port.getNumber());
801 portsToRemove.add(portEvent);
802 }
803 for (PortEvent portEvent : portsToRemove)
804 removePort(portEvent);
805
Pavlin Radoslavov74986ce2014-02-20 13:17:20 -0800806 networkGraph.removeSwitch(switchEvent.getDpid());
807 apiRemovedSwitchEvents.add(switchEvent);
Pavlin Radoslavov3c9cc552014-02-20 09:58:38 -0800808 }
809
Pavlin Radoslavov734ff5a2014-02-26 10:20:43 -0800810 /**
811 * Add a port to the Network Graph.
812 *
813 * @param portEvent the Port Event with the port to add.
814 */
Pavlin Radoslavov3c9cc552014-02-20 09:58:38 -0800815 private void addPort(PortEvent portEvent) {
816 Switch sw = networkGraph.getSwitch(portEvent.getDpid());
817 if (sw == null) {
Pavlin Radoslavov706add22014-02-20 12:15:59 -0800818 // Reordered event: delay the event in local cache
Yuta HIGUCHIa341b112014-02-23 15:42:00 -0800819 ByteBuffer id = portEvent.getIDasByteBuffer();
Pavlin Radoslavov706add22014-02-20 12:15:59 -0800820 reorderedAddedPortEvents.put(id, portEvent);
Pavlin Radoslavov3c9cc552014-02-20 09:58:38 -0800821 return;
822 }
823 SwitchImpl switchImpl = getSwitchImpl(sw);
824
825 Port port = sw.getPort(portEvent.getNumber());
826 if (port == null) {
827 port = new PortImpl(networkGraph, sw, portEvent.getNumber());
828 switchImpl.addPort(port);
829 } else {
830 // TODO: Update the port attributes
831 }
Pavlin Radoslavov74986ce2014-02-20 13:17:20 -0800832 apiAddedPortEvents.add(portEvent);
Pavlin Radoslavov3c9cc552014-02-20 09:58:38 -0800833 }
834
Pavlin Radoslavov734ff5a2014-02-26 10:20:43 -0800835 /**
836 * Remove a port from the Network Graph.
837 *
838 * @param portEvent the Port Event with the port to remove.
839 */
Pavlin Radoslavov3c9cc552014-02-20 09:58:38 -0800840 private void removePort(PortEvent portEvent) {
841 Switch sw = networkGraph.getSwitch(portEvent.getDpid());
842 if (sw == null) {
843 log.warn("Parent Switch for Port {} already removed, ignoring",
844 portEvent);
845 return;
846 }
847
848 Port port = sw.getPort(portEvent.getNumber());
849 if (port == null) {
850 log.warn("Port {} already removed, ignoring", portEvent);
851 return;
852 }
853
854 //
855 // Remove all Devices attached to the Port
856 //
857 ArrayList<DeviceEvent> devicesToRemove = new ArrayList<>();
858 for (Device device : port.getDevices()) {
859 log.debug("Removing Device {} on Port {}", device, portEvent);
860 DeviceEvent deviceEvent = new DeviceEvent(device.getMacAddress());
861 SwitchPort switchPort = new SwitchPort(port.getSwitch().getDpid(),
862 port.getNumber());
863 deviceEvent.addAttachmentPoint(switchPort);
864 devicesToRemove.add(deviceEvent);
865 }
866 for (DeviceEvent deviceEvent : devicesToRemove)
867 removeDevice(deviceEvent);
868
869 //
870 // Remove all Links connected to the Port
871 //
872 Set<Link> links = new HashSet<>();
873 links.add(port.getOutgoingLink());
874 links.add(port.getIncomingLink());
875 ArrayList<LinkEvent> linksToRemove = new ArrayList<>();
876 for (Link link : links) {
877 if (link == null)
878 continue;
879 log.debug("Removing Link {} on Port {}", link, portEvent);
880 LinkEvent linkEvent = new LinkEvent(link.getSrcSwitch().getDpid(),
881 link.getSrcPort().getNumber(),
882 link.getDstSwitch().getDpid(),
883 link.getDstPort().getNumber());
884 linksToRemove.add(linkEvent);
885 }
886 for (LinkEvent linkEvent : linksToRemove)
887 removeLink(linkEvent);
888
889 // Remove the Port from the Switch
890 SwitchImpl switchImpl = getSwitchImpl(sw);
891 switchImpl.removePort(port);
Pavlin Radoslavov74986ce2014-02-20 13:17:20 -0800892
893 apiRemovedPortEvents.add(portEvent);
Pavlin Radoslavov3c9cc552014-02-20 09:58:38 -0800894 }
895
Pavlin Radoslavov734ff5a2014-02-26 10:20:43 -0800896 /**
897 * Add a link to the Network Graph.
898 *
899 * @param linkEvent the Link Event with the link to add.
900 */
Pavlin Radoslavov3c9cc552014-02-20 09:58:38 -0800901 private void addLink(LinkEvent linkEvent) {
902 Port srcPort = networkGraph.getPort(linkEvent.getSrc().dpid,
903 linkEvent.getSrc().number);
Pavlin Radoslavov3c9cc552014-02-20 09:58:38 -0800904 Port dstPort = networkGraph.getPort(linkEvent.getDst().dpid,
905 linkEvent.getDst().number);
Pavlin Radoslavov706add22014-02-20 12:15:59 -0800906 if ((srcPort == null) || (dstPort == null)) {
907 // Reordered event: delay the event in local cache
Yuta HIGUCHIa341b112014-02-23 15:42:00 -0800908 ByteBuffer id = linkEvent.getIDasByteBuffer();
Pavlin Radoslavov706add22014-02-20 12:15:59 -0800909 reorderedAddedLinkEvents.put(id, linkEvent);
Pavlin Radoslavov3c9cc552014-02-20 09:58:38 -0800910 return;
911 }
912
913 // Get the Link instance from the Destination Port Incoming Link
914 Link link = dstPort.getIncomingLink();
915 assert(link == srcPort.getOutgoingLink());
916 if (link == null) {
917 link = new LinkImpl(networkGraph, srcPort, dstPort);
918 PortImpl srcPortImpl = getPortImpl(srcPort);
919 PortImpl dstPortImpl = getPortImpl(dstPort);
920 srcPortImpl.setOutgoingLink(link);
921 dstPortImpl.setIncomingLink(link);
922
923 // Remove all Devices attached to the Ports
924 ArrayList<DeviceEvent> devicesToRemove = new ArrayList<>();
925 ArrayList<Port> ports = new ArrayList<>();
926 ports.add(srcPort);
927 ports.add(dstPort);
928 for (Port port : ports) {
929 for (Device device : port.getDevices()) {
930 log.error("Device {} on Port {} should have been removed prior to adding Link {}",
931 device, port, linkEvent);
932 DeviceEvent deviceEvent =
933 new DeviceEvent(device.getMacAddress());
934 SwitchPort switchPort =
935 new SwitchPort(port.getSwitch().getDpid(),
936 port.getNumber());
937 deviceEvent.addAttachmentPoint(switchPort);
938 devicesToRemove.add(deviceEvent);
939 }
940 }
941 for (DeviceEvent deviceEvent : devicesToRemove)
942 removeDevice(deviceEvent);
943 } else {
944 // TODO: Update the link attributes
945 }
Pavlin Radoslavov74986ce2014-02-20 13:17:20 -0800946
947 apiAddedLinkEvents.add(linkEvent);
Pavlin Radoslavov3c9cc552014-02-20 09:58:38 -0800948 }
949
Pavlin Radoslavov734ff5a2014-02-26 10:20:43 -0800950 /**
951 * Remove a link from the Network Graph.
952 *
953 * @param linkEvent the Link Event with the link to remove.
954 */
Pavlin Radoslavov3c9cc552014-02-20 09:58:38 -0800955 private void removeLink(LinkEvent linkEvent) {
956 Port srcPort = networkGraph.getPort(linkEvent.getSrc().dpid,
957 linkEvent.getSrc().number);
958 if (srcPort == null) {
959 log.warn("Src Port for Link {} already removed, ignoring",
960 linkEvent);
961 return;
962 }
963
964 Port dstPort = networkGraph.getPort(linkEvent.getDst().dpid,
965 linkEvent.getDst().number);
966 if (dstPort == null) {
967 log.warn("Dst Port for Link {} already removed, ignoring",
968 linkEvent);
969 return;
970 }
971
972 //
973 // Remove the Link instance from the Destination Port Incoming Link
974 // and the Source Port Outgoing Link.
975 //
976 Link link = dstPort.getIncomingLink();
977 if (link == null) {
978 log.warn("Link {} already removed on destination Port", linkEvent);
979 }
980 link = srcPort.getOutgoingLink();
981 if (link == null) {
982 log.warn("Link {} already removed on src Port", linkEvent);
983 }
984 getPortImpl(dstPort).setIncomingLink(null);
985 getPortImpl(srcPort).setOutgoingLink(null);
Pavlin Radoslavov74986ce2014-02-20 13:17:20 -0800986
987 apiRemovedLinkEvents.add(linkEvent);
Pavlin Radoslavov3c9cc552014-02-20 09:58:38 -0800988 }
989
Pavlin Radoslavov734ff5a2014-02-26 10:20:43 -0800990 /**
991 * Add a device to the Network Graph.
992 *
993 * TODO: Device-related work is incomplete.
994 * TODO: Eventually, we might need to consider reordering
995 * or addLink() and addDevice() events on the same port.
996 *
997 * @param deviceEvent the Device Event with the device to add.
998 */
Pavlin Radoslavov3c9cc552014-02-20 09:58:38 -0800999 private void addDevice(DeviceEvent deviceEvent) {
1000 Device device = networkGraph.getDeviceByMac(deviceEvent.getMac());
1001 if (device == null) {
1002 device = new DeviceImpl(networkGraph, deviceEvent.getMac());
1003 }
1004 DeviceImpl deviceImpl = getDeviceImpl(device);
1005
1006 // Update the IP addresses
1007 for (InetAddress ipAddr : deviceEvent.getIpAddresses())
1008 deviceImpl.addIpAddress(ipAddr);
1009
1010 // Process each attachment point
1011 boolean attachmentFound = false;
1012 for (SwitchPort swp : deviceEvent.getAttachmentPoints()) {
1013 // Attached Ports must exist
1014 Port port = networkGraph.getPort(swp.dpid, swp.number);
1015 if (port == null) {
Pavlin Radoslavov706add22014-02-20 12:15:59 -08001016 // Reordered event: delay the event in local cache
Yuta HIGUCHIa341b112014-02-23 15:42:00 -08001017 ByteBuffer id = deviceEvent.getIDasByteBuffer();
Pavlin Radoslavov706add22014-02-20 12:15:59 -08001018 reorderedAddedDeviceEvents.put(id, deviceEvent);
Pavlin Radoslavov3c9cc552014-02-20 09:58:38 -08001019 continue;
1020 }
1021 // Attached Ports must not have Link
1022 if (port.getOutgoingLink() != null ||
1023 port.getIncomingLink() != null) {
1024 log.warn("Link (Out:{},In:{}) exist on the attachment point, skipping mutation.",
1025 port.getOutgoingLink(),
1026 port.getIncomingLink());
1027 continue;
1028 }
1029
1030 // Add Device <-> Port attachment
1031 PortImpl portImpl = getPortImpl(port);
1032 portImpl.addDevice(device);
1033 deviceImpl.addAttachmentPoint(port);
1034 attachmentFound = true;
1035 }
1036
1037 // Update the device in the Network Graph
Pavlin Radoslavov74986ce2014-02-20 13:17:20 -08001038 if (attachmentFound) {
Pavlin Radoslavov3c9cc552014-02-20 09:58:38 -08001039 networkGraph.putDevice(device);
Pavlin Radoslavov74986ce2014-02-20 13:17:20 -08001040 apiAddedDeviceEvents.add(deviceEvent);
1041 }
Pavlin Radoslavov3c9cc552014-02-20 09:58:38 -08001042 }
1043
Pavlin Radoslavov734ff5a2014-02-26 10:20:43 -08001044 /**
1045 * Remove a device from the Network Graph.
1046 *
1047 * TODO: Device-related work is incomplete.
1048 *
1049 * @param deviceEvent the Device Event with the device to remove.
1050 */
Pavlin Radoslavov3c9cc552014-02-20 09:58:38 -08001051 private void removeDevice(DeviceEvent deviceEvent) {
1052 Device device = networkGraph.getDeviceByMac(deviceEvent.getMac());
1053 if (device == null) {
1054 log.warn("Device {} already removed, ignoring", deviceEvent);
1055 return;
1056 }
1057 DeviceImpl deviceImpl = getDeviceImpl(device);
1058
1059 // Process each attachment point
1060 for (SwitchPort swp : deviceEvent.getAttachmentPoints()) {
1061 // Attached Ports must exist
1062 Port port = networkGraph.getPort(swp.dpid, swp.number);
1063 if (port == null) {
1064 log.warn("Port for the attachment point {} did not exist. skipping attachment point mutation", swp);
1065 continue;
1066 }
1067
1068 // Remove Device <-> Port attachment
1069 PortImpl portImpl = getPortImpl(port);
1070 portImpl.removeDevice(device);
1071 deviceImpl.removeAttachmentPoint(port);
1072 }
Pavlin Radoslavov74986ce2014-02-20 13:17:20 -08001073
Pavlin Radoslavov3c9cc552014-02-20 09:58:38 -08001074 networkGraph.removeDevice(device);
Pavlin Radoslavov74986ce2014-02-20 13:17:20 -08001075 apiRemovedDeviceEvents.add(deviceEvent);
Pavlin Radoslavov3c9cc552014-02-20 09:58:38 -08001076 }
Jonathan Hart22eb9882014-02-11 15:52:59 -08001077
Pavlin Radoslavovc1cfde52014-02-19 11:35:29 -08001078 /**
Pavlin Radoslavov734ff5a2014-02-26 10:20:43 -08001079 * Get the SwitchImpl-casted switch implementation.
Pavlin Radoslavovc1cfde52014-02-19 11:35:29 -08001080 *
Pavlin Radoslavov734ff5a2014-02-26 10:20:43 -08001081 * @param sw the Switch to cast.
1082 * @return the SwitchImpl-casted switch implementation.
Pavlin Radoslavovc1cfde52014-02-19 11:35:29 -08001083 */
Pavlin Radoslavovc1cfde52014-02-19 11:35:29 -08001084 private SwitchImpl getSwitchImpl(Switch sw) {
1085 if (sw instanceof SwitchImpl) {
Pavlin Radoslavov734ff5a2014-02-26 10:20:43 -08001086 return (SwitchImpl)sw;
Pavlin Radoslavovc1cfde52014-02-19 11:35:29 -08001087 }
1088 throw new ClassCastException("SwitchImpl expected, but found: " + sw);
1089 }
1090
Pavlin Radoslavov734ff5a2014-02-26 10:20:43 -08001091 /**
1092 * Get the PortImpl-casted port implementation.
1093 *
1094 * @param port the Port to cast.
1095 * @return the PortImpl-casted port implementation.
1096 */
1097 private PortImpl getPortImpl(Port port) {
1098 if (port instanceof PortImpl) {
1099 return (PortImpl)port;
Pavlin Radoslavovc1cfde52014-02-19 11:35:29 -08001100 }
Pavlin Radoslavov734ff5a2014-02-26 10:20:43 -08001101 throw new ClassCastException("PortImpl expected, but found: " + port);
Pavlin Radoslavovc1cfde52014-02-19 11:35:29 -08001102 }
1103
Pavlin Radoslavov734ff5a2014-02-26 10:20:43 -08001104 /**
1105 * Get the LinkImpl-casted link implementation.
1106 *
1107 * @param link the Link to cast.
1108 * @return the LinkImpl-casted link implementation.
1109 */
1110 private LinkImpl getLinkImpl(Link link) {
1111 if (link instanceof LinkImpl) {
1112 return (LinkImpl)link;
Pavlin Radoslavovc1cfde52014-02-19 11:35:29 -08001113 }
Pavlin Radoslavov734ff5a2014-02-26 10:20:43 -08001114 throw new ClassCastException("LinkImpl expected, but found: " + link);
Pavlin Radoslavovc1cfde52014-02-19 11:35:29 -08001115 }
1116
Pavlin Radoslavov734ff5a2014-02-26 10:20:43 -08001117 /**
1118 * Get the DeviceImpl-casted device implementation.
1119 *
1120 * @param device the Device to cast.
1121 * @return the DeviceImpl-casted device implementation.
1122 */
1123 private DeviceImpl getDeviceImpl(Device device) {
1124 if (device instanceof DeviceImpl) {
1125 return (DeviceImpl)device;
Pavlin Radoslavovc1cfde52014-02-19 11:35:29 -08001126 }
Pavlin Radoslavov734ff5a2014-02-26 10:20:43 -08001127 throw new ClassCastException("DeviceImpl expected, but found: " + device);
Pavlin Radoslavovc1cfde52014-02-19 11:35:29 -08001128 }
1129
Pavlin Radoslavov734ff5a2014-02-26 10:20:43 -08001130 /**
1131 * Read the whole topology from the database.
1132 *
1133 * @return a collection of EventEntry-encapsulated Topology Events for
1134 * the whole topology.
1135 */
Pavlin Radoslavov018d5332014-02-19 23:08:35 -08001136 private Collection<EventEntry<TopologyEvent>> readWholeTopologyFromDB() {
1137 Collection<EventEntry<TopologyEvent>> collection =
1138 new LinkedList<EventEntry<TopologyEvent>>();
1139
Pavlin Radoslavovc1cfde52014-02-19 11:35:29 -08001140 // XXX May need to clear whole topology first, depending on
1141 // how we initially subscribe to replication events
1142
Pavlin Radoslavov018d5332014-02-19 23:08:35 -08001143 // Add all active switches
Yuta HIGUCHI66ca1bf2014-03-12 18:34:09 -07001144 for (KVSwitch sw : KVSwitch.getAllSwitches()) {
1145 if (sw.getStatus() != KVSwitch.STATUS.ACTIVE) {
Pavlin Radoslavovc1cfde52014-02-19 11:35:29 -08001146 continue;
1147 }
Pavlin Radoslavov018d5332014-02-19 23:08:35 -08001148
1149 SwitchEvent switchEvent = new SwitchEvent(sw.getDpid());
1150 TopologyEvent topologyEvent = new TopologyEvent(switchEvent);
1151 EventEntry<TopologyEvent> eventEntry =
1152 new EventEntry<TopologyEvent>(EventEntry.Type.ENTRY_ADD,
1153 topologyEvent);
1154 collection.add(eventEntry);
Yuta HIGUCHIa536e762014-02-17 21:47:28 -08001155 }
1156
Pavlin Radoslavov018d5332014-02-19 23:08:35 -08001157 // Add all active ports
Yuta HIGUCHI66ca1bf2014-03-12 18:34:09 -07001158 for (KVPort p : KVPort.getAllPorts()) {
1159 if (p.getStatus() != KVPort.STATUS.ACTIVE) {
Pavlin Radoslavovc1cfde52014-02-19 11:35:29 -08001160 continue;
Yuta HIGUCHIa536e762014-02-17 21:47:28 -08001161 }
Pavlin Radoslavov018d5332014-02-19 23:08:35 -08001162
1163 PortEvent portEvent = new PortEvent(p.getDpid(), p.getNumber());
1164 TopologyEvent topologyEvent = new TopologyEvent(portEvent);
1165 EventEntry<TopologyEvent> eventEntry =
1166 new EventEntry<TopologyEvent>(EventEntry.Type.ENTRY_ADD,
1167 topologyEvent);
1168 collection.add(eventEntry);
Yuta HIGUCHIa536e762014-02-17 21:47:28 -08001169 }
1170
Pavlin Radoslavovc1cfde52014-02-19 11:35:29 -08001171 // TODO Is Device going to be in DB? If so, read from DB.
Yuta HIGUCHI66ca1bf2014-03-12 18:34:09 -07001172 // for (KVDevice d : KVDevice.getAllDevices()) {
Pavlin Radoslavovc1cfde52014-02-19 11:35:29 -08001173 // DeviceEvent devEvent = new DeviceEvent( MACAddress.valueOf(d.getMac()) );
1174 // for (byte[] portId : d.getAllPortIds() ) {
Yuta HIGUCHI66ca1bf2014-03-12 18:34:09 -07001175 // devEvent.addAttachmentPoint( new SwitchPort( KVPort.getDpidFromKey(portId), KVPort.getNumberFromKey(portId) ));
Pavlin Radoslavovc1cfde52014-02-19 11:35:29 -08001176 // }
1177 // }
1178
Yuta HIGUCHI66ca1bf2014-03-12 18:34:09 -07001179 for (KVLink l : KVLink.getAllLinks()) {
Pavlin Radoslavov018d5332014-02-19 23:08:35 -08001180 LinkEvent linkEvent = new LinkEvent(l.getSrc().dpid,
1181 l.getSrc().number,
1182 l.getDst().dpid,
1183 l.getDst().number);
1184 TopologyEvent topologyEvent = new TopologyEvent(linkEvent);
1185 EventEntry<TopologyEvent> eventEntry =
1186 new EventEntry<TopologyEvent>(EventEntry.Type.ENTRY_ADD,
1187 topologyEvent);
1188 collection.add(eventEntry);
Yuta HIGUCHI76df2472014-02-12 22:36:51 -08001189 }
Pavlin Radoslavov018d5332014-02-19 23:08:35 -08001190
1191 return collection;
Pavlin Radoslavovc1cfde52014-02-19 11:35:29 -08001192 }
Jonathan Hart062a2e82014-02-03 09:41:57 -08001193}