blob: 642a53607390846823fb58041fc8e0b1744b13ca [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;
Jonathan Hart10a7e2b2014-02-21 18:30:08 -080051 public static final String EVENT_CHANNEL_NAME = "onos.topology";
Pavlin Radoslavov721a2e02014-02-14 23:40:14 -080052 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
adminbc181552014-02-21 18:36:42 -0800390 //
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
Pavlin Radoslavov74986ce2014-02-20 13:17:20 -0800411 // Deliver the events
412 for (INetworkGraphListener listener : this.networkGraphListeners) {
413 // TODO: Should copy before handing them over to listener?
414 listener.networkGraphEvents(apiAddedSwitchEvents,
415 apiRemovedSwitchEvents,
416 apiAddedPortEvents,
417 apiRemovedPortEvents,
418 apiAddedLinkEvents,
419 apiRemovedLinkEvents,
420 apiAddedDeviceEvents,
421 apiRemovedDeviceEvents);
422 }
423
424 //
425 // Cleanup
426 //
427 apiAddedSwitchEvents.clear();
428 apiRemovedSwitchEvents.clear();
429 apiAddedPortEvents.clear();
430 apiRemovedPortEvents.clear();
431 apiAddedLinkEvents.clear();
432 apiRemovedLinkEvents.clear();
433 apiAddedDeviceEvents.clear();
434 apiRemovedDeviceEvents.clear();
435 }
436
437 /**
438 * Apply reordered events.
439 *
440 * @param hasAddedSwitchEvents true if there were Added Switch Events.
441 * @param hasAddedPortEvents true if there were Added Port Events.
442 */
443 private void applyReorderedEvents(boolean hasAddedSwitchEvents,
444 boolean hasAddedPortEvents) {
445 if (! (hasAddedSwitchEvents || hasAddedPortEvents))
446 return; // Nothing to do
447
448 //
449 // Try to apply the reordered events.
450 //
451 // NOTE: For simplicity we try to apply all events of a particular
452 // type if any "parent" type event was processed:
453 // - Apply reordered Port Events if Switches were added
454 // - Apply reordered Link and Device Events if Switches or Ports
455 // were added
456 //
adminbc181552014-02-21 18:36:42 -0800457
Pavlin Radoslavov74986ce2014-02-20 13:17:20 -0800458 //
459 // Apply reordered Port Events if Switches were added
460 //
461 if (hasAddedSwitchEvents) {
adminbc181552014-02-21 18:36:42 -0800462 Map<ByteBuffer, PortEvent> portEvents = reorderedAddedPortEvents;
463 reorderedAddedPortEvents = new HashMap<>();
Pavlin Radoslavov74986ce2014-02-20 13:17:20 -0800464 for (PortEvent portEvent : portEvents.values())
465 addPort(portEvent);
466 }
467 //
468 // Apply reordered Link and Device Events if Switches or Ports
469 // were added.
470 //
adminbc181552014-02-21 18:36:42 -0800471 Map<ByteBuffer, LinkEvent> linkEvents = reorderedAddedLinkEvents;
472 reorderedAddedLinkEvents = new HashMap<>();
Pavlin Radoslavov74986ce2014-02-20 13:17:20 -0800473 for (LinkEvent linkEvent : linkEvents.values())
474 addLink(linkEvent);
adminbc181552014-02-21 18:36:42 -0800475 //
476 Map<ByteBuffer, DeviceEvent> deviceEvents = reorderedAddedDeviceEvents;
477 reorderedAddedDeviceEvents = new HashMap<>();
Pavlin Radoslavov74986ce2014-02-20 13:17:20 -0800478 for (DeviceEvent deviceEvent : deviceEvents.values())
479 addDevice(deviceEvent);
480 }
481
Jonathan Hart22eb9882014-02-11 15:52:59 -0800482 /* ******************************
483 * NetworkGraphDiscoveryInterface methods
484 * ******************************/
Yuta HIGUCHIcd922f42014-02-11 18:59:11 -0800485
Pavlin Radoslavovc1cfde52014-02-19 11:35:29 -0800486 @Override
Pavlin Radoslavov018d5332014-02-19 23:08:35 -0800487 public void putSwitchDiscoveryEvent(SwitchEvent switchEvent,
488 Collection<PortEvent> portEvents) {
489 if (datastore.addSwitch(switchEvent, portEvents)) {
Pavlin Radoslavovc1cfde52014-02-19 11:35:29 -0800490 // Send out notification
Pavlin Radoslavov87dcc262014-02-19 21:13:23 -0800491 TopologyEvent topologyEvent = new TopologyEvent(switchEvent);
Pavlin Radoslavovc1cfde52014-02-19 11:35:29 -0800492 eventChannel.addEntry(topologyEvent.getID(), topologyEvent);
Pavlin Radoslavov018d5332014-02-19 23:08:35 -0800493
Pavlin Radoslavov26d83402014-02-20 15:24:30 -0800494 // Send out notification for each port
Pavlin Radoslavov018d5332014-02-19 23:08:35 -0800495 for (PortEvent portEvent : portEvents) {
496 topologyEvent = new TopologyEvent(portEvent);
497 eventChannel.addEntry(topologyEvent.getID(), topologyEvent);
498 }
Pavlin Radoslavov26d83402014-02-20 15:24:30 -0800499
500 //
501 // Keep track of the added ports
502 //
503 // Get the old Port Events
504 Map<ByteBuffer, PortEvent> oldPortEvents =
505 discoveredAddedPortEvents.get(switchEvent.getDpid());
506 if (oldPortEvents == null)
507 oldPortEvents = new HashMap<>();
508
509 // Store the new Port Events in the local cache
510 Map<ByteBuffer, PortEvent> newPortEvents = new HashMap<>();
511 for (PortEvent portEvent : portEvents) {
512 ByteBuffer id = ByteBuffer.wrap(portEvent.getID());
513 newPortEvents.put(id, portEvent);
514 }
515 discoveredAddedPortEvents.put(switchEvent.getDpid(),
516 newPortEvents);
517
518 //
519 // Extract the removed ports
520 //
521 List<PortEvent> removedPortEvents = new LinkedList<>();
522 for (Map.Entry<ByteBuffer, PortEvent> entry : oldPortEvents.entrySet()) {
523 ByteBuffer key = entry.getKey();
524 PortEvent portEvent = entry.getValue();
525 if (! newPortEvents.containsKey(key))
526 removedPortEvents.add(portEvent);
527 }
528
529 // Cleanup old removed ports
530 for (PortEvent portEvent : removedPortEvents)
531 removePortDiscoveryEvent(portEvent);
Pavlin Radoslavovc1cfde52014-02-19 11:35:29 -0800532 }
Pavlin Radoslavovc1cfde52014-02-19 11:35:29 -0800533 }
534
535 @Override
Pavlin Radoslavov6ea84a42014-02-19 15:50:01 -0800536 public void removeSwitchDiscoveryEvent(SwitchEvent switchEvent) {
Pavlin Radoslavov26d83402014-02-20 15:24:30 -0800537 // Get the old Port Events
538 Map<ByteBuffer, PortEvent> oldPortEvents =
539 discoveredAddedPortEvents.get(switchEvent.getDpid());
540 if (oldPortEvents == null)
541 oldPortEvents = new HashMap<>();
Pavlin Radoslavov018d5332014-02-19 23:08:35 -0800542
Pavlin Radoslavov26d83402014-02-20 15:24:30 -0800543 if (datastore.deactivateSwitch(switchEvent, oldPortEvents.values())) {
Pavlin Radoslavovc1cfde52014-02-19 11:35:29 -0800544 // Send out notification
545 eventChannel.removeEntry(switchEvent.getID());
Pavlin Radoslavov018d5332014-02-19 23:08:35 -0800546
Pavlin Radoslavov26d83402014-02-20 15:24:30 -0800547 // Send out notification for each port
548 for (PortEvent portEvent : oldPortEvents.values())
Pavlin Radoslavov018d5332014-02-19 23:08:35 -0800549 eventChannel.removeEntry(portEvent.getID());
Pavlin Radoslavov26d83402014-02-20 15:24:30 -0800550 discoveredAddedPortEvents.remove(switchEvent.getDpid());
551
552 // Cleanup for each link
553 Map<ByteBuffer, LinkEvent> oldLinkEvents =
554 discoveredAddedLinkEvents.get(switchEvent.getDpid());
555 if (oldLinkEvents != null) {
556 for (LinkEvent linkEvent : oldLinkEvents.values())
557 removeLinkDiscoveryEvent(linkEvent);
558 discoveredAddedLinkEvents.remove(switchEvent.getDpid());
559 }
560
561 // Cleanup for each device
562 Map<ByteBuffer, DeviceEvent> oldDeviceEvents =
563 discoveredAddedDeviceEvents.get(switchEvent.getDpid());
564 if (oldDeviceEvents != null) {
565 for (DeviceEvent deviceEvent : oldDeviceEvents.values())
566 removeDeviceDiscoveryEvent(deviceEvent);
567 discoveredAddedDeviceEvents.remove(switchEvent.getDpid());
Pavlin Radoslavov018d5332014-02-19 23:08:35 -0800568 }
Pavlin Radoslavovc1cfde52014-02-19 11:35:29 -0800569 }
Pavlin Radoslavovc1cfde52014-02-19 11:35:29 -0800570 }
571
572 @Override
Pavlin Radoslavov6ea84a42014-02-19 15:50:01 -0800573 public void putPortDiscoveryEvent(PortEvent portEvent) {
Pavlin Radoslavov50cd1482014-02-19 16:57:03 -0800574 if (datastore.addPort(portEvent)) {
Pavlin Radoslavovc1cfde52014-02-19 11:35:29 -0800575 // Send out notification
Pavlin Radoslavov87dcc262014-02-19 21:13:23 -0800576 TopologyEvent topologyEvent = new TopologyEvent(portEvent);
Pavlin Radoslavov018d5332014-02-19 23:08:35 -0800577 eventChannel.addEntry(topologyEvent.getID(), topologyEvent);
Pavlin Radoslavov26d83402014-02-20 15:24:30 -0800578
579 // Store the new Port Event in the local cache
580 Map<ByteBuffer, PortEvent> oldPortEvents =
581 discoveredAddedPortEvents.get(portEvent.getDpid());
582 if (oldPortEvents == null) {
583 oldPortEvents = new HashMap<>();
584 discoveredAddedPortEvents.put(portEvent.getDpid(),
585 oldPortEvents);
586 }
587 ByteBuffer id = ByteBuffer.wrap(portEvent.getID());
588 oldPortEvents.put(id, portEvent);
Pavlin Radoslavovc1cfde52014-02-19 11:35:29 -0800589 }
Pavlin Radoslavovc1cfde52014-02-19 11:35:29 -0800590 }
591
592 @Override
Pavlin Radoslavov6ea84a42014-02-19 15:50:01 -0800593 public void removePortDiscoveryEvent(PortEvent portEvent) {
Pavlin Radoslavov50cd1482014-02-19 16:57:03 -0800594 if (datastore.deactivatePort(portEvent)) {
Pavlin Radoslavovc1cfde52014-02-19 11:35:29 -0800595 // Send out notification
596 eventChannel.removeEntry(portEvent.getID());
Pavlin Radoslavov26d83402014-02-20 15:24:30 -0800597
598 // Cleanup the Port Event from the local cache
599 Map<ByteBuffer, PortEvent> oldPortEvents =
600 discoveredAddedPortEvents.get(portEvent.getDpid());
601 if (oldPortEvents != null) {
602 ByteBuffer id = ByteBuffer.wrap(portEvent.getID());
603 oldPortEvents.remove(id);
604 }
605
606 // Cleanup for the incoming link
607 Map<ByteBuffer, LinkEvent> oldLinkEvents =
608 discoveredAddedLinkEvents.get(portEvent.getDpid());
609 if (oldLinkEvents != null) {
610 for (LinkEvent linkEvent : oldLinkEvents.values()) {
611 if (linkEvent.getDst().equals(portEvent.id)) {
612 removeLinkDiscoveryEvent(linkEvent);
613 //
614 // NOTE: oldLinkEvents was modified by
615 // removeLinkDiscoveryEvent() and cannot be iterated
616 // anymore.
617 //
618 break;
619 }
620 }
621 }
622
623 // Cleanup for the connected devices
624 // TODO: The implementation below is probably wrong
625 List<DeviceEvent> removedDeviceEvents = new LinkedList<>();
626 Map<ByteBuffer, DeviceEvent> oldDeviceEvents =
627 discoveredAddedDeviceEvents.get(portEvent.getDpid());
628 if (oldDeviceEvents != null) {
629 for (DeviceEvent deviceEvent : oldDeviceEvents.values()) {
630 for (SwitchPort swp : deviceEvent.getAttachmentPoints()) {
631 if (swp.equals(portEvent.id)) {
632 removedDeviceEvents.add(deviceEvent);
633 break;
634 }
635 }
636 }
637 for (DeviceEvent deviceEvent : removedDeviceEvents)
638 removeDeviceDiscoveryEvent(deviceEvent);
639 }
Pavlin Radoslavovc1cfde52014-02-19 11:35:29 -0800640 }
Pavlin Radoslavovc1cfde52014-02-19 11:35:29 -0800641 }
642
643 @Override
Pavlin Radoslavov6ea84a42014-02-19 15:50:01 -0800644 public void putLinkDiscoveryEvent(LinkEvent linkEvent) {
Pavlin Radoslavov50cd1482014-02-19 16:57:03 -0800645 if (datastore.addLink(linkEvent)) {
Pavlin Radoslavovc1cfde52014-02-19 11:35:29 -0800646 // Send out notification
Pavlin Radoslavov87dcc262014-02-19 21:13:23 -0800647 TopologyEvent topologyEvent = new TopologyEvent(linkEvent);
Pavlin Radoslavovc1cfde52014-02-19 11:35:29 -0800648 eventChannel.addEntry(topologyEvent.getID(), topologyEvent);
Pavlin Radoslavov26d83402014-02-20 15:24:30 -0800649
650 // Store the new Link Event in the local cache
651 Map<ByteBuffer, LinkEvent> oldLinkEvents =
652 discoveredAddedLinkEvents.get(linkEvent.getDst().getDpid());
653 if (oldLinkEvents == null) {
654 oldLinkEvents = new HashMap<>();
655 discoveredAddedLinkEvents.put(linkEvent.getDst().getDpid(),
656 oldLinkEvents);
657 }
658 ByteBuffer id = ByteBuffer.wrap(linkEvent.getID());
659 oldLinkEvents.put(id, linkEvent);
Pavlin Radoslavovc1cfde52014-02-19 11:35:29 -0800660 }
Pavlin Radoslavovc1cfde52014-02-19 11:35:29 -0800661 }
662
663 @Override
Pavlin Radoslavov6ea84a42014-02-19 15:50:01 -0800664 public void removeLinkDiscoveryEvent(LinkEvent linkEvent) {
Pavlin Radoslavov50cd1482014-02-19 16:57:03 -0800665 if (datastore.removeLink(linkEvent)) {
Pavlin Radoslavovc1cfde52014-02-19 11:35:29 -0800666 // Send out notification
667 eventChannel.removeEntry(linkEvent.getID());
Pavlin Radoslavov26d83402014-02-20 15:24:30 -0800668
669 // Cleanup the Link Event from the local cache
670 Map<ByteBuffer, LinkEvent> oldLinkEvents =
671 discoveredAddedLinkEvents.get(linkEvent.getDst().getDpid());
672 if (oldLinkEvents != null) {
673 ByteBuffer id = ByteBuffer.wrap(linkEvent.getID());
674 oldLinkEvents.remove(id);
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 putDeviceDiscoveryEvent(DeviceEvent deviceEvent) {
Pavlin Radoslavov50cd1482014-02-19 16:57:03 -0800681 if (datastore.addDevice(deviceEvent)) {
Pavlin Radoslavovc1cfde52014-02-19 11:35:29 -0800682 // Send out notification
Pavlin Radoslavov87dcc262014-02-19 21:13:23 -0800683 TopologyEvent topologyEvent = new TopologyEvent(deviceEvent);
Pavlin Radoslavov50cd1482014-02-19 16:57:03 -0800684 eventChannel.addEntry(topologyEvent.getID(), topologyEvent);
Pavlin Radoslavov26d83402014-02-20 15:24:30 -0800685
686 // Store the new Device Event in the local cache
687 // TODO: The implementation below is probably wrong
688 for (SwitchPort swp : deviceEvent.getAttachmentPoints()) {
689 Map<ByteBuffer, DeviceEvent> oldDeviceEvents =
690 discoveredAddedDeviceEvents.get(swp.getDpid());
691 if (oldDeviceEvents == null) {
692 oldDeviceEvents = new HashMap<>();
693 discoveredAddedDeviceEvents.put(swp.getDpid(),
694 oldDeviceEvents);
695 }
696 ByteBuffer id = ByteBuffer.wrap(deviceEvent.getID());
697 oldDeviceEvents.put(id, deviceEvent);
698 }
Jonathan Hart22eb9882014-02-11 15:52:59 -0800699 }
Pavlin Radoslavovc1cfde52014-02-19 11:35:29 -0800700 }
Jonathan Hart22eb9882014-02-11 15:52:59 -0800701
Pavlin Radoslavovc1cfde52014-02-19 11:35:29 -0800702 @Override
Pavlin Radoslavov6ea84a42014-02-19 15:50:01 -0800703 public void removeDeviceDiscoveryEvent(DeviceEvent deviceEvent) {
Pavlin Radoslavov50cd1482014-02-19 16:57:03 -0800704 if (datastore.removeDevice(deviceEvent)) {
Pavlin Radoslavovc1cfde52014-02-19 11:35:29 -0800705 // Send out notification
706 eventChannel.removeEntry(deviceEvent.getID());
Pavlin Radoslavov26d83402014-02-20 15:24:30 -0800707
708 // Cleanup the Device Event from the local cache
709 // TODO: The implementation below is probably wrong
710 ByteBuffer id = ByteBuffer.wrap(deviceEvent.getID());
711 for (SwitchPort swp : deviceEvent.getAttachmentPoints()) {
712 Map<ByteBuffer, DeviceEvent> oldDeviceEvents =
713 discoveredAddedDeviceEvents.get(swp.getDpid());
714 if (oldDeviceEvents != null) {
715 oldDeviceEvents.remove(id);
716 }
717 }
Jonathan Hart22eb9882014-02-11 15:52:59 -0800718 }
Pavlin Radoslavovc1cfde52014-02-19 11:35:29 -0800719 }
Jonathan Hart22eb9882014-02-11 15:52:59 -0800720
Pavlin Radoslavov3c9cc552014-02-20 09:58:38 -0800721 /* ************************************************
722 * Internal methods to maintain the network graph
723 * ************************************************/
Pavlin Radoslavov74986ce2014-02-20 13:17:20 -0800724 private void addSwitch(SwitchEvent switchEvent) {
725 Switch sw = networkGraph.getSwitch(switchEvent.getDpid());
Pavlin Radoslavov3c9cc552014-02-20 09:58:38 -0800726 if (sw == null) {
Pavlin Radoslavov74986ce2014-02-20 13:17:20 -0800727 sw = new SwitchImpl(networkGraph, switchEvent.getDpid());
Pavlin Radoslavov3c9cc552014-02-20 09:58:38 -0800728 networkGraph.putSwitch(sw);
729 } else {
730 // TODO: Update the switch attributes
731 // TODO: Nothing to do for now
732 }
Pavlin Radoslavov74986ce2014-02-20 13:17:20 -0800733 apiAddedSwitchEvents.add(switchEvent);
Pavlin Radoslavov3c9cc552014-02-20 09:58:38 -0800734 }
735
Pavlin Radoslavov74986ce2014-02-20 13:17:20 -0800736 private void removeSwitch(SwitchEvent switchEvent) {
737 Switch sw = networkGraph.getSwitch(switchEvent.getDpid());
Pavlin Radoslavov3c9cc552014-02-20 09:58:38 -0800738 if (sw == null) {
Pavlin Radoslavov74986ce2014-02-20 13:17:20 -0800739 log.warn("Switch {} already removed, ignoring", switchEvent);
Pavlin Radoslavov3c9cc552014-02-20 09:58:38 -0800740 return;
741 }
742
743 //
744 // Remove all Ports on the Switch
745 //
746 ArrayList<PortEvent> portsToRemove = new ArrayList<>();
747 for (Port port : sw.getPorts()) {
748 log.warn("Port {} on Switch {} should be removed prior to removing Switch. Removing Port now.",
Pavlin Radoslavov74986ce2014-02-20 13:17:20 -0800749 port, switchEvent);
Pavlin Radoslavov3c9cc552014-02-20 09:58:38 -0800750 PortEvent portEvent = new PortEvent(port.getDpid(),
751 port.getNumber());
752 portsToRemove.add(portEvent);
753 }
754 for (PortEvent portEvent : portsToRemove)
755 removePort(portEvent);
756
Pavlin Radoslavov74986ce2014-02-20 13:17:20 -0800757 networkGraph.removeSwitch(switchEvent.getDpid());
758 apiRemovedSwitchEvents.add(switchEvent);
Pavlin Radoslavov3c9cc552014-02-20 09:58:38 -0800759 }
760
761 private void addPort(PortEvent portEvent) {
762 Switch sw = networkGraph.getSwitch(portEvent.getDpid());
763 if (sw == null) {
Pavlin Radoslavov706add22014-02-20 12:15:59 -0800764 // Reordered event: delay the event in local cache
765 ByteBuffer id = ByteBuffer.wrap(portEvent.getID());
766 reorderedAddedPortEvents.put(id, portEvent);
Pavlin Radoslavov3c9cc552014-02-20 09:58:38 -0800767 return;
768 }
769 SwitchImpl switchImpl = getSwitchImpl(sw);
770
771 Port port = sw.getPort(portEvent.getNumber());
772 if (port == null) {
773 port = new PortImpl(networkGraph, sw, portEvent.getNumber());
774 switchImpl.addPort(port);
775 } else {
776 // TODO: Update the port attributes
777 }
Pavlin Radoslavov74986ce2014-02-20 13:17:20 -0800778 apiAddedPortEvents.add(portEvent);
Pavlin Radoslavov3c9cc552014-02-20 09:58:38 -0800779 }
780
781 private void removePort(PortEvent portEvent) {
782 Switch sw = networkGraph.getSwitch(portEvent.getDpid());
783 if (sw == null) {
784 log.warn("Parent Switch for Port {} already removed, ignoring",
785 portEvent);
786 return;
787 }
788
789 Port port = sw.getPort(portEvent.getNumber());
790 if (port == null) {
791 log.warn("Port {} already removed, ignoring", portEvent);
792 return;
793 }
794
795 //
796 // Remove all Devices attached to the Port
797 //
798 ArrayList<DeviceEvent> devicesToRemove = new ArrayList<>();
799 for (Device device : port.getDevices()) {
800 log.debug("Removing Device {} on Port {}", device, portEvent);
801 DeviceEvent deviceEvent = new DeviceEvent(device.getMacAddress());
802 SwitchPort switchPort = new SwitchPort(port.getSwitch().getDpid(),
803 port.getNumber());
804 deviceEvent.addAttachmentPoint(switchPort);
805 devicesToRemove.add(deviceEvent);
806 }
807 for (DeviceEvent deviceEvent : devicesToRemove)
808 removeDevice(deviceEvent);
809
810 //
811 // Remove all Links connected to the Port
812 //
813 Set<Link> links = new HashSet<>();
814 links.add(port.getOutgoingLink());
815 links.add(port.getIncomingLink());
816 ArrayList<LinkEvent> linksToRemove = new ArrayList<>();
817 for (Link link : links) {
818 if (link == null)
819 continue;
820 log.debug("Removing Link {} on Port {}", link, portEvent);
821 LinkEvent linkEvent = new LinkEvent(link.getSrcSwitch().getDpid(),
822 link.getSrcPort().getNumber(),
823 link.getDstSwitch().getDpid(),
824 link.getDstPort().getNumber());
825 linksToRemove.add(linkEvent);
826 }
827 for (LinkEvent linkEvent : linksToRemove)
828 removeLink(linkEvent);
829
830 // Remove the Port from the Switch
831 SwitchImpl switchImpl = getSwitchImpl(sw);
832 switchImpl.removePort(port);
Pavlin Radoslavov74986ce2014-02-20 13:17:20 -0800833
834 apiRemovedPortEvents.add(portEvent);
Pavlin Radoslavov3c9cc552014-02-20 09:58:38 -0800835 }
836
837 private void addLink(LinkEvent linkEvent) {
838 Port srcPort = networkGraph.getPort(linkEvent.getSrc().dpid,
839 linkEvent.getSrc().number);
Pavlin Radoslavov3c9cc552014-02-20 09:58:38 -0800840 Port dstPort = networkGraph.getPort(linkEvent.getDst().dpid,
841 linkEvent.getDst().number);
Pavlin Radoslavov706add22014-02-20 12:15:59 -0800842 if ((srcPort == null) || (dstPort == null)) {
843 // Reordered event: delay the event in local cache
844 ByteBuffer id = ByteBuffer.wrap(linkEvent.getID());
845 reorderedAddedLinkEvents.put(id, linkEvent);
Pavlin Radoslavov3c9cc552014-02-20 09:58:38 -0800846 return;
847 }
848
849 // Get the Link instance from the Destination Port Incoming Link
850 Link link = dstPort.getIncomingLink();
851 assert(link == srcPort.getOutgoingLink());
852 if (link == null) {
853 link = new LinkImpl(networkGraph, srcPort, dstPort);
854 PortImpl srcPortImpl = getPortImpl(srcPort);
855 PortImpl dstPortImpl = getPortImpl(dstPort);
856 srcPortImpl.setOutgoingLink(link);
857 dstPortImpl.setIncomingLink(link);
858
859 // Remove all Devices attached to the Ports
860 ArrayList<DeviceEvent> devicesToRemove = new ArrayList<>();
861 ArrayList<Port> ports = new ArrayList<>();
862 ports.add(srcPort);
863 ports.add(dstPort);
864 for (Port port : ports) {
865 for (Device device : port.getDevices()) {
866 log.error("Device {} on Port {} should have been removed prior to adding Link {}",
867 device, port, linkEvent);
868 DeviceEvent deviceEvent =
869 new DeviceEvent(device.getMacAddress());
870 SwitchPort switchPort =
871 new SwitchPort(port.getSwitch().getDpid(),
872 port.getNumber());
873 deviceEvent.addAttachmentPoint(switchPort);
874 devicesToRemove.add(deviceEvent);
875 }
876 }
877 for (DeviceEvent deviceEvent : devicesToRemove)
878 removeDevice(deviceEvent);
879 } else {
880 // TODO: Update the link attributes
881 }
Pavlin Radoslavov74986ce2014-02-20 13:17:20 -0800882
883 apiAddedLinkEvents.add(linkEvent);
Pavlin Radoslavov3c9cc552014-02-20 09:58:38 -0800884 }
885
886 private void removeLink(LinkEvent linkEvent) {
887 Port srcPort = networkGraph.getPort(linkEvent.getSrc().dpid,
888 linkEvent.getSrc().number);
889 if (srcPort == null) {
890 log.warn("Src Port for Link {} already removed, ignoring",
891 linkEvent);
892 return;
893 }
894
895 Port dstPort = networkGraph.getPort(linkEvent.getDst().dpid,
896 linkEvent.getDst().number);
897 if (dstPort == null) {
898 log.warn("Dst Port for Link {} already removed, ignoring",
899 linkEvent);
900 return;
901 }
902
903 //
904 // Remove the Link instance from the Destination Port Incoming Link
905 // and the Source Port Outgoing Link.
906 //
907 Link link = dstPort.getIncomingLink();
908 if (link == null) {
909 log.warn("Link {} already removed on destination Port", linkEvent);
910 }
911 link = srcPort.getOutgoingLink();
912 if (link == null) {
913 log.warn("Link {} already removed on src Port", linkEvent);
914 }
915 getPortImpl(dstPort).setIncomingLink(null);
916 getPortImpl(srcPort).setOutgoingLink(null);
Pavlin Radoslavov74986ce2014-02-20 13:17:20 -0800917
918 apiRemovedLinkEvents.add(linkEvent);
Pavlin Radoslavov3c9cc552014-02-20 09:58:38 -0800919 }
920
921 // TODO: Device-related work is incomplete
922 private void addDevice(DeviceEvent deviceEvent) {
923 Device device = networkGraph.getDeviceByMac(deviceEvent.getMac());
924 if (device == null) {
925 device = new DeviceImpl(networkGraph, deviceEvent.getMac());
926 }
927 DeviceImpl deviceImpl = getDeviceImpl(device);
928
929 // Update the IP addresses
930 for (InetAddress ipAddr : deviceEvent.getIpAddresses())
931 deviceImpl.addIpAddress(ipAddr);
932
933 // Process each attachment point
934 boolean attachmentFound = false;
935 for (SwitchPort swp : deviceEvent.getAttachmentPoints()) {
936 // Attached Ports must exist
937 Port port = networkGraph.getPort(swp.dpid, swp.number);
938 if (port == null) {
Pavlin Radoslavov706add22014-02-20 12:15:59 -0800939 // Reordered event: delay the event in local cache
940 ByteBuffer id = ByteBuffer.wrap(deviceEvent.getID());
941 reorderedAddedDeviceEvents.put(id, deviceEvent);
Pavlin Radoslavov3c9cc552014-02-20 09:58:38 -0800942 continue;
943 }
944 // Attached Ports must not have Link
945 if (port.getOutgoingLink() != null ||
946 port.getIncomingLink() != null) {
947 log.warn("Link (Out:{},In:{}) exist on the attachment point, skipping mutation.",
948 port.getOutgoingLink(),
949 port.getIncomingLink());
950 continue;
951 }
952
953 // Add Device <-> Port attachment
954 PortImpl portImpl = getPortImpl(port);
955 portImpl.addDevice(device);
956 deviceImpl.addAttachmentPoint(port);
957 attachmentFound = true;
958 }
959
960 // Update the device in the Network Graph
Pavlin Radoslavov74986ce2014-02-20 13:17:20 -0800961 if (attachmentFound) {
Pavlin Radoslavov3c9cc552014-02-20 09:58:38 -0800962 networkGraph.putDevice(device);
Pavlin Radoslavov74986ce2014-02-20 13:17:20 -0800963 apiAddedDeviceEvents.add(deviceEvent);
964 }
Pavlin Radoslavov3c9cc552014-02-20 09:58:38 -0800965 }
966
967 private void removeDevice(DeviceEvent deviceEvent) {
968 Device device = networkGraph.getDeviceByMac(deviceEvent.getMac());
969 if (device == null) {
970 log.warn("Device {} already removed, ignoring", deviceEvent);
971 return;
972 }
973 DeviceImpl deviceImpl = getDeviceImpl(device);
974
975 // Process each attachment point
976 for (SwitchPort swp : deviceEvent.getAttachmentPoints()) {
977 // Attached Ports must exist
978 Port port = networkGraph.getPort(swp.dpid, swp.number);
979 if (port == null) {
980 log.warn("Port for the attachment point {} did not exist. skipping attachment point mutation", swp);
981 continue;
982 }
983
984 // Remove Device <-> Port attachment
985 PortImpl portImpl = getPortImpl(port);
986 portImpl.removeDevice(device);
987 deviceImpl.removeAttachmentPoint(port);
988 }
Pavlin Radoslavov74986ce2014-02-20 13:17:20 -0800989
Pavlin Radoslavov3c9cc552014-02-20 09:58:38 -0800990 networkGraph.removeDevice(device);
Pavlin Radoslavov74986ce2014-02-20 13:17:20 -0800991 apiRemovedDeviceEvents.add(deviceEvent);
Pavlin Radoslavov3c9cc552014-02-20 09:58:38 -0800992 }
Jonathan Hart22eb9882014-02-11 15:52:59 -0800993
Pavlin Radoslavovc1cfde52014-02-19 11:35:29 -0800994 /**
995 *
Pavlin Radoslavov74986ce2014-02-20 13:17:20 -0800996 * @param switchEvent
Pavlin Radoslavovc1cfde52014-02-19 11:35:29 -0800997 * @return true if ready to accept event.
998 */
Pavlin Radoslavov74986ce2014-02-20 13:17:20 -0800999 private boolean prepareForAddSwitchEvent(SwitchEvent switchEvent) {
Pavlin Radoslavovc1cfde52014-02-19 11:35:29 -08001000 // No show stopping precondition
Pavlin Radoslavovc1cfde52014-02-19 11:35:29 -08001001 return true;
1002 }
Jonathan Hart22eb9882014-02-11 15:52:59 -08001003
Pavlin Radoslavov74986ce2014-02-20 13:17:20 -08001004 private boolean prepareForRemoveSwitchEvent(SwitchEvent switchEvent) {
Pavlin Radoslavovc1cfde52014-02-19 11:35:29 -08001005 // No show stopping precondition
Pavlin Radoslavovc1cfde52014-02-19 11:35:29 -08001006 return true;
1007 }
Yuta HIGUCHI71e7a052014-02-17 22:14:15 -08001008
Pavlin Radoslavovc1cfde52014-02-19 11:35:29 -08001009 private boolean prepareForAddPortEvent(PortEvent portEvent) {
1010 // Parent Switch must exist
1011 if (networkGraph.getSwitch(portEvent.getDpid()) == null) {
1012 log.warn("Dropping add port event because switch doesn't exist: {}",
1013 portEvent);
1014 return false;
1015 }
1016 // Prep: None
1017 return true;
1018 }
1019
1020 private boolean prepareForRemovePortEvent(PortEvent portEvent) {
1021 Port port = networkGraph.getPort(portEvent.getDpid(),
1022 portEvent.getNumber());
1023 if (port == null) {
1024 log.debug("Port already removed? {}", portEvent);
1025 // let it pass
1026 return true;
Jonathan Hart22eb9882014-02-11 15:52:59 -08001027 }
Yuta HIGUCHIcd922f42014-02-11 18:59:11 -08001028
Pavlin Radoslavovc1cfde52014-02-19 11:35:29 -08001029 // Prep: Remove Link and Device Attachment
1030 ArrayList<DeviceEvent> deviceEvents = new ArrayList<>();
1031 for (Device device : port.getDevices()) {
1032 log.debug("Removing Device {} on Port {}", device, portEvent);
1033 DeviceEvent devEvent = new DeviceEvent(device.getMacAddress());
1034 devEvent.addAttachmentPoint(new SwitchPort(port.getSwitch().getDpid(),
1035 port.getNumber()));
1036 deviceEvents.add(devEvent);
1037 }
1038 for (DeviceEvent devEvent : deviceEvents) {
1039 // calling Discovery API to wipe from DB, etc.
Pavlin Radoslavov6ea84a42014-02-19 15:50:01 -08001040 removeDeviceDiscoveryEvent(devEvent);
Jonathan Hart22eb9882014-02-11 15:52:59 -08001041 }
Yuta HIGUCHIcd922f42014-02-11 18:59:11 -08001042
Pavlin Radoslavovc1cfde52014-02-19 11:35:29 -08001043 Set<Link> links = new HashSet<>();
1044 links.add(port.getOutgoingLink());
1045 links.add(port.getIncomingLink());
1046 for (Link link : links) {
1047 if (link == null) {
1048 continue;
1049 }
1050 log.debug("Removing Link {} on Port {}", link, portEvent);
1051 LinkEvent linkEvent =
Pavlin Radoslavov7c8f69a2014-02-19 19:01:45 -08001052 new LinkEvent(link.getSrcSwitch().getDpid(),
1053 link.getSrcPort().getNumber(),
1054 link.getDstSwitch().getDpid(),
1055 link.getDstPort().getNumber());
Pavlin Radoslavovc1cfde52014-02-19 11:35:29 -08001056 // calling Discovery API to wipe from DB, etc.
Yuta HIGUCHI8d762e92014-02-12 14:10:25 -08001057
Pavlin Radoslavovc1cfde52014-02-19 11:35:29 -08001058 // Call internal remove Link, which will check
1059 // ownership of DST dpid and modify DB only if it is the owner
Pavlin Radoslavov6ea84a42014-02-19 15:50:01 -08001060 removeLinkDiscoveryEvent(linkEvent, true);
Jonathan Hart22eb9882014-02-11 15:52:59 -08001061 }
Pavlin Radoslavovc1cfde52014-02-19 11:35:29 -08001062 return true;
1063 }
Yuta HIGUCHIcd922f42014-02-11 18:59:11 -08001064
Pavlin Radoslavovc1cfde52014-02-19 11:35:29 -08001065 private boolean prepareForAddLinkEvent(LinkEvent linkEvent) {
1066 // Src/Dst Port must exist
1067 Port srcPort = networkGraph.getPort(linkEvent.getSrc().dpid,
1068 linkEvent.getSrc().number);
1069 Port dstPort = networkGraph.getPort(linkEvent.getDst().dpid,
1070 linkEvent.getDst().number);
1071 if (srcPort == null || dstPort == null) {
Jonathan Hart0a4846e2014-02-18 11:03:40 -08001072 log.warn("Dropping add link event because port doesn't exist: {}",
Pavlin Radoslavovc1cfde52014-02-19 11:35:29 -08001073 linkEvent);
1074 return false;
Jonathan Hart22eb9882014-02-11 15:52:59 -08001075 }
Yuta HIGUCHIcd922f42014-02-11 18:59:11 -08001076
Pavlin Radoslavovc1cfde52014-02-19 11:35:29 -08001077 // Prep: remove Device attachment on both Ports
1078 ArrayList<DeviceEvent> deviceEvents = new ArrayList<>();
1079 for (Device device : srcPort.getDevices()) {
1080 DeviceEvent devEvent = new DeviceEvent(device.getMacAddress());
1081 devEvent.addAttachmentPoint(new SwitchPort(srcPort.getSwitch().getDpid(), srcPort.getNumber()));
1082 deviceEvents.add(devEvent);
1083 }
1084 for (Device device : dstPort.getDevices()) {
1085 DeviceEvent devEvent = new DeviceEvent(device.getMacAddress());
1086 devEvent.addAttachmentPoint(new SwitchPort(dstPort.getSwitch().getDpid(),
1087 dstPort.getNumber()));
1088 deviceEvents.add(devEvent);
1089 }
1090 for (DeviceEvent devEvent : deviceEvents) {
1091 // calling Discovery API to wipe from DB, etc.
Pavlin Radoslavov6ea84a42014-02-19 15:50:01 -08001092 removeDeviceDiscoveryEvent(devEvent);
Jonathan Hart22eb9882014-02-11 15:52:59 -08001093 }
Yuta HIGUCHIcd922f42014-02-11 18:59:11 -08001094
Pavlin Radoslavovc1cfde52014-02-19 11:35:29 -08001095 return true;
1096 }
Yuta HIGUCHId02e9282014-02-12 09:24:41 -08001097
Pavlin Radoslavovc1cfde52014-02-19 11:35:29 -08001098 private boolean prepareForRemoveLinkEvent(LinkEvent linkEvent) {
1099 // Src/Dst Port must exist
1100 Port srcPort = networkGraph.getPort(linkEvent.getSrc().dpid,
1101 linkEvent.getSrc().number);
1102 Port dstPort = networkGraph.getPort(linkEvent.getDst().dpid,
1103 linkEvent.getDst().number);
1104 if (srcPort == null || dstPort == null) {
1105 log.warn("Dropping remove link event because port doesn't exist {}", linkEvent);
1106 return false;
1107 }
Yuta HIGUCHI8d762e92014-02-12 14:10:25 -08001108
Pavlin Radoslavovc1cfde52014-02-19 11:35:29 -08001109 Link link = srcPort.getOutgoingLink();
1110
1111 // Link is already gone, or different Link exist in memory
1112 // XXX Check if we should reject or just accept these cases.
1113 // it should be harmless to remove the Link on event from DB anyways
1114 if (link == null ||
Pavlin Radoslavov7c8f69a2014-02-19 19:01:45 -08001115 !link.getDstPort().getNumber().equals(linkEvent.getDst().number)
1116 || !link.getDstSwitch().getDpid().equals(linkEvent.getDst().dpid)) {
Pavlin Radoslavovc1cfde52014-02-19 11:35:29 -08001117 log.warn("Dropping remove link event because link doesn't exist: {}", linkEvent);
1118 return false;
1119 }
1120 // Prep: None
1121 return true;
1122 }
1123
1124 /**
1125 *
1126 * @param deviceEvent Event will be modified to remove inapplicable attachemntPoints/ipAddress
1127 * @return false if this event should be dropped.
1128 */
1129 private boolean prepareForAddDeviceEvent(DeviceEvent deviceEvent) {
1130 boolean preconditionBroken = false;
1131 ArrayList<PortEvent.SwitchPort> failedSwitchPort = new ArrayList<>();
1132 for ( PortEvent.SwitchPort swp : deviceEvent.getAttachmentPoints() ) {
1133 // Attached Ports must exist
1134 Port port = networkGraph.getPort(swp.dpid, swp.number);
1135 if (port == null) {
1136 preconditionBroken = true;
1137 failedSwitchPort.add(swp);
1138 continue;
Yuta HIGUCHI8d762e92014-02-12 14:10:25 -08001139 }
Pavlin Radoslavovc1cfde52014-02-19 11:35:29 -08001140 // Attached Ports must not have Link
1141 if (port.getOutgoingLink() != null ||
1142 port.getIncomingLink() != null) {
1143 preconditionBroken = true;
1144 failedSwitchPort.add(swp);
1145 continue;
1146 }
1147 }
1148
1149 // Rewriting event to exclude failed attachmentPoint
1150 // XXX Assumption behind this is that inapplicable device event should
1151 // be dropped, not deferred. If we decide to defer Device event,
1152 // rewriting can become a problem
1153 List<SwitchPort> attachmentPoints = deviceEvent.getAttachmentPoints();
1154 attachmentPoints.removeAll(failedSwitchPort);
1155 deviceEvent.setAttachmentPoints(attachmentPoints);
1156
1157 if (deviceEvent.getAttachmentPoints().isEmpty() &&
1158 deviceEvent.getIpAddresses().isEmpty()) {
1159 // return false to represent: Nothing left to do for this event.
1160 // Caller should drop event
1161 return false;
1162 }
Yuta HIGUCHI8d762e92014-02-12 14:10:25 -08001163
1164 // Should we return false to tell caller that the event was trimmed?
1165 // if ( preconditionBroken ) {
1166 // return false;
1167 // }
1168
Pavlin Radoslavovc1cfde52014-02-19 11:35:29 -08001169 return true;
1170 }
1171
1172 private boolean prepareForRemoveDeviceEvent(DeviceEvent deviceEvent) {
1173 // No show stopping precondition?
1174 // Prep: none
1175 return true;
1176 }
1177
Pavlin Radoslavovc1cfde52014-02-19 11:35:29 -08001178 private SwitchImpl getSwitchImpl(Switch sw) {
1179 if (sw instanceof SwitchImpl) {
1180 return (SwitchImpl) sw;
1181 }
1182 throw new ClassCastException("SwitchImpl expected, but found: " + sw);
1183 }
1184
1185 private PortImpl getPortImpl(Port p) {
1186 if (p instanceof PortImpl) {
1187 return (PortImpl) p;
1188 }
1189 throw new ClassCastException("PortImpl expected, but found: " + p);
1190 }
1191
1192 private LinkImpl getLinkImpl(Link l) {
1193 if (l instanceof LinkImpl) {
1194 return (LinkImpl) l;
1195 }
1196 throw new ClassCastException("LinkImpl expected, but found: " + l);
1197 }
1198
1199 private DeviceImpl getDeviceImpl(Device d) {
1200 if (d instanceof DeviceImpl) {
1201 return (DeviceImpl) d;
1202 }
1203 throw new ClassCastException("DeviceImpl expected, but found: " + d);
1204 }
1205
1206 @Deprecated
Pavlin Radoslavov018d5332014-02-19 23:08:35 -08001207 private Collection<EventEntry<TopologyEvent>> readWholeTopologyFromDB() {
1208 Collection<EventEntry<TopologyEvent>> collection =
1209 new LinkedList<EventEntry<TopologyEvent>>();
1210
Pavlin Radoslavovc1cfde52014-02-19 11:35:29 -08001211 // XXX May need to clear whole topology first, depending on
1212 // how we initially subscribe to replication events
1213
Pavlin Radoslavov018d5332014-02-19 23:08:35 -08001214 // Add all active switches
Pavlin Radoslavovc1cfde52014-02-19 11:35:29 -08001215 for (RCSwitch sw : RCSwitch.getAllSwitches()) {
1216 if (sw.getStatus() != RCSwitch.STATUS.ACTIVE) {
1217 continue;
1218 }
Pavlin Radoslavov018d5332014-02-19 23:08:35 -08001219
1220 SwitchEvent switchEvent = new SwitchEvent(sw.getDpid());
1221 TopologyEvent topologyEvent = new TopologyEvent(switchEvent);
1222 EventEntry<TopologyEvent> eventEntry =
1223 new EventEntry<TopologyEvent>(EventEntry.Type.ENTRY_ADD,
1224 topologyEvent);
1225 collection.add(eventEntry);
Yuta HIGUCHIa536e762014-02-17 21:47:28 -08001226 }
1227
Pavlin Radoslavov018d5332014-02-19 23:08:35 -08001228 // Add all active ports
Pavlin Radoslavovc1cfde52014-02-19 11:35:29 -08001229 for (RCPort p : RCPort.getAllPorts()) {
1230 if (p.getStatus() != RCPort.STATUS.ACTIVE) {
1231 continue;
Yuta HIGUCHIa536e762014-02-17 21:47:28 -08001232 }
Pavlin Radoslavov018d5332014-02-19 23:08:35 -08001233
1234 PortEvent portEvent = new PortEvent(p.getDpid(), p.getNumber());
1235 TopologyEvent topologyEvent = new TopologyEvent(portEvent);
1236 EventEntry<TopologyEvent> eventEntry =
1237 new EventEntry<TopologyEvent>(EventEntry.Type.ENTRY_ADD,
1238 topologyEvent);
1239 collection.add(eventEntry);
Yuta HIGUCHIa536e762014-02-17 21:47:28 -08001240 }
1241
Pavlin Radoslavovc1cfde52014-02-19 11:35:29 -08001242 // TODO Is Device going to be in DB? If so, read from DB.
1243 // for (RCDevice d : RCDevice.getAllDevices()) {
1244 // DeviceEvent devEvent = new DeviceEvent( MACAddress.valueOf(d.getMac()) );
1245 // for (byte[] portId : d.getAllPortIds() ) {
1246 // devEvent.addAttachmentPoint( new SwitchPort( RCPort.getDpidFromKey(portId), RCPort.getNumberFromKey(portId) ));
1247 // }
1248 // }
1249
1250 for (RCLink l : RCLink.getAllLinks()) {
1251 // check if src/dst switch/port exist before triggering event
1252 Port srcPort = networkGraph.getPort(l.getSrc().dpid,
1253 l.getSrc().number);
1254 Port dstPort = networkGraph.getPort(l.getDst().dpid,
1255 l.getDst().number);
1256 if (srcPort == null || dstPort == null) {
1257 continue;
Yuta HIGUCHI76df2472014-02-12 22:36:51 -08001258 }
Pavlin Radoslavov018d5332014-02-19 23:08:35 -08001259
1260 LinkEvent linkEvent = new LinkEvent(l.getSrc().dpid,
1261 l.getSrc().number,
1262 l.getDst().dpid,
1263 l.getDst().number);
1264 TopologyEvent topologyEvent = new TopologyEvent(linkEvent);
1265 EventEntry<TopologyEvent> eventEntry =
1266 new EventEntry<TopologyEvent>(EventEntry.Type.ENTRY_ADD,
1267 topologyEvent);
1268 collection.add(eventEntry);
Yuta HIGUCHI76df2472014-02-12 22:36:51 -08001269 }
Pavlin Radoslavov018d5332014-02-19 23:08:35 -08001270
1271 return collection;
Pavlin Radoslavovc1cfde52014-02-19 11:35:29 -08001272 }
Pavlin Radoslavov50cd1482014-02-19 16:57:03 -08001273
1274 @Deprecated
1275 private void removeLinkDiscoveryEvent(LinkEvent linkEvent,
1276 boolean dstCheckBeforeDBmodify) {
1277 if (prepareForRemoveLinkEvent(linkEvent)) {
1278 if (dstCheckBeforeDBmodify) {
1279 // write to DB only if it is owner of the dst dpid
1280 // XXX this will cause link remove events to be dropped
1281 // if the dst switch just disconnected
1282 if (registryService.hasControl(linkEvent.getDst().dpid)) {
1283 datastore.removeLink(linkEvent);
1284 }
1285 } else {
1286 datastore.removeLink(linkEvent);
1287 }
1288 removeLink(linkEvent);
1289 // Send out notification
1290 eventChannel.removeEntry(linkEvent.getID());
1291 }
1292 // TODO handle invariant violation
1293 }
Jonathan Hart062a2e82014-02-03 09:41:57 -08001294}