blob: 7fe7955a7393cfb0a515b14fc48f6af1d83a8b2a [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 HIGUCHI765cd0d2014-02-06 12:46:41 -080020import net.onrc.onos.datastore.topology.RCLink;
Jonathan Hart062a2e82014-02-03 09:41:57 -080021import net.onrc.onos.datastore.topology.RCPort;
22import net.onrc.onos.datastore.topology.RCSwitch;
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 HIGUCHI765cd0d2014-02-06 12:46:41 -080025import net.onrc.onos.ofcontroller.util.Dpid;
Yuta HIGUCHI170229f2014-02-17 15:47:54 -080026import net.onrc.onos.registry.controller.IControllerRegistryService;
Jonathan Hart062a2e82014-02-03 09:41:57 -080027
28import org.slf4j.Logger;
29import org.slf4j.LoggerFactory;
30
Yuta HIGUCHI181d34d2014-02-05 15:05:46 -080031/**
32 * The "NB" read-only Network Map.
33 *
Yuta HIGUCHI4bfdd532014-02-07 13:47:36 -080034 * - Maintain Invariant/Relationships between Topology Objects.
35 *
Yuta HIGUCHI765cd0d2014-02-06 12:46:41 -080036 * TODO To be synchronized based on TopologyEvent Notification.
Yuta HIGUCHI181d34d2014-02-05 15:05:46 -080037 *
Yuta HIGUCHIcb951982014-02-11 13:31:44 -080038 * TODO TBD: Caller is expected to maintain parent/child calling order. Parent
Yuta HIGUCHI1c700102014-02-12 16:30:52 -080039 * Object must exist before adding sub component(Add Switch -> Port).
Yuta HIGUCHIcb951982014-02-11 13:31:44 -080040 *
Yuta HIGUCHI4bfdd532014-02-07 13:47:36 -080041 * TODO TBD: This class may delay the requested change to handle event
42 * re-ordering. e.g.) Link Add came in, but Switch was not there.
Yuta HIGUCHIcb951982014-02-11 13:31:44 -080043 *
Yuta HIGUCHI181d34d2014-02-05 15:05:46 -080044 */
Pavlin Radoslavov87dcc262014-02-19 21:13:23 -080045public class TopologyManager implements NetworkGraphDiscoveryInterface {
Jonathan Hart062a2e82014-02-03 09:41:57 -080046
Yuta HIGUCHI80829d12014-02-05 20:16:56 -080047 private static final Logger log = LoggerFactory
Pavlin Radoslavovdb7dbb22014-02-18 14:45:10 -080048 .getLogger(TopologyManager.class);
Yuta HIGUCHIcd922f42014-02-11 18:59:11 -080049
Pavlin Radoslavov721a2e02014-02-14 23:40:14 -080050 private IEventChannel<byte[], TopologyEvent> eventChannel;
51 private static final String EVENT_CHANNEL_NAME = "onos.topology";
52 private EventHandler eventHandler = new EventHandler();
53
Jonathan Hart22eb9882014-02-11 15:52:59 -080054 private final NetworkGraphDatastore datastore;
Pavlin Radoslavov6d224ee2014-02-18 16:43:15 -080055 private final NetworkGraphImpl networkGraph = new NetworkGraphImpl();
Yuta HIGUCHI170229f2014-02-17 15:47:54 -080056 private final IControllerRegistryService registryService;
Yuta HIGUCHIa536e762014-02-17 21:47:28 -080057 private CopyOnWriteArrayList<INetworkGraphListener> networkGraphListeners;
Yuta HIGUCHI181d34d2014-02-05 15:05:46 -080058
Pavlin Radoslavov706add22014-02-20 12:15:59 -080059 //
60 // Local state for keeping track of reordered events.
61 // NOTE: Switch Events are not affected by the event reordering.
62 //
63 private Map<ByteBuffer, PortEvent> reorderedAddedPortEvents =
Pavlin Radoslavov018d5332014-02-19 23:08:35 -080064 new HashMap<ByteBuffer, PortEvent>();
Pavlin Radoslavov706add22014-02-20 12:15:59 -080065 private Map<ByteBuffer, LinkEvent> reorderedAddedLinkEvents =
Pavlin Radoslavov018d5332014-02-19 23:08:35 -080066 new HashMap<ByteBuffer, LinkEvent>();
Pavlin Radoslavov706add22014-02-20 12:15:59 -080067 private Map<ByteBuffer, DeviceEvent> reorderedAddedDeviceEvents =
Pavlin Radoslavov018d5332014-02-19 23:08:35 -080068 new HashMap<ByteBuffer, DeviceEvent>();
69
Pavlin Radoslavov74986ce2014-02-20 13:17:20 -080070 //
Pavlin Radoslavov26d83402014-02-20 15:24:30 -080071 // Local state for keeping track of locally discovered events so we can
72 // cleanup properly when a Switch or Port is removed.
73 //
74 // We keep all Port, Link and Device events per Switch DPID:
75 // - If a switch goes down, we remove all corresponding Port, Link and
76 // Device events.
77 // - If a port on a switch goes down, we remove all corresponding Link
78 // and Device events.
79 //
80 private Map<Long, Map<ByteBuffer, PortEvent>> discoveredAddedPortEvents =
81 new HashMap<>();
82 private Map<Long, Map<ByteBuffer, LinkEvent>> discoveredAddedLinkEvents =
83 new HashMap<>();
84 private Map<Long, Map<ByteBuffer, DeviceEvent>> discoveredAddedDeviceEvents =
85 new HashMap<>();
86
87 //
Pavlin Radoslavov74986ce2014-02-20 13:17:20 -080088 // Local state for keeping track of the application event notifications
89 //
90 List<SwitchEvent> apiAddedSwitchEvents = new LinkedList<SwitchEvent>();
91 List<SwitchEvent> apiRemovedSwitchEvents = new LinkedList<SwitchEvent>();
92 List<PortEvent> apiAddedPortEvents = new LinkedList<PortEvent>();
93 List<PortEvent> apiRemovedPortEvents = new LinkedList<PortEvent>();
94 List<LinkEvent> apiAddedLinkEvents = new LinkedList<LinkEvent>();
95 List<LinkEvent> apiRemovedLinkEvents = new LinkedList<LinkEvent>();
96 List<DeviceEvent> apiAddedDeviceEvents = new LinkedList<DeviceEvent>();
97 List<DeviceEvent> apiRemovedDeviceEvents = new LinkedList<DeviceEvent>();
98
Pavlin Radoslavovc1cfde52014-02-19 11:35:29 -080099 /**
100 * Constructor.
101 *
102 * @param registryService the Registry Service to use.
103 * @param networkGraphListeners the collection of Network Graph Listeners
104 * to use.
105 */
106 public TopologyManager(IControllerRegistryService registryService,
107 CopyOnWriteArrayList<INetworkGraphListener> networkGraphListeners) {
Jonathan Hartdaea86f2014-02-19 15:28:42 -0800108 datastore = new NetworkGraphDatastore();
Yuta HIGUCHI170229f2014-02-17 15:47:54 -0800109 this.registryService = registryService;
Yuta HIGUCHIa536e762014-02-17 21:47:28 -0800110 this.networkGraphListeners = networkGraphListeners;
Yuta HIGUCHI80829d12014-02-05 20:16:56 -0800111 }
Yuta HIGUCHI181d34d2014-02-05 15:05:46 -0800112
Pavlin Radoslavovc1cfde52014-02-19 11:35:29 -0800113 /**
114 * Get the Network Graph.
115 *
116 * @return the Network Graph.
117 */
Pavlin Radoslavov6d224ee2014-02-18 16:43:15 -0800118 NetworkGraph getNetworkGraph() {
119 return networkGraph;
120 }
121
Yuta HIGUCHI4bfdd532014-02-07 13:47:36 -0800122 /**
Pavlin Radoslavov721a2e02014-02-14 23:40:14 -0800123 * Event handler class.
124 */
125 private class EventHandler extends Thread implements
126 IEventChannelListener<byte[], TopologyEvent> {
127 private BlockingQueue<EventEntry<TopologyEvent>> topologyEvents =
128 new LinkedBlockingQueue<EventEntry<TopologyEvent>>();
129
130 /**
131 * Startup processing.
132 */
133 private void startup() {
134 //
Pavlin Radoslavov018d5332014-02-19 23:08:35 -0800135 // TODO: Read all state from the database:
136 //
137 // Collection<EventEntry<TopologyEvent>> collection =
138 // readWholeTopologyFromDB();
139 //
Pavlin Radoslavov721a2e02014-02-14 23:40:14 -0800140 // For now, as a shortcut we read it from the datagrid
141 //
142 Collection<TopologyEvent> topologyEvents =
143 eventChannel.getAllEntries();
144 Collection<EventEntry<TopologyEvent>> collection =
145 new LinkedList<EventEntry<TopologyEvent>>();
146
147 for (TopologyEvent topologyEvent : topologyEvents) {
148 EventEntry<TopologyEvent> eventEntry =
149 new EventEntry<TopologyEvent>(EventEntry.Type.ENTRY_ADD,
150 topologyEvent);
151 collection.add(eventEntry);
152 }
153 processEvents(collection);
154 }
155
156 /**
157 * Run the thread.
158 */
Yuta HIGUCHI240bf072014-02-17 10:55:21 -0800159 @Override
Pavlin Radoslavov721a2e02014-02-14 23:40:14 -0800160 public void run() {
161 Collection<EventEntry<TopologyEvent>> collection =
162 new LinkedList<EventEntry<TopologyEvent>>();
163
Pavlin Radoslavovdb7dbb22014-02-18 14:45:10 -0800164 this.setName("TopologyManager.EventHandler " + this.getId());
Pavlin Radoslavov721a2e02014-02-14 23:40:14 -0800165 startup();
166
167 //
168 // The main loop
169 //
170 try {
171 while (true) {
172 EventEntry<TopologyEvent> eventEntry = topologyEvents.take();
173 collection.add(eventEntry);
174 topologyEvents.drainTo(collection);
175
176 processEvents(collection);
177 collection.clear();
178 }
179 } catch (Exception exception) {
180 log.debug("Exception processing Topology Events: ", exception);
181 }
182 }
183
184 /**
185 * Process all topology events.
186 *
187 * @param events the events to process.
188 */
189 private void processEvents(Collection<EventEntry<TopologyEvent>> events) {
Pavlin Radoslavov706add22014-02-20 12:15:59 -0800190 // Local state for computing the final set of events
Pavlin Radoslavov26d83402014-02-20 15:24:30 -0800191 Map<ByteBuffer, SwitchEvent> addedSwitchEvents = new HashMap<>();
192 Map<ByteBuffer, SwitchEvent> removedSwitchEvents = new HashMap<>();
193 Map<ByteBuffer, PortEvent> addedPortEvents = new HashMap<>();
194 Map<ByteBuffer, PortEvent> removedPortEvents = new HashMap<>();
195 Map<ByteBuffer, LinkEvent> addedLinkEvents = new HashMap<>();
196 Map<ByteBuffer, LinkEvent> removedLinkEvents = new HashMap<>();
197 Map<ByteBuffer, DeviceEvent> addedDeviceEvents = new HashMap<>();
198 Map<ByteBuffer, DeviceEvent> removedDeviceEvents = new HashMap<>();
Pavlin Radoslavov3c9cc552014-02-20 09:58:38 -0800199
200 //
201 // Classify and suppress matching events
202 //
Pavlin Radoslavov721a2e02014-02-14 23:40:14 -0800203 for (EventEntry<TopologyEvent> event : events) {
204 TopologyEvent topologyEvent = event.eventData();
Pavlin Radoslavov018d5332014-02-19 23:08:35 -0800205 SwitchEvent switchEvent = topologyEvent.switchEvent;
206 PortEvent portEvent = topologyEvent.portEvent;
207 LinkEvent linkEvent = topologyEvent.linkEvent;
208 DeviceEvent deviceEvent = topologyEvent.deviceEvent;
209
210 //
Pavlin Radoslavov3c9cc552014-02-20 09:58:38 -0800211 // Extract the events
Pavlin Radoslavov018d5332014-02-19 23:08:35 -0800212 //
Pavlin Radoslavov721a2e02014-02-14 23:40:14 -0800213 switch (event.eventType()) {
214 case ENTRY_ADD:
215 log.debug("Topology event ENTRY_ADD: {}", topologyEvent);
Pavlin Radoslavov018d5332014-02-19 23:08:35 -0800216 if (switchEvent != null) {
217 ByteBuffer id = ByteBuffer.wrap(switchEvent.getID());
218 addedSwitchEvents.put(id, switchEvent);
219 removedSwitchEvents.remove(id);
Pavlin Radoslavov706add22014-02-20 12:15:59 -0800220 // Switch Events are not affected by event reordering
Pavlin Radoslavov018d5332014-02-19 23:08:35 -0800221 }
222 if (portEvent != null) {
223 ByteBuffer id = ByteBuffer.wrap(portEvent.getID());
224 addedPortEvents.put(id, portEvent);
225 removedPortEvents.remove(id);
Pavlin Radoslavov706add22014-02-20 12:15:59 -0800226 reorderedAddedPortEvents.remove(id);
Pavlin Radoslavov018d5332014-02-19 23:08:35 -0800227 }
228 if (linkEvent != null) {
229 ByteBuffer id = ByteBuffer.wrap(linkEvent.getID());
230 addedLinkEvents.put(id, linkEvent);
231 removedLinkEvents.remove(id);
Pavlin Radoslavov706add22014-02-20 12:15:59 -0800232 reorderedAddedLinkEvents.remove(id);
Pavlin Radoslavov018d5332014-02-19 23:08:35 -0800233 }
234 if (deviceEvent != null) {
235 ByteBuffer id = ByteBuffer.wrap(deviceEvent.getID());
236 addedDeviceEvents.put(id, deviceEvent);
237 removedDeviceEvents.remove(id);
Pavlin Radoslavov706add22014-02-20 12:15:59 -0800238 reorderedAddedDeviceEvents.remove(id);
Pavlin Radoslavov018d5332014-02-19 23:08:35 -0800239 }
Pavlin Radoslavov721a2e02014-02-14 23:40:14 -0800240 break;
241 case ENTRY_REMOVE:
242 log.debug("Topology event ENTRY_REMOVE: {}", topologyEvent);
Pavlin Radoslavov018d5332014-02-19 23:08:35 -0800243 if (switchEvent != null) {
244 ByteBuffer id = ByteBuffer.wrap(switchEvent.getID());
245 addedSwitchEvents.remove(id);
246 removedSwitchEvents.put(id, switchEvent);
Pavlin Radoslavov706add22014-02-20 12:15:59 -0800247 // Switch Events are not affected by event reordering
Pavlin Radoslavov018d5332014-02-19 23:08:35 -0800248 }
249 if (portEvent != null) {
250 ByteBuffer id = ByteBuffer.wrap(portEvent.getID());
251 addedPortEvents.remove(id);
252 removedPortEvents.put(id, portEvent);
Pavlin Radoslavov706add22014-02-20 12:15:59 -0800253 reorderedAddedPortEvents.remove(id);
Pavlin Radoslavov018d5332014-02-19 23:08:35 -0800254 }
255 if (linkEvent != null) {
256 ByteBuffer id = ByteBuffer.wrap(linkEvent.getID());
257 addedLinkEvents.remove(id);
258 removedLinkEvents.put(id, linkEvent);
Pavlin Radoslavov706add22014-02-20 12:15:59 -0800259 reorderedAddedLinkEvents.remove(id);
Pavlin Radoslavov018d5332014-02-19 23:08:35 -0800260 }
261 if (deviceEvent != null) {
262 ByteBuffer id = ByteBuffer.wrap(deviceEvent.getID());
263 addedDeviceEvents.remove(id);
264 removedDeviceEvents.put(id, deviceEvent);
Pavlin Radoslavov706add22014-02-20 12:15:59 -0800265 reorderedAddedDeviceEvents.remove(id);
Pavlin Radoslavov018d5332014-02-19 23:08:35 -0800266 }
Pavlin Radoslavov721a2e02014-02-14 23:40:14 -0800267 break;
268 }
269 }
Pavlin Radoslavov3c9cc552014-02-20 09:58:38 -0800270
271 //
Pavlin Radoslavov8ffb8bf2014-02-20 15:34:26 -0800272 // Lock the Network Graph while it is modified
273 //
274 networkGraph.acquireWriteLock();
275
Jonathan Hart26241692014-02-20 16:31:11 -0800276 try {
277 //
278 // Apply the classified events.
279 //
280 // Apply the "add" events in the proper order:
281 // switch, port, link, device
282 //
283 for (SwitchEvent switchEvent : addedSwitchEvents.values())
284 addSwitch(switchEvent);
285 for (PortEvent portEvent : addedPortEvents.values())
286 addPort(portEvent);
287 for (LinkEvent linkEvent : addedLinkEvents.values())
288 addLink(linkEvent);
289 for (DeviceEvent deviceEvent : addedDeviceEvents.values())
290 addDevice(deviceEvent);
291 //
292 // Apply the "remove" events in the reverse order:
293 // device, link, port, switch
294 //
295 for (DeviceEvent deviceEvent : removedDeviceEvents.values())
296 removeDevice(deviceEvent);
297 for (LinkEvent linkEvent : removedLinkEvents.values())
298 removeLink(linkEvent);
299 for (PortEvent portEvent : removedPortEvents.values())
300 removePort(portEvent);
301 for (SwitchEvent switchEvent : removedSwitchEvents.values())
302 removeSwitch(switchEvent);
303
304 //
305 // Apply reordered events
306 //
307 applyReorderedEvents(! addedSwitchEvents.isEmpty(),
308 ! addedPortEvents.isEmpty());
309
310 }
311 finally {
312 //
313 // Network Graph modifications completed: Release the lock
314 //
315 networkGraph.releaseWriteLock();
316 }
317
Pavlin Radoslavov8ffb8bf2014-02-20 15:34:26 -0800318 //
Pavlin Radoslavov74986ce2014-02-20 13:17:20 -0800319 // Dispatch the Topology Notification Events to the applications
320 //
321 dispatchNetworkGraphEvents();
Pavlin Radoslavov721a2e02014-02-14 23:40:14 -0800322 }
323
324 /**
325 * Receive a notification that an entry is added.
326 *
327 * @param value the value for the entry.
328 */
329 @Override
330 public void entryAdded(TopologyEvent value) {
331 EventEntry<TopologyEvent> eventEntry =
332 new EventEntry<TopologyEvent>(EventEntry.Type.ENTRY_ADD,
333 value);
334 topologyEvents.add(eventEntry);
335 }
336
337 /**
338 * Receive a notification that an entry is removed.
339 *
340 * @param value the value for the entry.
341 */
342 @Override
343 public void entryRemoved(TopologyEvent value) {
344 EventEntry<TopologyEvent> eventEntry =
345 new EventEntry<TopologyEvent>(EventEntry.Type.ENTRY_REMOVE,
346 value);
347 topologyEvents.add(eventEntry);
348 }
349
350 /**
351 * Receive a notification that an entry is updated.
352 *
353 * @param value the value for the entry.
354 */
355 @Override
356 public void entryUpdated(TopologyEvent value) {
357 // NOTE: The ADD and UPDATE events are processed in same way
358 entryAdded(value);
359 }
360 }
361
362 /**
363 * Startup processing.
364 *
365 * @param datagridService the datagrid service to use.
366 */
367 void startup(IDatagridService datagridService) {
368 eventChannel = datagridService.addListener(EVENT_CHANNEL_NAME,
369 eventHandler,
370 byte[].class,
371 TopologyEvent.class);
372 eventHandler.start();
373 }
374
Pavlin Radoslavov74986ce2014-02-20 13:17:20 -0800375 /**
376 * Dispatch Network Graph Events to the listeners.
377 */
378 private void dispatchNetworkGraphEvents() {
379 if (apiAddedSwitchEvents.isEmpty() &&
380 apiRemovedSwitchEvents.isEmpty() &&
381 apiAddedPortEvents.isEmpty() &&
382 apiRemovedPortEvents.isEmpty() &&
383 apiAddedLinkEvents.isEmpty() &&
384 apiRemovedLinkEvents.isEmpty() &&
385 apiAddedDeviceEvents.isEmpty() &&
386 apiRemovedDeviceEvents.isEmpty()) {
387 return; // No events to dispatch
388 }
389
390 // Deliver the events
391 for (INetworkGraphListener listener : this.networkGraphListeners) {
392 // TODO: Should copy before handing them over to listener?
393 listener.networkGraphEvents(apiAddedSwitchEvents,
394 apiRemovedSwitchEvents,
395 apiAddedPortEvents,
396 apiRemovedPortEvents,
397 apiAddedLinkEvents,
398 apiRemovedLinkEvents,
399 apiAddedDeviceEvents,
400 apiRemovedDeviceEvents);
401 }
402
403 //
404 // Cleanup
405 //
406 apiAddedSwitchEvents.clear();
407 apiRemovedSwitchEvents.clear();
408 apiAddedPortEvents.clear();
409 apiRemovedPortEvents.clear();
410 apiAddedLinkEvents.clear();
411 apiRemovedLinkEvents.clear();
412 apiAddedDeviceEvents.clear();
413 apiRemovedDeviceEvents.clear();
414 }
415
416 /**
417 * Apply reordered events.
418 *
419 * @param hasAddedSwitchEvents true if there were Added Switch Events.
420 * @param hasAddedPortEvents true if there were Added Port Events.
421 */
422 private void applyReorderedEvents(boolean hasAddedSwitchEvents,
423 boolean hasAddedPortEvents) {
424 if (! (hasAddedSwitchEvents || hasAddedPortEvents))
425 return; // Nothing to do
426
427 //
428 // Try to apply the reordered events.
429 //
430 // NOTE: For simplicity we try to apply all events of a particular
431 // type if any "parent" type event was processed:
432 // - Apply reordered Port Events if Switches were added
433 // - Apply reordered Link and Device Events if Switches or Ports
434 // were added
435 //
436 Map<ByteBuffer, PortEvent> portEvents = reorderedAddedPortEvents;
437 Map<ByteBuffer, LinkEvent> linkEvents = reorderedAddedLinkEvents;
438 Map<ByteBuffer, DeviceEvent> deviceEvents = reorderedAddedDeviceEvents;
439 reorderedAddedPortEvents = new HashMap<>();
440 reorderedAddedLinkEvents = new HashMap<>();
441 reorderedAddedDeviceEvents = new HashMap<>();
442 //
443 // Apply reordered Port Events if Switches were added
444 //
445 if (hasAddedSwitchEvents) {
446 for (PortEvent portEvent : portEvents.values())
447 addPort(portEvent);
448 }
449 //
450 // Apply reordered Link and Device Events if Switches or Ports
451 // were added.
452 //
453 for (LinkEvent linkEvent : linkEvents.values())
454 addLink(linkEvent);
455 for (DeviceEvent deviceEvent : deviceEvents.values())
456 addDevice(deviceEvent);
457 }
458
Jonathan Hart22eb9882014-02-11 15:52:59 -0800459 /* ******************************
460 * NetworkGraphDiscoveryInterface methods
461 * ******************************/
Yuta HIGUCHIcd922f42014-02-11 18:59:11 -0800462
Pavlin Radoslavovc1cfde52014-02-19 11:35:29 -0800463 @Override
Pavlin Radoslavov018d5332014-02-19 23:08:35 -0800464 public void putSwitchDiscoveryEvent(SwitchEvent switchEvent,
465 Collection<PortEvent> portEvents) {
466 if (datastore.addSwitch(switchEvent, portEvents)) {
Pavlin Radoslavovc1cfde52014-02-19 11:35:29 -0800467 // Send out notification
Pavlin Radoslavov87dcc262014-02-19 21:13:23 -0800468 TopologyEvent topologyEvent = new TopologyEvent(switchEvent);
Pavlin Radoslavovc1cfde52014-02-19 11:35:29 -0800469 eventChannel.addEntry(topologyEvent.getID(), topologyEvent);
Pavlin Radoslavov018d5332014-02-19 23:08:35 -0800470
Pavlin Radoslavov26d83402014-02-20 15:24:30 -0800471 // Send out notification for each port
Pavlin Radoslavov018d5332014-02-19 23:08:35 -0800472 for (PortEvent portEvent : portEvents) {
473 topologyEvent = new TopologyEvent(portEvent);
474 eventChannel.addEntry(topologyEvent.getID(), topologyEvent);
475 }
Pavlin Radoslavov26d83402014-02-20 15:24:30 -0800476
477 //
478 // Keep track of the added ports
479 //
480 // Get the old Port Events
481 Map<ByteBuffer, PortEvent> oldPortEvents =
482 discoveredAddedPortEvents.get(switchEvent.getDpid());
483 if (oldPortEvents == null)
484 oldPortEvents = new HashMap<>();
485
486 // Store the new Port Events in the local cache
487 Map<ByteBuffer, PortEvent> newPortEvents = new HashMap<>();
488 for (PortEvent portEvent : portEvents) {
489 ByteBuffer id = ByteBuffer.wrap(portEvent.getID());
490 newPortEvents.put(id, portEvent);
491 }
492 discoveredAddedPortEvents.put(switchEvent.getDpid(),
493 newPortEvents);
494
495 //
496 // Extract the removed ports
497 //
498 List<PortEvent> removedPortEvents = new LinkedList<>();
499 for (Map.Entry<ByteBuffer, PortEvent> entry : oldPortEvents.entrySet()) {
500 ByteBuffer key = entry.getKey();
501 PortEvent portEvent = entry.getValue();
502 if (! newPortEvents.containsKey(key))
503 removedPortEvents.add(portEvent);
504 }
505
506 // Cleanup old removed ports
507 for (PortEvent portEvent : removedPortEvents)
508 removePortDiscoveryEvent(portEvent);
Pavlin Radoslavovc1cfde52014-02-19 11:35:29 -0800509 }
Pavlin Radoslavovc1cfde52014-02-19 11:35:29 -0800510 }
511
512 @Override
Pavlin Radoslavov6ea84a42014-02-19 15:50:01 -0800513 public void removeSwitchDiscoveryEvent(SwitchEvent switchEvent) {
Pavlin Radoslavov26d83402014-02-20 15:24:30 -0800514 // Get the old Port Events
515 Map<ByteBuffer, PortEvent> oldPortEvents =
516 discoveredAddedPortEvents.get(switchEvent.getDpid());
517 if (oldPortEvents == null)
518 oldPortEvents = new HashMap<>();
Pavlin Radoslavov018d5332014-02-19 23:08:35 -0800519
Pavlin Radoslavov26d83402014-02-20 15:24:30 -0800520 if (datastore.deactivateSwitch(switchEvent, oldPortEvents.values())) {
Pavlin Radoslavovc1cfde52014-02-19 11:35:29 -0800521 // Send out notification
522 eventChannel.removeEntry(switchEvent.getID());
Pavlin Radoslavov018d5332014-02-19 23:08:35 -0800523
Pavlin Radoslavov26d83402014-02-20 15:24:30 -0800524 // Send out notification for each port
525 for (PortEvent portEvent : oldPortEvents.values())
Pavlin Radoslavov018d5332014-02-19 23:08:35 -0800526 eventChannel.removeEntry(portEvent.getID());
Pavlin Radoslavov26d83402014-02-20 15:24:30 -0800527 discoveredAddedPortEvents.remove(switchEvent.getDpid());
528
529 // Cleanup for each link
530 Map<ByteBuffer, LinkEvent> oldLinkEvents =
531 discoveredAddedLinkEvents.get(switchEvent.getDpid());
532 if (oldLinkEvents != null) {
533 for (LinkEvent linkEvent : oldLinkEvents.values())
534 removeLinkDiscoveryEvent(linkEvent);
535 discoveredAddedLinkEvents.remove(switchEvent.getDpid());
536 }
537
538 // Cleanup for each device
539 Map<ByteBuffer, DeviceEvent> oldDeviceEvents =
540 discoveredAddedDeviceEvents.get(switchEvent.getDpid());
541 if (oldDeviceEvents != null) {
542 for (DeviceEvent deviceEvent : oldDeviceEvents.values())
543 removeDeviceDiscoveryEvent(deviceEvent);
544 discoveredAddedDeviceEvents.remove(switchEvent.getDpid());
Pavlin Radoslavov018d5332014-02-19 23:08:35 -0800545 }
Pavlin Radoslavovc1cfde52014-02-19 11:35:29 -0800546 }
Pavlin Radoslavovc1cfde52014-02-19 11:35:29 -0800547 }
548
549 @Override
Pavlin Radoslavov6ea84a42014-02-19 15:50:01 -0800550 public void putPortDiscoveryEvent(PortEvent portEvent) {
Pavlin Radoslavov50cd1482014-02-19 16:57:03 -0800551 if (datastore.addPort(portEvent)) {
Pavlin Radoslavovc1cfde52014-02-19 11:35:29 -0800552 // Send out notification
Pavlin Radoslavov87dcc262014-02-19 21:13:23 -0800553 TopologyEvent topologyEvent = new TopologyEvent(portEvent);
Pavlin Radoslavov018d5332014-02-19 23:08:35 -0800554 eventChannel.addEntry(topologyEvent.getID(), topologyEvent);
Pavlin Radoslavov26d83402014-02-20 15:24:30 -0800555
556 // Store the new Port Event in the local cache
557 Map<ByteBuffer, PortEvent> oldPortEvents =
558 discoveredAddedPortEvents.get(portEvent.getDpid());
559 if (oldPortEvents == null) {
560 oldPortEvents = new HashMap<>();
561 discoveredAddedPortEvents.put(portEvent.getDpid(),
562 oldPortEvents);
563 }
564 ByteBuffer id = ByteBuffer.wrap(portEvent.getID());
565 oldPortEvents.put(id, portEvent);
Pavlin Radoslavovc1cfde52014-02-19 11:35:29 -0800566 }
Pavlin Radoslavovc1cfde52014-02-19 11:35:29 -0800567 }
568
569 @Override
Pavlin Radoslavov6ea84a42014-02-19 15:50:01 -0800570 public void removePortDiscoveryEvent(PortEvent portEvent) {
Pavlin Radoslavov50cd1482014-02-19 16:57:03 -0800571 if (datastore.deactivatePort(portEvent)) {
Pavlin Radoslavovc1cfde52014-02-19 11:35:29 -0800572 // Send out notification
573 eventChannel.removeEntry(portEvent.getID());
Pavlin Radoslavov26d83402014-02-20 15:24:30 -0800574
575 // Cleanup the Port Event from the local cache
576 Map<ByteBuffer, PortEvent> oldPortEvents =
577 discoveredAddedPortEvents.get(portEvent.getDpid());
578 if (oldPortEvents != null) {
579 ByteBuffer id = ByteBuffer.wrap(portEvent.getID());
580 oldPortEvents.remove(id);
581 }
582
583 // Cleanup for the incoming link
584 Map<ByteBuffer, LinkEvent> oldLinkEvents =
585 discoveredAddedLinkEvents.get(portEvent.getDpid());
586 if (oldLinkEvents != null) {
587 for (LinkEvent linkEvent : oldLinkEvents.values()) {
588 if (linkEvent.getDst().equals(portEvent.id)) {
589 removeLinkDiscoveryEvent(linkEvent);
590 //
591 // NOTE: oldLinkEvents was modified by
592 // removeLinkDiscoveryEvent() and cannot be iterated
593 // anymore.
594 //
595 break;
596 }
597 }
598 }
599
600 // Cleanup for the connected devices
601 // TODO: The implementation below is probably wrong
602 List<DeviceEvent> removedDeviceEvents = new LinkedList<>();
603 Map<ByteBuffer, DeviceEvent> oldDeviceEvents =
604 discoveredAddedDeviceEvents.get(portEvent.getDpid());
605 if (oldDeviceEvents != null) {
606 for (DeviceEvent deviceEvent : oldDeviceEvents.values()) {
607 for (SwitchPort swp : deviceEvent.getAttachmentPoints()) {
608 if (swp.equals(portEvent.id)) {
609 removedDeviceEvents.add(deviceEvent);
610 break;
611 }
612 }
613 }
614 for (DeviceEvent deviceEvent : removedDeviceEvents)
615 removeDeviceDiscoveryEvent(deviceEvent);
616 }
Pavlin Radoslavovc1cfde52014-02-19 11:35:29 -0800617 }
Pavlin Radoslavovc1cfde52014-02-19 11:35:29 -0800618 }
619
620 @Override
Pavlin Radoslavov6ea84a42014-02-19 15:50:01 -0800621 public void putLinkDiscoveryEvent(LinkEvent linkEvent) {
Pavlin Radoslavov50cd1482014-02-19 16:57:03 -0800622 if (datastore.addLink(linkEvent)) {
Pavlin Radoslavovc1cfde52014-02-19 11:35:29 -0800623 // Send out notification
Pavlin Radoslavov87dcc262014-02-19 21:13:23 -0800624 TopologyEvent topologyEvent = new TopologyEvent(linkEvent);
Pavlin Radoslavovc1cfde52014-02-19 11:35:29 -0800625 eventChannel.addEntry(topologyEvent.getID(), topologyEvent);
Pavlin Radoslavov26d83402014-02-20 15:24:30 -0800626
627 // Store the new Link Event in the local cache
628 Map<ByteBuffer, LinkEvent> oldLinkEvents =
629 discoveredAddedLinkEvents.get(linkEvent.getDst().getDpid());
630 if (oldLinkEvents == null) {
631 oldLinkEvents = new HashMap<>();
632 discoveredAddedLinkEvents.put(linkEvent.getDst().getDpid(),
633 oldLinkEvents);
634 }
635 ByteBuffer id = ByteBuffer.wrap(linkEvent.getID());
636 oldLinkEvents.put(id, linkEvent);
Pavlin Radoslavovc1cfde52014-02-19 11:35:29 -0800637 }
Pavlin Radoslavovc1cfde52014-02-19 11:35:29 -0800638 }
639
640 @Override
Pavlin Radoslavov6ea84a42014-02-19 15:50:01 -0800641 public void removeLinkDiscoveryEvent(LinkEvent linkEvent) {
Pavlin Radoslavov50cd1482014-02-19 16:57:03 -0800642 if (datastore.removeLink(linkEvent)) {
Pavlin Radoslavovc1cfde52014-02-19 11:35:29 -0800643 // Send out notification
644 eventChannel.removeEntry(linkEvent.getID());
Pavlin Radoslavov26d83402014-02-20 15:24:30 -0800645
646 // Cleanup the Link Event from the local cache
647 Map<ByteBuffer, LinkEvent> oldLinkEvents =
648 discoveredAddedLinkEvents.get(linkEvent.getDst().getDpid());
649 if (oldLinkEvents != null) {
650 ByteBuffer id = ByteBuffer.wrap(linkEvent.getID());
651 oldLinkEvents.remove(id);
652 }
Jonathan Hart22eb9882014-02-11 15:52:59 -0800653 }
Pavlin Radoslavovc1cfde52014-02-19 11:35:29 -0800654 }
Jonathan Hart22eb9882014-02-11 15:52:59 -0800655
Pavlin Radoslavovc1cfde52014-02-19 11:35:29 -0800656 @Override
Pavlin Radoslavov6ea84a42014-02-19 15:50:01 -0800657 public void putDeviceDiscoveryEvent(DeviceEvent deviceEvent) {
Pavlin Radoslavov50cd1482014-02-19 16:57:03 -0800658 if (datastore.addDevice(deviceEvent)) {
Pavlin Radoslavovc1cfde52014-02-19 11:35:29 -0800659 // Send out notification
Pavlin Radoslavov87dcc262014-02-19 21:13:23 -0800660 TopologyEvent topologyEvent = new TopologyEvent(deviceEvent);
Pavlin Radoslavov50cd1482014-02-19 16:57:03 -0800661 eventChannel.addEntry(topologyEvent.getID(), topologyEvent);
Pavlin Radoslavov26d83402014-02-20 15:24:30 -0800662
663 // Store the new Device Event in the local cache
664 // TODO: The implementation below is probably wrong
665 for (SwitchPort swp : deviceEvent.getAttachmentPoints()) {
666 Map<ByteBuffer, DeviceEvent> oldDeviceEvents =
667 discoveredAddedDeviceEvents.get(swp.getDpid());
668 if (oldDeviceEvents == null) {
669 oldDeviceEvents = new HashMap<>();
670 discoveredAddedDeviceEvents.put(swp.getDpid(),
671 oldDeviceEvents);
672 }
673 ByteBuffer id = ByteBuffer.wrap(deviceEvent.getID());
674 oldDeviceEvents.put(id, deviceEvent);
675 }
Jonathan Hart22eb9882014-02-11 15:52:59 -0800676 }
Pavlin Radoslavovc1cfde52014-02-19 11:35:29 -0800677 }
Jonathan Hart22eb9882014-02-11 15:52:59 -0800678
Pavlin Radoslavovc1cfde52014-02-19 11:35:29 -0800679 @Override
Pavlin Radoslavov6ea84a42014-02-19 15:50:01 -0800680 public void removeDeviceDiscoveryEvent(DeviceEvent deviceEvent) {
Pavlin Radoslavov50cd1482014-02-19 16:57:03 -0800681 if (datastore.removeDevice(deviceEvent)) {
Pavlin Radoslavovc1cfde52014-02-19 11:35:29 -0800682 // Send out notification
683 eventChannel.removeEntry(deviceEvent.getID());
Pavlin Radoslavov26d83402014-02-20 15:24:30 -0800684
685 // Cleanup the Device Event from the local cache
686 // TODO: The implementation below is probably wrong
687 ByteBuffer id = ByteBuffer.wrap(deviceEvent.getID());
688 for (SwitchPort swp : deviceEvent.getAttachmentPoints()) {
689 Map<ByteBuffer, DeviceEvent> oldDeviceEvents =
690 discoveredAddedDeviceEvents.get(swp.getDpid());
691 if (oldDeviceEvents != null) {
692 oldDeviceEvents.remove(id);
693 }
694 }
Jonathan Hart22eb9882014-02-11 15:52:59 -0800695 }
Pavlin Radoslavovc1cfde52014-02-19 11:35:29 -0800696 }
Jonathan Hart22eb9882014-02-11 15:52:59 -0800697
Pavlin Radoslavov3c9cc552014-02-20 09:58:38 -0800698 /* ************************************************
699 * Internal methods to maintain the network graph
700 * ************************************************/
Pavlin Radoslavov74986ce2014-02-20 13:17:20 -0800701 private void addSwitch(SwitchEvent switchEvent) {
702 Switch sw = networkGraph.getSwitch(switchEvent.getDpid());
Pavlin Radoslavov3c9cc552014-02-20 09:58:38 -0800703 if (sw == null) {
Pavlin Radoslavov74986ce2014-02-20 13:17:20 -0800704 sw = new SwitchImpl(networkGraph, switchEvent.getDpid());
Pavlin Radoslavov3c9cc552014-02-20 09:58:38 -0800705 networkGraph.putSwitch(sw);
706 } else {
707 // TODO: Update the switch attributes
708 // TODO: Nothing to do for now
709 }
Pavlin Radoslavov74986ce2014-02-20 13:17:20 -0800710 apiAddedSwitchEvents.add(switchEvent);
Pavlin Radoslavov3c9cc552014-02-20 09:58:38 -0800711 }
712
Pavlin Radoslavov74986ce2014-02-20 13:17:20 -0800713 private void removeSwitch(SwitchEvent switchEvent) {
714 Switch sw = networkGraph.getSwitch(switchEvent.getDpid());
Pavlin Radoslavov3c9cc552014-02-20 09:58:38 -0800715 if (sw == null) {
Pavlin Radoslavov74986ce2014-02-20 13:17:20 -0800716 log.warn("Switch {} already removed, ignoring", switchEvent);
Pavlin Radoslavov3c9cc552014-02-20 09:58:38 -0800717 return;
718 }
719
720 //
721 // Remove all Ports on the Switch
722 //
723 ArrayList<PortEvent> portsToRemove = new ArrayList<>();
724 for (Port port : sw.getPorts()) {
725 log.warn("Port {} on Switch {} should be removed prior to removing Switch. Removing Port now.",
Pavlin Radoslavov74986ce2014-02-20 13:17:20 -0800726 port, switchEvent);
Pavlin Radoslavov3c9cc552014-02-20 09:58:38 -0800727 PortEvent portEvent = new PortEvent(port.getDpid(),
728 port.getNumber());
729 portsToRemove.add(portEvent);
730 }
731 for (PortEvent portEvent : portsToRemove)
732 removePort(portEvent);
733
Pavlin Radoslavov74986ce2014-02-20 13:17:20 -0800734 networkGraph.removeSwitch(switchEvent.getDpid());
735 apiRemovedSwitchEvents.add(switchEvent);
Pavlin Radoslavov3c9cc552014-02-20 09:58:38 -0800736 }
737
738 private void addPort(PortEvent portEvent) {
739 Switch sw = networkGraph.getSwitch(portEvent.getDpid());
740 if (sw == null) {
Pavlin Radoslavov706add22014-02-20 12:15:59 -0800741 // Reordered event: delay the event in local cache
742 ByteBuffer id = ByteBuffer.wrap(portEvent.getID());
743 reorderedAddedPortEvents.put(id, portEvent);
Pavlin Radoslavov3c9cc552014-02-20 09:58:38 -0800744 return;
745 }
746 SwitchImpl switchImpl = getSwitchImpl(sw);
747
748 Port port = sw.getPort(portEvent.getNumber());
749 if (port == null) {
750 port = new PortImpl(networkGraph, sw, portEvent.getNumber());
751 switchImpl.addPort(port);
752 } else {
753 // TODO: Update the port attributes
754 }
Pavlin Radoslavov74986ce2014-02-20 13:17:20 -0800755 apiAddedPortEvents.add(portEvent);
Pavlin Radoslavov3c9cc552014-02-20 09:58:38 -0800756 }
757
758 private void removePort(PortEvent portEvent) {
759 Switch sw = networkGraph.getSwitch(portEvent.getDpid());
760 if (sw == null) {
761 log.warn("Parent Switch for Port {} already removed, ignoring",
762 portEvent);
763 return;
764 }
765
766 Port port = sw.getPort(portEvent.getNumber());
767 if (port == null) {
768 log.warn("Port {} already removed, ignoring", portEvent);
769 return;
770 }
771
772 //
773 // Remove all Devices attached to the Port
774 //
775 ArrayList<DeviceEvent> devicesToRemove = new ArrayList<>();
776 for (Device device : port.getDevices()) {
777 log.debug("Removing Device {} on Port {}", device, portEvent);
778 DeviceEvent deviceEvent = new DeviceEvent(device.getMacAddress());
779 SwitchPort switchPort = new SwitchPort(port.getSwitch().getDpid(),
780 port.getNumber());
781 deviceEvent.addAttachmentPoint(switchPort);
782 devicesToRemove.add(deviceEvent);
783 }
784 for (DeviceEvent deviceEvent : devicesToRemove)
785 removeDevice(deviceEvent);
786
787 //
788 // Remove all Links connected to the Port
789 //
790 Set<Link> links = new HashSet<>();
791 links.add(port.getOutgoingLink());
792 links.add(port.getIncomingLink());
793 ArrayList<LinkEvent> linksToRemove = new ArrayList<>();
794 for (Link link : links) {
795 if (link == null)
796 continue;
797 log.debug("Removing Link {} on Port {}", link, portEvent);
798 LinkEvent linkEvent = new LinkEvent(link.getSrcSwitch().getDpid(),
799 link.getSrcPort().getNumber(),
800 link.getDstSwitch().getDpid(),
801 link.getDstPort().getNumber());
802 linksToRemove.add(linkEvent);
803 }
804 for (LinkEvent linkEvent : linksToRemove)
805 removeLink(linkEvent);
806
807 // Remove the Port from the Switch
808 SwitchImpl switchImpl = getSwitchImpl(sw);
809 switchImpl.removePort(port);
Pavlin Radoslavov74986ce2014-02-20 13:17:20 -0800810
811 apiRemovedPortEvents.add(portEvent);
Pavlin Radoslavov3c9cc552014-02-20 09:58:38 -0800812 }
813
814 private void addLink(LinkEvent linkEvent) {
815 Port srcPort = networkGraph.getPort(linkEvent.getSrc().dpid,
816 linkEvent.getSrc().number);
Pavlin Radoslavov3c9cc552014-02-20 09:58:38 -0800817 Port dstPort = networkGraph.getPort(linkEvent.getDst().dpid,
818 linkEvent.getDst().number);
Pavlin Radoslavov706add22014-02-20 12:15:59 -0800819 if ((srcPort == null) || (dstPort == null)) {
820 // Reordered event: delay the event in local cache
821 ByteBuffer id = ByteBuffer.wrap(linkEvent.getID());
822 reorderedAddedLinkEvents.put(id, linkEvent);
Pavlin Radoslavov3c9cc552014-02-20 09:58:38 -0800823 return;
824 }
825
826 // Get the Link instance from the Destination Port Incoming Link
827 Link link = dstPort.getIncomingLink();
828 assert(link == srcPort.getOutgoingLink());
829 if (link == null) {
830 link = new LinkImpl(networkGraph, srcPort, dstPort);
831 PortImpl srcPortImpl = getPortImpl(srcPort);
832 PortImpl dstPortImpl = getPortImpl(dstPort);
833 srcPortImpl.setOutgoingLink(link);
834 dstPortImpl.setIncomingLink(link);
835
836 // Remove all Devices attached to the Ports
837 ArrayList<DeviceEvent> devicesToRemove = new ArrayList<>();
838 ArrayList<Port> ports = new ArrayList<>();
839 ports.add(srcPort);
840 ports.add(dstPort);
841 for (Port port : ports) {
842 for (Device device : port.getDevices()) {
843 log.error("Device {} on Port {} should have been removed prior to adding Link {}",
844 device, port, linkEvent);
845 DeviceEvent deviceEvent =
846 new DeviceEvent(device.getMacAddress());
847 SwitchPort switchPort =
848 new SwitchPort(port.getSwitch().getDpid(),
849 port.getNumber());
850 deviceEvent.addAttachmentPoint(switchPort);
851 devicesToRemove.add(deviceEvent);
852 }
853 }
854 for (DeviceEvent deviceEvent : devicesToRemove)
855 removeDevice(deviceEvent);
856 } else {
857 // TODO: Update the link attributes
858 }
Pavlin Radoslavov74986ce2014-02-20 13:17:20 -0800859
860 apiAddedLinkEvents.add(linkEvent);
Pavlin Radoslavov3c9cc552014-02-20 09:58:38 -0800861 }
862
863 private void removeLink(LinkEvent linkEvent) {
864 Port srcPort = networkGraph.getPort(linkEvent.getSrc().dpid,
865 linkEvent.getSrc().number);
866 if (srcPort == null) {
867 log.warn("Src Port for Link {} already removed, ignoring",
868 linkEvent);
869 return;
870 }
871
872 Port dstPort = networkGraph.getPort(linkEvent.getDst().dpid,
873 linkEvent.getDst().number);
874 if (dstPort == null) {
875 log.warn("Dst Port for Link {} already removed, ignoring",
876 linkEvent);
877 return;
878 }
879
880 //
881 // Remove the Link instance from the Destination Port Incoming Link
882 // and the Source Port Outgoing Link.
883 //
884 Link link = dstPort.getIncomingLink();
885 if (link == null) {
886 log.warn("Link {} already removed on destination Port", linkEvent);
887 }
888 link = srcPort.getOutgoingLink();
889 if (link == null) {
890 log.warn("Link {} already removed on src Port", linkEvent);
891 }
892 getPortImpl(dstPort).setIncomingLink(null);
893 getPortImpl(srcPort).setOutgoingLink(null);
Pavlin Radoslavov74986ce2014-02-20 13:17:20 -0800894
895 apiRemovedLinkEvents.add(linkEvent);
Pavlin Radoslavov3c9cc552014-02-20 09:58:38 -0800896 }
897
898 // TODO: Device-related work is incomplete
899 private void addDevice(DeviceEvent deviceEvent) {
900 Device device = networkGraph.getDeviceByMac(deviceEvent.getMac());
901 if (device == null) {
902 device = new DeviceImpl(networkGraph, deviceEvent.getMac());
903 }
904 DeviceImpl deviceImpl = getDeviceImpl(device);
905
906 // Update the IP addresses
907 for (InetAddress ipAddr : deviceEvent.getIpAddresses())
908 deviceImpl.addIpAddress(ipAddr);
909
910 // Process each attachment point
911 boolean attachmentFound = false;
912 for (SwitchPort swp : deviceEvent.getAttachmentPoints()) {
913 // Attached Ports must exist
914 Port port = networkGraph.getPort(swp.dpid, swp.number);
915 if (port == null) {
Pavlin Radoslavov706add22014-02-20 12:15:59 -0800916 // Reordered event: delay the event in local cache
917 ByteBuffer id = ByteBuffer.wrap(deviceEvent.getID());
918 reorderedAddedDeviceEvents.put(id, deviceEvent);
Pavlin Radoslavov3c9cc552014-02-20 09:58:38 -0800919 continue;
920 }
921 // Attached Ports must not have Link
922 if (port.getOutgoingLink() != null ||
923 port.getIncomingLink() != null) {
924 log.warn("Link (Out:{},In:{}) exist on the attachment point, skipping mutation.",
925 port.getOutgoingLink(),
926 port.getIncomingLink());
927 continue;
928 }
929
930 // Add Device <-> Port attachment
931 PortImpl portImpl = getPortImpl(port);
932 portImpl.addDevice(device);
933 deviceImpl.addAttachmentPoint(port);
934 attachmentFound = true;
935 }
936
937 // Update the device in the Network Graph
Pavlin Radoslavov74986ce2014-02-20 13:17:20 -0800938 if (attachmentFound) {
Pavlin Radoslavov3c9cc552014-02-20 09:58:38 -0800939 networkGraph.putDevice(device);
Pavlin Radoslavov74986ce2014-02-20 13:17:20 -0800940 apiAddedDeviceEvents.add(deviceEvent);
941 }
Pavlin Radoslavov3c9cc552014-02-20 09:58:38 -0800942 }
943
944 private void removeDevice(DeviceEvent deviceEvent) {
945 Device device = networkGraph.getDeviceByMac(deviceEvent.getMac());
946 if (device == null) {
947 log.warn("Device {} already removed, ignoring", deviceEvent);
948 return;
949 }
950 DeviceImpl deviceImpl = getDeviceImpl(device);
951
952 // Process each attachment point
953 for (SwitchPort swp : deviceEvent.getAttachmentPoints()) {
954 // Attached Ports must exist
955 Port port = networkGraph.getPort(swp.dpid, swp.number);
956 if (port == null) {
957 log.warn("Port for the attachment point {} did not exist. skipping attachment point mutation", swp);
958 continue;
959 }
960
961 // Remove Device <-> Port attachment
962 PortImpl portImpl = getPortImpl(port);
963 portImpl.removeDevice(device);
964 deviceImpl.removeAttachmentPoint(port);
965 }
Pavlin Radoslavov74986ce2014-02-20 13:17:20 -0800966
Pavlin Radoslavov3c9cc552014-02-20 09:58:38 -0800967 networkGraph.removeDevice(device);
Pavlin Radoslavov74986ce2014-02-20 13:17:20 -0800968 apiRemovedDeviceEvents.add(deviceEvent);
Pavlin Radoslavov3c9cc552014-02-20 09:58:38 -0800969 }
Jonathan Hart22eb9882014-02-11 15:52:59 -0800970
Pavlin Radoslavovc1cfde52014-02-19 11:35:29 -0800971 /**
972 *
Pavlin Radoslavov74986ce2014-02-20 13:17:20 -0800973 * @param switchEvent
Pavlin Radoslavovc1cfde52014-02-19 11:35:29 -0800974 * @return true if ready to accept event.
975 */
Pavlin Radoslavov74986ce2014-02-20 13:17:20 -0800976 private boolean prepareForAddSwitchEvent(SwitchEvent switchEvent) {
Pavlin Radoslavovc1cfde52014-02-19 11:35:29 -0800977 // No show stopping precondition
Pavlin Radoslavovc1cfde52014-02-19 11:35:29 -0800978 return true;
979 }
Jonathan Hart22eb9882014-02-11 15:52:59 -0800980
Pavlin Radoslavov74986ce2014-02-20 13:17:20 -0800981 private boolean prepareForRemoveSwitchEvent(SwitchEvent switchEvent) {
Pavlin Radoslavovc1cfde52014-02-19 11:35:29 -0800982 // No show stopping precondition
Pavlin Radoslavovc1cfde52014-02-19 11:35:29 -0800983 return true;
984 }
Yuta HIGUCHI71e7a052014-02-17 22:14:15 -0800985
Pavlin Radoslavovc1cfde52014-02-19 11:35:29 -0800986 private boolean prepareForAddPortEvent(PortEvent portEvent) {
987 // Parent Switch must exist
988 if (networkGraph.getSwitch(portEvent.getDpid()) == null) {
989 log.warn("Dropping add port event because switch doesn't exist: {}",
990 portEvent);
991 return false;
992 }
993 // Prep: None
994 return true;
995 }
996
997 private boolean prepareForRemovePortEvent(PortEvent portEvent) {
998 Port port = networkGraph.getPort(portEvent.getDpid(),
999 portEvent.getNumber());
1000 if (port == null) {
1001 log.debug("Port already removed? {}", portEvent);
1002 // let it pass
1003 return true;
Jonathan Hart22eb9882014-02-11 15:52:59 -08001004 }
Yuta HIGUCHIcd922f42014-02-11 18:59:11 -08001005
Pavlin Radoslavovc1cfde52014-02-19 11:35:29 -08001006 // Prep: Remove Link and Device Attachment
1007 ArrayList<DeviceEvent> deviceEvents = new ArrayList<>();
1008 for (Device device : port.getDevices()) {
1009 log.debug("Removing Device {} on Port {}", device, portEvent);
1010 DeviceEvent devEvent = new DeviceEvent(device.getMacAddress());
1011 devEvent.addAttachmentPoint(new SwitchPort(port.getSwitch().getDpid(),
1012 port.getNumber()));
1013 deviceEvents.add(devEvent);
1014 }
1015 for (DeviceEvent devEvent : deviceEvents) {
1016 // calling Discovery API to wipe from DB, etc.
Pavlin Radoslavov6ea84a42014-02-19 15:50:01 -08001017 removeDeviceDiscoveryEvent(devEvent);
Jonathan Hart22eb9882014-02-11 15:52:59 -08001018 }
Yuta HIGUCHIcd922f42014-02-11 18:59:11 -08001019
Pavlin Radoslavovc1cfde52014-02-19 11:35:29 -08001020 Set<Link> links = new HashSet<>();
1021 links.add(port.getOutgoingLink());
1022 links.add(port.getIncomingLink());
1023 for (Link link : links) {
1024 if (link == null) {
1025 continue;
1026 }
1027 log.debug("Removing Link {} on Port {}", link, portEvent);
1028 LinkEvent linkEvent =
Pavlin Radoslavov7c8f69a2014-02-19 19:01:45 -08001029 new LinkEvent(link.getSrcSwitch().getDpid(),
1030 link.getSrcPort().getNumber(),
1031 link.getDstSwitch().getDpid(),
1032 link.getDstPort().getNumber());
Pavlin Radoslavovc1cfde52014-02-19 11:35:29 -08001033 // calling Discovery API to wipe from DB, etc.
Yuta HIGUCHI8d762e92014-02-12 14:10:25 -08001034
Pavlin Radoslavovc1cfde52014-02-19 11:35:29 -08001035 // Call internal remove Link, which will check
1036 // ownership of DST dpid and modify DB only if it is the owner
Pavlin Radoslavov6ea84a42014-02-19 15:50:01 -08001037 removeLinkDiscoveryEvent(linkEvent, true);
Jonathan Hart22eb9882014-02-11 15:52:59 -08001038 }
Pavlin Radoslavovc1cfde52014-02-19 11:35:29 -08001039 return true;
1040 }
Yuta HIGUCHIcd922f42014-02-11 18:59:11 -08001041
Pavlin Radoslavovc1cfde52014-02-19 11:35:29 -08001042 private boolean prepareForAddLinkEvent(LinkEvent linkEvent) {
1043 // Src/Dst Port must exist
1044 Port srcPort = networkGraph.getPort(linkEvent.getSrc().dpid,
1045 linkEvent.getSrc().number);
1046 Port dstPort = networkGraph.getPort(linkEvent.getDst().dpid,
1047 linkEvent.getDst().number);
1048 if (srcPort == null || dstPort == null) {
Jonathan Hart0a4846e2014-02-18 11:03:40 -08001049 log.warn("Dropping add link event because port doesn't exist: {}",
Pavlin Radoslavovc1cfde52014-02-19 11:35:29 -08001050 linkEvent);
1051 return false;
Jonathan Hart22eb9882014-02-11 15:52:59 -08001052 }
Yuta HIGUCHIcd922f42014-02-11 18:59:11 -08001053
Pavlin Radoslavovc1cfde52014-02-19 11:35:29 -08001054 // Prep: remove Device attachment on both Ports
1055 ArrayList<DeviceEvent> deviceEvents = new ArrayList<>();
1056 for (Device device : srcPort.getDevices()) {
1057 DeviceEvent devEvent = new DeviceEvent(device.getMacAddress());
1058 devEvent.addAttachmentPoint(new SwitchPort(srcPort.getSwitch().getDpid(), srcPort.getNumber()));
1059 deviceEvents.add(devEvent);
1060 }
1061 for (Device device : dstPort.getDevices()) {
1062 DeviceEvent devEvent = new DeviceEvent(device.getMacAddress());
1063 devEvent.addAttachmentPoint(new SwitchPort(dstPort.getSwitch().getDpid(),
1064 dstPort.getNumber()));
1065 deviceEvents.add(devEvent);
1066 }
1067 for (DeviceEvent devEvent : deviceEvents) {
1068 // calling Discovery API to wipe from DB, etc.
Pavlin Radoslavov6ea84a42014-02-19 15:50:01 -08001069 removeDeviceDiscoveryEvent(devEvent);
Jonathan Hart22eb9882014-02-11 15:52:59 -08001070 }
Yuta HIGUCHIcd922f42014-02-11 18:59:11 -08001071
Pavlin Radoslavovc1cfde52014-02-19 11:35:29 -08001072 return true;
1073 }
Yuta HIGUCHId02e9282014-02-12 09:24:41 -08001074
Pavlin Radoslavovc1cfde52014-02-19 11:35:29 -08001075 private boolean prepareForRemoveLinkEvent(LinkEvent linkEvent) {
1076 // Src/Dst Port must exist
1077 Port srcPort = networkGraph.getPort(linkEvent.getSrc().dpid,
1078 linkEvent.getSrc().number);
1079 Port dstPort = networkGraph.getPort(linkEvent.getDst().dpid,
1080 linkEvent.getDst().number);
1081 if (srcPort == null || dstPort == null) {
1082 log.warn("Dropping remove link event because port doesn't exist {}", linkEvent);
1083 return false;
1084 }
Yuta HIGUCHI8d762e92014-02-12 14:10:25 -08001085
Pavlin Radoslavovc1cfde52014-02-19 11:35:29 -08001086 Link link = srcPort.getOutgoingLink();
1087
1088 // Link is already gone, or different Link exist in memory
1089 // XXX Check if we should reject or just accept these cases.
1090 // it should be harmless to remove the Link on event from DB anyways
1091 if (link == null ||
Pavlin Radoslavov7c8f69a2014-02-19 19:01:45 -08001092 !link.getDstPort().getNumber().equals(linkEvent.getDst().number)
1093 || !link.getDstSwitch().getDpid().equals(linkEvent.getDst().dpid)) {
Pavlin Radoslavovc1cfde52014-02-19 11:35:29 -08001094 log.warn("Dropping remove link event because link doesn't exist: {}", linkEvent);
1095 return false;
1096 }
1097 // Prep: None
1098 return true;
1099 }
1100
1101 /**
1102 *
1103 * @param deviceEvent Event will be modified to remove inapplicable attachemntPoints/ipAddress
1104 * @return false if this event should be dropped.
1105 */
1106 private boolean prepareForAddDeviceEvent(DeviceEvent deviceEvent) {
1107 boolean preconditionBroken = false;
1108 ArrayList<PortEvent.SwitchPort> failedSwitchPort = new ArrayList<>();
1109 for ( PortEvent.SwitchPort swp : deviceEvent.getAttachmentPoints() ) {
1110 // Attached Ports must exist
1111 Port port = networkGraph.getPort(swp.dpid, swp.number);
1112 if (port == null) {
1113 preconditionBroken = true;
1114 failedSwitchPort.add(swp);
1115 continue;
Yuta HIGUCHI8d762e92014-02-12 14:10:25 -08001116 }
Pavlin Radoslavovc1cfde52014-02-19 11:35:29 -08001117 // Attached Ports must not have Link
1118 if (port.getOutgoingLink() != null ||
1119 port.getIncomingLink() != null) {
1120 preconditionBroken = true;
1121 failedSwitchPort.add(swp);
1122 continue;
1123 }
1124 }
1125
1126 // Rewriting event to exclude failed attachmentPoint
1127 // XXX Assumption behind this is that inapplicable device event should
1128 // be dropped, not deferred. If we decide to defer Device event,
1129 // rewriting can become a problem
1130 List<SwitchPort> attachmentPoints = deviceEvent.getAttachmentPoints();
1131 attachmentPoints.removeAll(failedSwitchPort);
1132 deviceEvent.setAttachmentPoints(attachmentPoints);
1133
1134 if (deviceEvent.getAttachmentPoints().isEmpty() &&
1135 deviceEvent.getIpAddresses().isEmpty()) {
1136 // return false to represent: Nothing left to do for this event.
1137 // Caller should drop event
1138 return false;
1139 }
Yuta HIGUCHI8d762e92014-02-12 14:10:25 -08001140
1141 // Should we return false to tell caller that the event was trimmed?
1142 // if ( preconditionBroken ) {
1143 // return false;
1144 // }
1145
Pavlin Radoslavovc1cfde52014-02-19 11:35:29 -08001146 return true;
1147 }
1148
1149 private boolean prepareForRemoveDeviceEvent(DeviceEvent deviceEvent) {
1150 // No show stopping precondition?
1151 // Prep: none
1152 return true;
1153 }
1154
Pavlin Radoslavovc1cfde52014-02-19 11:35:29 -08001155 private SwitchImpl getSwitchImpl(Switch sw) {
1156 if (sw instanceof SwitchImpl) {
1157 return (SwitchImpl) sw;
1158 }
1159 throw new ClassCastException("SwitchImpl expected, but found: " + sw);
1160 }
1161
1162 private PortImpl getPortImpl(Port p) {
1163 if (p instanceof PortImpl) {
1164 return (PortImpl) p;
1165 }
1166 throw new ClassCastException("PortImpl expected, but found: " + p);
1167 }
1168
1169 private LinkImpl getLinkImpl(Link l) {
1170 if (l instanceof LinkImpl) {
1171 return (LinkImpl) l;
1172 }
1173 throw new ClassCastException("LinkImpl expected, but found: " + l);
1174 }
1175
1176 private DeviceImpl getDeviceImpl(Device d) {
1177 if (d instanceof DeviceImpl) {
1178 return (DeviceImpl) d;
1179 }
1180 throw new ClassCastException("DeviceImpl expected, but found: " + d);
1181 }
1182
1183 @Deprecated
Pavlin Radoslavov018d5332014-02-19 23:08:35 -08001184 private Collection<EventEntry<TopologyEvent>> readWholeTopologyFromDB() {
1185 Collection<EventEntry<TopologyEvent>> collection =
1186 new LinkedList<EventEntry<TopologyEvent>>();
1187
Pavlin Radoslavovc1cfde52014-02-19 11:35:29 -08001188 // XXX May need to clear whole topology first, depending on
1189 // how we initially subscribe to replication events
1190
Pavlin Radoslavov018d5332014-02-19 23:08:35 -08001191 // Add all active switches
Pavlin Radoslavovc1cfde52014-02-19 11:35:29 -08001192 for (RCSwitch sw : RCSwitch.getAllSwitches()) {
1193 if (sw.getStatus() != RCSwitch.STATUS.ACTIVE) {
1194 continue;
1195 }
Pavlin Radoslavov018d5332014-02-19 23:08:35 -08001196
1197 SwitchEvent switchEvent = new SwitchEvent(sw.getDpid());
1198 TopologyEvent topologyEvent = new TopologyEvent(switchEvent);
1199 EventEntry<TopologyEvent> eventEntry =
1200 new EventEntry<TopologyEvent>(EventEntry.Type.ENTRY_ADD,
1201 topologyEvent);
1202 collection.add(eventEntry);
Yuta HIGUCHIa536e762014-02-17 21:47:28 -08001203 }
1204
Pavlin Radoslavov018d5332014-02-19 23:08:35 -08001205 // Add all active ports
Pavlin Radoslavovc1cfde52014-02-19 11:35:29 -08001206 for (RCPort p : RCPort.getAllPorts()) {
1207 if (p.getStatus() != RCPort.STATUS.ACTIVE) {
1208 continue;
Yuta HIGUCHIa536e762014-02-17 21:47:28 -08001209 }
Pavlin Radoslavov018d5332014-02-19 23:08:35 -08001210
1211 PortEvent portEvent = new PortEvent(p.getDpid(), p.getNumber());
1212 TopologyEvent topologyEvent = new TopologyEvent(portEvent);
1213 EventEntry<TopologyEvent> eventEntry =
1214 new EventEntry<TopologyEvent>(EventEntry.Type.ENTRY_ADD,
1215 topologyEvent);
1216 collection.add(eventEntry);
Yuta HIGUCHIa536e762014-02-17 21:47:28 -08001217 }
1218
Pavlin Radoslavovc1cfde52014-02-19 11:35:29 -08001219 // TODO Is Device going to be in DB? If so, read from DB.
1220 // for (RCDevice d : RCDevice.getAllDevices()) {
1221 // DeviceEvent devEvent = new DeviceEvent( MACAddress.valueOf(d.getMac()) );
1222 // for (byte[] portId : d.getAllPortIds() ) {
1223 // devEvent.addAttachmentPoint( new SwitchPort( RCPort.getDpidFromKey(portId), RCPort.getNumberFromKey(portId) ));
1224 // }
1225 // }
1226
1227 for (RCLink l : RCLink.getAllLinks()) {
1228 // check if src/dst switch/port exist before triggering event
1229 Port srcPort = networkGraph.getPort(l.getSrc().dpid,
1230 l.getSrc().number);
1231 Port dstPort = networkGraph.getPort(l.getDst().dpid,
1232 l.getDst().number);
1233 if (srcPort == null || dstPort == null) {
1234 continue;
Yuta HIGUCHI76df2472014-02-12 22:36:51 -08001235 }
Pavlin Radoslavov018d5332014-02-19 23:08:35 -08001236
1237 LinkEvent linkEvent = new LinkEvent(l.getSrc().dpid,
1238 l.getSrc().number,
1239 l.getDst().dpid,
1240 l.getDst().number);
1241 TopologyEvent topologyEvent = new TopologyEvent(linkEvent);
1242 EventEntry<TopologyEvent> eventEntry =
1243 new EventEntry<TopologyEvent>(EventEntry.Type.ENTRY_ADD,
1244 topologyEvent);
1245 collection.add(eventEntry);
Yuta HIGUCHI76df2472014-02-12 22:36:51 -08001246 }
Pavlin Radoslavov018d5332014-02-19 23:08:35 -08001247
1248 return collection;
Pavlin Radoslavovc1cfde52014-02-19 11:35:29 -08001249 }
Pavlin Radoslavov50cd1482014-02-19 16:57:03 -08001250
1251 @Deprecated
1252 private void removeLinkDiscoveryEvent(LinkEvent linkEvent,
1253 boolean dstCheckBeforeDBmodify) {
1254 if (prepareForRemoveLinkEvent(linkEvent)) {
1255 if (dstCheckBeforeDBmodify) {
1256 // write to DB only if it is owner of the dst dpid
1257 // XXX this will cause link remove events to be dropped
1258 // if the dst switch just disconnected
1259 if (registryService.hasControl(linkEvent.getDst().dpid)) {
1260 datastore.removeLink(linkEvent);
1261 }
1262 } else {
1263 datastore.removeLink(linkEvent);
1264 }
1265 removeLink(linkEvent);
1266 // Send out notification
1267 eventChannel.removeEntry(linkEvent.getID());
1268 }
1269 // TODO handle invariant violation
1270 }
Jonathan Hart062a2e82014-02-03 09:41:57 -08001271}