blob: b07b4ff9dcde57c42f1b82a6b8432d80b4dc111d [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
276 //
Pavlin Radoslavov3c9cc552014-02-20 09:58:38 -0800277 // Apply the classified events.
278 //
279 // Apply the "add" events in the proper order:
280 // switch, port, link, device
281 //
282 for (SwitchEvent switchEvent : addedSwitchEvents.values())
283 addSwitch(switchEvent);
284 for (PortEvent portEvent : addedPortEvents.values())
285 addPort(portEvent);
286 for (LinkEvent linkEvent : addedLinkEvents.values())
287 addLink(linkEvent);
288 for (DeviceEvent deviceEvent : addedDeviceEvents.values())
289 addDevice(deviceEvent);
290 //
291 // Apply the "remove" events in the reverse order:
292 // device, link, port, switch
293 //
294 for (DeviceEvent deviceEvent : removedDeviceEvents.values())
295 removeDevice(deviceEvent);
296 for (LinkEvent linkEvent : removedLinkEvents.values())
297 removeLink(linkEvent);
298 for (PortEvent portEvent : removedPortEvents.values())
299 removePort(portEvent);
300 for (SwitchEvent switchEvent : removedSwitchEvents.values())
301 removeSwitch(switchEvent);
302
Pavlin Radoslavov3c9cc552014-02-20 09:58:38 -0800303 //
Pavlin Radoslavov74986ce2014-02-20 13:17:20 -0800304 // Apply reordered events
Pavlin Radoslavov3c9cc552014-02-20 09:58:38 -0800305 //
Pavlin Radoslavov74986ce2014-02-20 13:17:20 -0800306 applyReorderedEvents(! addedSwitchEvents.isEmpty(),
307 ! addedPortEvents.isEmpty());
308
Pavlin Radoslavov706add22014-02-20 12:15:59 -0800309 //
Pavlin Radoslavov8ffb8bf2014-02-20 15:34:26 -0800310 // Network Graph modifications completed: Release the lock
311 //
312 networkGraph.releaseWriteLock();
313
314 //
Pavlin Radoslavov74986ce2014-02-20 13:17:20 -0800315 // Dispatch the Topology Notification Events to the applications
316 //
317 dispatchNetworkGraphEvents();
Pavlin Radoslavov721a2e02014-02-14 23:40:14 -0800318 }
319
320 /**
321 * Receive a notification that an entry is added.
322 *
323 * @param value the value for the entry.
324 */
325 @Override
326 public void entryAdded(TopologyEvent value) {
327 EventEntry<TopologyEvent> eventEntry =
328 new EventEntry<TopologyEvent>(EventEntry.Type.ENTRY_ADD,
329 value);
330 topologyEvents.add(eventEntry);
331 }
332
333 /**
334 * Receive a notification that an entry is removed.
335 *
336 * @param value the value for the entry.
337 */
338 @Override
339 public void entryRemoved(TopologyEvent value) {
340 EventEntry<TopologyEvent> eventEntry =
341 new EventEntry<TopologyEvent>(EventEntry.Type.ENTRY_REMOVE,
342 value);
343 topologyEvents.add(eventEntry);
344 }
345
346 /**
347 * Receive a notification that an entry is updated.
348 *
349 * @param value the value for the entry.
350 */
351 @Override
352 public void entryUpdated(TopologyEvent value) {
353 // NOTE: The ADD and UPDATE events are processed in same way
354 entryAdded(value);
355 }
356 }
357
358 /**
359 * Startup processing.
360 *
361 * @param datagridService the datagrid service to use.
362 */
363 void startup(IDatagridService datagridService) {
364 eventChannel = datagridService.addListener(EVENT_CHANNEL_NAME,
365 eventHandler,
366 byte[].class,
367 TopologyEvent.class);
368 eventHandler.start();
369 }
370
Pavlin Radoslavov74986ce2014-02-20 13:17:20 -0800371 /**
372 * Dispatch Network Graph Events to the listeners.
373 */
374 private void dispatchNetworkGraphEvents() {
375 if (apiAddedSwitchEvents.isEmpty() &&
376 apiRemovedSwitchEvents.isEmpty() &&
377 apiAddedPortEvents.isEmpty() &&
378 apiRemovedPortEvents.isEmpty() &&
379 apiAddedLinkEvents.isEmpty() &&
380 apiRemovedLinkEvents.isEmpty() &&
381 apiAddedDeviceEvents.isEmpty() &&
382 apiRemovedDeviceEvents.isEmpty()) {
383 return; // No events to dispatch
384 }
385
386 // Deliver the events
387 for (INetworkGraphListener listener : this.networkGraphListeners) {
388 // TODO: Should copy before handing them over to listener?
389 listener.networkGraphEvents(apiAddedSwitchEvents,
390 apiRemovedSwitchEvents,
391 apiAddedPortEvents,
392 apiRemovedPortEvents,
393 apiAddedLinkEvents,
394 apiRemovedLinkEvents,
395 apiAddedDeviceEvents,
396 apiRemovedDeviceEvents);
397 }
398
399 //
400 // Cleanup
401 //
402 apiAddedSwitchEvents.clear();
403 apiRemovedSwitchEvents.clear();
404 apiAddedPortEvents.clear();
405 apiRemovedPortEvents.clear();
406 apiAddedLinkEvents.clear();
407 apiRemovedLinkEvents.clear();
408 apiAddedDeviceEvents.clear();
409 apiRemovedDeviceEvents.clear();
410 }
411
412 /**
413 * Apply reordered events.
414 *
415 * @param hasAddedSwitchEvents true if there were Added Switch Events.
416 * @param hasAddedPortEvents true if there were Added Port Events.
417 */
418 private void applyReorderedEvents(boolean hasAddedSwitchEvents,
419 boolean hasAddedPortEvents) {
420 if (! (hasAddedSwitchEvents || hasAddedPortEvents))
421 return; // Nothing to do
422
423 //
424 // Try to apply the reordered events.
425 //
426 // NOTE: For simplicity we try to apply all events of a particular
427 // type if any "parent" type event was processed:
428 // - Apply reordered Port Events if Switches were added
429 // - Apply reordered Link and Device Events if Switches or Ports
430 // were added
431 //
432 Map<ByteBuffer, PortEvent> portEvents = reorderedAddedPortEvents;
433 Map<ByteBuffer, LinkEvent> linkEvents = reorderedAddedLinkEvents;
434 Map<ByteBuffer, DeviceEvent> deviceEvents = reorderedAddedDeviceEvents;
435 reorderedAddedPortEvents = new HashMap<>();
436 reorderedAddedLinkEvents = new HashMap<>();
437 reorderedAddedDeviceEvents = new HashMap<>();
438 //
439 // Apply reordered Port Events if Switches were added
440 //
441 if (hasAddedSwitchEvents) {
442 for (PortEvent portEvent : portEvents.values())
443 addPort(portEvent);
444 }
445 //
446 // Apply reordered Link and Device Events if Switches or Ports
447 // were added.
448 //
449 for (LinkEvent linkEvent : linkEvents.values())
450 addLink(linkEvent);
451 for (DeviceEvent deviceEvent : deviceEvents.values())
452 addDevice(deviceEvent);
453 }
454
Jonathan Hart22eb9882014-02-11 15:52:59 -0800455 /* ******************************
456 * NetworkGraphDiscoveryInterface methods
457 * ******************************/
Yuta HIGUCHIcd922f42014-02-11 18:59:11 -0800458
Pavlin Radoslavovc1cfde52014-02-19 11:35:29 -0800459 @Override
Pavlin Radoslavov018d5332014-02-19 23:08:35 -0800460 public void putSwitchDiscoveryEvent(SwitchEvent switchEvent,
461 Collection<PortEvent> portEvents) {
462 if (datastore.addSwitch(switchEvent, portEvents)) {
Pavlin Radoslavovc1cfde52014-02-19 11:35:29 -0800463 // Send out notification
Pavlin Radoslavov87dcc262014-02-19 21:13:23 -0800464 TopologyEvent topologyEvent = new TopologyEvent(switchEvent);
Pavlin Radoslavovc1cfde52014-02-19 11:35:29 -0800465 eventChannel.addEntry(topologyEvent.getID(), topologyEvent);
Pavlin Radoslavov018d5332014-02-19 23:08:35 -0800466
Pavlin Radoslavov26d83402014-02-20 15:24:30 -0800467 // Send out notification for each port
Pavlin Radoslavov018d5332014-02-19 23:08:35 -0800468 for (PortEvent portEvent : portEvents) {
469 topologyEvent = new TopologyEvent(portEvent);
470 eventChannel.addEntry(topologyEvent.getID(), topologyEvent);
471 }
Pavlin Radoslavov26d83402014-02-20 15:24:30 -0800472
473 //
474 // Keep track of the added ports
475 //
476 // Get the old Port Events
477 Map<ByteBuffer, PortEvent> oldPortEvents =
478 discoveredAddedPortEvents.get(switchEvent.getDpid());
479 if (oldPortEvents == null)
480 oldPortEvents = new HashMap<>();
481
482 // Store the new Port Events in the local cache
483 Map<ByteBuffer, PortEvent> newPortEvents = new HashMap<>();
484 for (PortEvent portEvent : portEvents) {
485 ByteBuffer id = ByteBuffer.wrap(portEvent.getID());
486 newPortEvents.put(id, portEvent);
487 }
488 discoveredAddedPortEvents.put(switchEvent.getDpid(),
489 newPortEvents);
490
491 //
492 // Extract the removed ports
493 //
494 List<PortEvent> removedPortEvents = new LinkedList<>();
495 for (Map.Entry<ByteBuffer, PortEvent> entry : oldPortEvents.entrySet()) {
496 ByteBuffer key = entry.getKey();
497 PortEvent portEvent = entry.getValue();
498 if (! newPortEvents.containsKey(key))
499 removedPortEvents.add(portEvent);
500 }
501
502 // Cleanup old removed ports
503 for (PortEvent portEvent : removedPortEvents)
504 removePortDiscoveryEvent(portEvent);
Pavlin Radoslavovc1cfde52014-02-19 11:35:29 -0800505 }
Pavlin Radoslavovc1cfde52014-02-19 11:35:29 -0800506 }
507
508 @Override
Pavlin Radoslavov6ea84a42014-02-19 15:50:01 -0800509 public void removeSwitchDiscoveryEvent(SwitchEvent switchEvent) {
Pavlin Radoslavov26d83402014-02-20 15:24:30 -0800510 // Get the old Port Events
511 Map<ByteBuffer, PortEvent> oldPortEvents =
512 discoveredAddedPortEvents.get(switchEvent.getDpid());
513 if (oldPortEvents == null)
514 oldPortEvents = new HashMap<>();
Pavlin Radoslavov018d5332014-02-19 23:08:35 -0800515
Pavlin Radoslavov26d83402014-02-20 15:24:30 -0800516 if (datastore.deactivateSwitch(switchEvent, oldPortEvents.values())) {
Pavlin Radoslavovc1cfde52014-02-19 11:35:29 -0800517 // Send out notification
518 eventChannel.removeEntry(switchEvent.getID());
Pavlin Radoslavov018d5332014-02-19 23:08:35 -0800519
Pavlin Radoslavov26d83402014-02-20 15:24:30 -0800520 // Send out notification for each port
521 for (PortEvent portEvent : oldPortEvents.values())
Pavlin Radoslavov018d5332014-02-19 23:08:35 -0800522 eventChannel.removeEntry(portEvent.getID());
Pavlin Radoslavov26d83402014-02-20 15:24:30 -0800523 discoveredAddedPortEvents.remove(switchEvent.getDpid());
524
525 // Cleanup for each link
526 Map<ByteBuffer, LinkEvent> oldLinkEvents =
527 discoveredAddedLinkEvents.get(switchEvent.getDpid());
528 if (oldLinkEvents != null) {
529 for (LinkEvent linkEvent : oldLinkEvents.values())
530 removeLinkDiscoveryEvent(linkEvent);
531 discoveredAddedLinkEvents.remove(switchEvent.getDpid());
532 }
533
534 // Cleanup for each device
535 Map<ByteBuffer, DeviceEvent> oldDeviceEvents =
536 discoveredAddedDeviceEvents.get(switchEvent.getDpid());
537 if (oldDeviceEvents != null) {
538 for (DeviceEvent deviceEvent : oldDeviceEvents.values())
539 removeDeviceDiscoveryEvent(deviceEvent);
540 discoveredAddedDeviceEvents.remove(switchEvent.getDpid());
Pavlin Radoslavov018d5332014-02-19 23:08:35 -0800541 }
Pavlin Radoslavovc1cfde52014-02-19 11:35:29 -0800542 }
Pavlin Radoslavovc1cfde52014-02-19 11:35:29 -0800543 }
544
545 @Override
Pavlin Radoslavov6ea84a42014-02-19 15:50:01 -0800546 public void putPortDiscoveryEvent(PortEvent portEvent) {
Pavlin Radoslavov50cd1482014-02-19 16:57:03 -0800547 if (datastore.addPort(portEvent)) {
Pavlin Radoslavovc1cfde52014-02-19 11:35:29 -0800548 // Send out notification
Pavlin Radoslavov87dcc262014-02-19 21:13:23 -0800549 TopologyEvent topologyEvent = new TopologyEvent(portEvent);
Pavlin Radoslavov018d5332014-02-19 23:08:35 -0800550 eventChannel.addEntry(topologyEvent.getID(), topologyEvent);
Pavlin Radoslavov26d83402014-02-20 15:24:30 -0800551
552 // Store the new Port Event in the local cache
553 Map<ByteBuffer, PortEvent> oldPortEvents =
554 discoveredAddedPortEvents.get(portEvent.getDpid());
555 if (oldPortEvents == null) {
556 oldPortEvents = new HashMap<>();
557 discoveredAddedPortEvents.put(portEvent.getDpid(),
558 oldPortEvents);
559 }
560 ByteBuffer id = ByteBuffer.wrap(portEvent.getID());
561 oldPortEvents.put(id, portEvent);
Pavlin Radoslavovc1cfde52014-02-19 11:35:29 -0800562 }
Pavlin Radoslavovc1cfde52014-02-19 11:35:29 -0800563 }
564
565 @Override
Pavlin Radoslavov6ea84a42014-02-19 15:50:01 -0800566 public void removePortDiscoveryEvent(PortEvent portEvent) {
Pavlin Radoslavov50cd1482014-02-19 16:57:03 -0800567 if (datastore.deactivatePort(portEvent)) {
Pavlin Radoslavovc1cfde52014-02-19 11:35:29 -0800568 // Send out notification
569 eventChannel.removeEntry(portEvent.getID());
Pavlin Radoslavov26d83402014-02-20 15:24:30 -0800570
571 // Cleanup the Port Event from the local cache
572 Map<ByteBuffer, PortEvent> oldPortEvents =
573 discoveredAddedPortEvents.get(portEvent.getDpid());
574 if (oldPortEvents != null) {
575 ByteBuffer id = ByteBuffer.wrap(portEvent.getID());
576 oldPortEvents.remove(id);
577 }
578
579 // Cleanup for the incoming link
580 Map<ByteBuffer, LinkEvent> oldLinkEvents =
581 discoveredAddedLinkEvents.get(portEvent.getDpid());
582 if (oldLinkEvents != null) {
583 for (LinkEvent linkEvent : oldLinkEvents.values()) {
584 if (linkEvent.getDst().equals(portEvent.id)) {
585 removeLinkDiscoveryEvent(linkEvent);
586 //
587 // NOTE: oldLinkEvents was modified by
588 // removeLinkDiscoveryEvent() and cannot be iterated
589 // anymore.
590 //
591 break;
592 }
593 }
594 }
595
596 // Cleanup for the connected devices
597 // TODO: The implementation below is probably wrong
598 List<DeviceEvent> removedDeviceEvents = new LinkedList<>();
599 Map<ByteBuffer, DeviceEvent> oldDeviceEvents =
600 discoveredAddedDeviceEvents.get(portEvent.getDpid());
601 if (oldDeviceEvents != null) {
602 for (DeviceEvent deviceEvent : oldDeviceEvents.values()) {
603 for (SwitchPort swp : deviceEvent.getAttachmentPoints()) {
604 if (swp.equals(portEvent.id)) {
605 removedDeviceEvents.add(deviceEvent);
606 break;
607 }
608 }
609 }
610 for (DeviceEvent deviceEvent : removedDeviceEvents)
611 removeDeviceDiscoveryEvent(deviceEvent);
612 }
Pavlin Radoslavovc1cfde52014-02-19 11:35:29 -0800613 }
Pavlin Radoslavovc1cfde52014-02-19 11:35:29 -0800614 }
615
616 @Override
Pavlin Radoslavov6ea84a42014-02-19 15:50:01 -0800617 public void putLinkDiscoveryEvent(LinkEvent linkEvent) {
Pavlin Radoslavov50cd1482014-02-19 16:57:03 -0800618 if (datastore.addLink(linkEvent)) {
Pavlin Radoslavovc1cfde52014-02-19 11:35:29 -0800619 // Send out notification
Pavlin Radoslavov87dcc262014-02-19 21:13:23 -0800620 TopologyEvent topologyEvent = new TopologyEvent(linkEvent);
Pavlin Radoslavovc1cfde52014-02-19 11:35:29 -0800621 eventChannel.addEntry(topologyEvent.getID(), topologyEvent);
Pavlin Radoslavov26d83402014-02-20 15:24:30 -0800622
623 // Store the new Link Event in the local cache
624 Map<ByteBuffer, LinkEvent> oldLinkEvents =
625 discoveredAddedLinkEvents.get(linkEvent.getDst().getDpid());
626 if (oldLinkEvents == null) {
627 oldLinkEvents = new HashMap<>();
628 discoveredAddedLinkEvents.put(linkEvent.getDst().getDpid(),
629 oldLinkEvents);
630 }
631 ByteBuffer id = ByteBuffer.wrap(linkEvent.getID());
632 oldLinkEvents.put(id, linkEvent);
Pavlin Radoslavovc1cfde52014-02-19 11:35:29 -0800633 }
Pavlin Radoslavovc1cfde52014-02-19 11:35:29 -0800634 }
635
636 @Override
Pavlin Radoslavov6ea84a42014-02-19 15:50:01 -0800637 public void removeLinkDiscoveryEvent(LinkEvent linkEvent) {
Pavlin Radoslavov50cd1482014-02-19 16:57:03 -0800638 if (datastore.removeLink(linkEvent)) {
Pavlin Radoslavovc1cfde52014-02-19 11:35:29 -0800639 // Send out notification
640 eventChannel.removeEntry(linkEvent.getID());
Pavlin Radoslavov26d83402014-02-20 15:24:30 -0800641
642 // Cleanup the Link Event from the local cache
643 Map<ByteBuffer, LinkEvent> oldLinkEvents =
644 discoveredAddedLinkEvents.get(linkEvent.getDst().getDpid());
645 if (oldLinkEvents != null) {
646 ByteBuffer id = ByteBuffer.wrap(linkEvent.getID());
647 oldLinkEvents.remove(id);
648 }
Jonathan Hart22eb9882014-02-11 15:52:59 -0800649 }
Pavlin Radoslavovc1cfde52014-02-19 11:35:29 -0800650 }
Jonathan Hart22eb9882014-02-11 15:52:59 -0800651
Pavlin Radoslavovc1cfde52014-02-19 11:35:29 -0800652 @Override
Pavlin Radoslavov6ea84a42014-02-19 15:50:01 -0800653 public void putDeviceDiscoveryEvent(DeviceEvent deviceEvent) {
Pavlin Radoslavov50cd1482014-02-19 16:57:03 -0800654 if (datastore.addDevice(deviceEvent)) {
Pavlin Radoslavovc1cfde52014-02-19 11:35:29 -0800655 // Send out notification
Pavlin Radoslavov87dcc262014-02-19 21:13:23 -0800656 TopologyEvent topologyEvent = new TopologyEvent(deviceEvent);
Pavlin Radoslavov50cd1482014-02-19 16:57:03 -0800657 eventChannel.addEntry(topologyEvent.getID(), topologyEvent);
Pavlin Radoslavov26d83402014-02-20 15:24:30 -0800658
659 // Store the new Device Event in the local cache
660 // TODO: The implementation below is probably wrong
661 for (SwitchPort swp : deviceEvent.getAttachmentPoints()) {
662 Map<ByteBuffer, DeviceEvent> oldDeviceEvents =
663 discoveredAddedDeviceEvents.get(swp.getDpid());
664 if (oldDeviceEvents == null) {
665 oldDeviceEvents = new HashMap<>();
666 discoveredAddedDeviceEvents.put(swp.getDpid(),
667 oldDeviceEvents);
668 }
669 ByteBuffer id = ByteBuffer.wrap(deviceEvent.getID());
670 oldDeviceEvents.put(id, deviceEvent);
671 }
Jonathan Hart22eb9882014-02-11 15:52:59 -0800672 }
Pavlin Radoslavovc1cfde52014-02-19 11:35:29 -0800673 }
Jonathan Hart22eb9882014-02-11 15:52:59 -0800674
Pavlin Radoslavovc1cfde52014-02-19 11:35:29 -0800675 @Override
Pavlin Radoslavov6ea84a42014-02-19 15:50:01 -0800676 public void removeDeviceDiscoveryEvent(DeviceEvent deviceEvent) {
Pavlin Radoslavov50cd1482014-02-19 16:57:03 -0800677 if (datastore.removeDevice(deviceEvent)) {
Pavlin Radoslavovc1cfde52014-02-19 11:35:29 -0800678 // Send out notification
679 eventChannel.removeEntry(deviceEvent.getID());
Pavlin Radoslavov26d83402014-02-20 15:24:30 -0800680
681 // Cleanup the Device Event from the local cache
682 // TODO: The implementation below is probably wrong
683 ByteBuffer id = ByteBuffer.wrap(deviceEvent.getID());
684 for (SwitchPort swp : deviceEvent.getAttachmentPoints()) {
685 Map<ByteBuffer, DeviceEvent> oldDeviceEvents =
686 discoveredAddedDeviceEvents.get(swp.getDpid());
687 if (oldDeviceEvents != null) {
688 oldDeviceEvents.remove(id);
689 }
690 }
Jonathan Hart22eb9882014-02-11 15:52:59 -0800691 }
Pavlin Radoslavovc1cfde52014-02-19 11:35:29 -0800692 }
Jonathan Hart22eb9882014-02-11 15:52:59 -0800693
Pavlin Radoslavov3c9cc552014-02-20 09:58:38 -0800694 /* ************************************************
695 * Internal methods to maintain the network graph
696 * ************************************************/
Pavlin Radoslavov74986ce2014-02-20 13:17:20 -0800697 private void addSwitch(SwitchEvent switchEvent) {
698 Switch sw = networkGraph.getSwitch(switchEvent.getDpid());
Pavlin Radoslavov3c9cc552014-02-20 09:58:38 -0800699 if (sw == null) {
Pavlin Radoslavov74986ce2014-02-20 13:17:20 -0800700 sw = new SwitchImpl(networkGraph, switchEvent.getDpid());
Pavlin Radoslavov3c9cc552014-02-20 09:58:38 -0800701 networkGraph.putSwitch(sw);
702 } else {
703 // TODO: Update the switch attributes
704 // TODO: Nothing to do for now
705 }
Pavlin Radoslavov74986ce2014-02-20 13:17:20 -0800706 apiAddedSwitchEvents.add(switchEvent);
Pavlin Radoslavov3c9cc552014-02-20 09:58:38 -0800707 }
708
Pavlin Radoslavov74986ce2014-02-20 13:17:20 -0800709 private void removeSwitch(SwitchEvent switchEvent) {
710 Switch sw = networkGraph.getSwitch(switchEvent.getDpid());
Pavlin Radoslavov3c9cc552014-02-20 09:58:38 -0800711 if (sw == null) {
Pavlin Radoslavov74986ce2014-02-20 13:17:20 -0800712 log.warn("Switch {} already removed, ignoring", switchEvent);
Pavlin Radoslavov3c9cc552014-02-20 09:58:38 -0800713 return;
714 }
715
716 //
717 // Remove all Ports on the Switch
718 //
719 ArrayList<PortEvent> portsToRemove = new ArrayList<>();
720 for (Port port : sw.getPorts()) {
721 log.warn("Port {} on Switch {} should be removed prior to removing Switch. Removing Port now.",
Pavlin Radoslavov74986ce2014-02-20 13:17:20 -0800722 port, switchEvent);
Pavlin Radoslavov3c9cc552014-02-20 09:58:38 -0800723 PortEvent portEvent = new PortEvent(port.getDpid(),
724 port.getNumber());
725 portsToRemove.add(portEvent);
726 }
727 for (PortEvent portEvent : portsToRemove)
728 removePort(portEvent);
729
Pavlin Radoslavov74986ce2014-02-20 13:17:20 -0800730 networkGraph.removeSwitch(switchEvent.getDpid());
731 apiRemovedSwitchEvents.add(switchEvent);
Pavlin Radoslavov3c9cc552014-02-20 09:58:38 -0800732 }
733
734 private void addPort(PortEvent portEvent) {
735 Switch sw = networkGraph.getSwitch(portEvent.getDpid());
736 if (sw == null) {
Pavlin Radoslavov706add22014-02-20 12:15:59 -0800737 // Reordered event: delay the event in local cache
738 ByteBuffer id = ByteBuffer.wrap(portEvent.getID());
739 reorderedAddedPortEvents.put(id, portEvent);
Pavlin Radoslavov3c9cc552014-02-20 09:58:38 -0800740 return;
741 }
742 SwitchImpl switchImpl = getSwitchImpl(sw);
743
744 Port port = sw.getPort(portEvent.getNumber());
745 if (port == null) {
746 port = new PortImpl(networkGraph, sw, portEvent.getNumber());
747 switchImpl.addPort(port);
748 } else {
749 // TODO: Update the port attributes
750 }
Pavlin Radoslavov74986ce2014-02-20 13:17:20 -0800751 apiAddedPortEvents.add(portEvent);
Pavlin Radoslavov3c9cc552014-02-20 09:58:38 -0800752 }
753
754 private void removePort(PortEvent portEvent) {
755 Switch sw = networkGraph.getSwitch(portEvent.getDpid());
756 if (sw == null) {
757 log.warn("Parent Switch for Port {} already removed, ignoring",
758 portEvent);
759 return;
760 }
761
762 Port port = sw.getPort(portEvent.getNumber());
763 if (port == null) {
764 log.warn("Port {} already removed, ignoring", portEvent);
765 return;
766 }
767
768 //
769 // Remove all Devices attached to the Port
770 //
771 ArrayList<DeviceEvent> devicesToRemove = new ArrayList<>();
772 for (Device device : port.getDevices()) {
773 log.debug("Removing Device {} on Port {}", device, portEvent);
774 DeviceEvent deviceEvent = new DeviceEvent(device.getMacAddress());
775 SwitchPort switchPort = new SwitchPort(port.getSwitch().getDpid(),
776 port.getNumber());
777 deviceEvent.addAttachmentPoint(switchPort);
778 devicesToRemove.add(deviceEvent);
779 }
780 for (DeviceEvent deviceEvent : devicesToRemove)
781 removeDevice(deviceEvent);
782
783 //
784 // Remove all Links connected to the Port
785 //
786 Set<Link> links = new HashSet<>();
787 links.add(port.getOutgoingLink());
788 links.add(port.getIncomingLink());
789 ArrayList<LinkEvent> linksToRemove = new ArrayList<>();
790 for (Link link : links) {
791 if (link == null)
792 continue;
793 log.debug("Removing Link {} on Port {}", link, portEvent);
794 LinkEvent linkEvent = new LinkEvent(link.getSrcSwitch().getDpid(),
795 link.getSrcPort().getNumber(),
796 link.getDstSwitch().getDpid(),
797 link.getDstPort().getNumber());
798 linksToRemove.add(linkEvent);
799 }
800 for (LinkEvent linkEvent : linksToRemove)
801 removeLink(linkEvent);
802
803 // Remove the Port from the Switch
804 SwitchImpl switchImpl = getSwitchImpl(sw);
805 switchImpl.removePort(port);
Pavlin Radoslavov74986ce2014-02-20 13:17:20 -0800806
807 apiRemovedPortEvents.add(portEvent);
Pavlin Radoslavov3c9cc552014-02-20 09:58:38 -0800808 }
809
810 private void addLink(LinkEvent linkEvent) {
811 Port srcPort = networkGraph.getPort(linkEvent.getSrc().dpid,
812 linkEvent.getSrc().number);
Pavlin Radoslavov3c9cc552014-02-20 09:58:38 -0800813 Port dstPort = networkGraph.getPort(linkEvent.getDst().dpid,
814 linkEvent.getDst().number);
Pavlin Radoslavov706add22014-02-20 12:15:59 -0800815 if ((srcPort == null) || (dstPort == null)) {
816 // Reordered event: delay the event in local cache
817 ByteBuffer id = ByteBuffer.wrap(linkEvent.getID());
818 reorderedAddedLinkEvents.put(id, linkEvent);
Pavlin Radoslavov3c9cc552014-02-20 09:58:38 -0800819 return;
820 }
821
822 // Get the Link instance from the Destination Port Incoming Link
823 Link link = dstPort.getIncomingLink();
824 assert(link == srcPort.getOutgoingLink());
825 if (link == null) {
826 link = new LinkImpl(networkGraph, srcPort, dstPort);
827 PortImpl srcPortImpl = getPortImpl(srcPort);
828 PortImpl dstPortImpl = getPortImpl(dstPort);
829 srcPortImpl.setOutgoingLink(link);
830 dstPortImpl.setIncomingLink(link);
831
832 // Remove all Devices attached to the Ports
833 ArrayList<DeviceEvent> devicesToRemove = new ArrayList<>();
834 ArrayList<Port> ports = new ArrayList<>();
835 ports.add(srcPort);
836 ports.add(dstPort);
837 for (Port port : ports) {
838 for (Device device : port.getDevices()) {
839 log.error("Device {} on Port {} should have been removed prior to adding Link {}",
840 device, port, linkEvent);
841 DeviceEvent deviceEvent =
842 new DeviceEvent(device.getMacAddress());
843 SwitchPort switchPort =
844 new SwitchPort(port.getSwitch().getDpid(),
845 port.getNumber());
846 deviceEvent.addAttachmentPoint(switchPort);
847 devicesToRemove.add(deviceEvent);
848 }
849 }
850 for (DeviceEvent deviceEvent : devicesToRemove)
851 removeDevice(deviceEvent);
852 } else {
853 // TODO: Update the link attributes
854 }
Pavlin Radoslavov74986ce2014-02-20 13:17:20 -0800855
856 apiAddedLinkEvents.add(linkEvent);
Pavlin Radoslavov3c9cc552014-02-20 09:58:38 -0800857 }
858
859 private void removeLink(LinkEvent linkEvent) {
860 Port srcPort = networkGraph.getPort(linkEvent.getSrc().dpid,
861 linkEvent.getSrc().number);
862 if (srcPort == null) {
863 log.warn("Src Port for Link {} already removed, ignoring",
864 linkEvent);
865 return;
866 }
867
868 Port dstPort = networkGraph.getPort(linkEvent.getDst().dpid,
869 linkEvent.getDst().number);
870 if (dstPort == null) {
871 log.warn("Dst Port for Link {} already removed, ignoring",
872 linkEvent);
873 return;
874 }
875
876 //
877 // Remove the Link instance from the Destination Port Incoming Link
878 // and the Source Port Outgoing Link.
879 //
880 Link link = dstPort.getIncomingLink();
881 if (link == null) {
882 log.warn("Link {} already removed on destination Port", linkEvent);
883 }
884 link = srcPort.getOutgoingLink();
885 if (link == null) {
886 log.warn("Link {} already removed on src Port", linkEvent);
887 }
888 getPortImpl(dstPort).setIncomingLink(null);
889 getPortImpl(srcPort).setOutgoingLink(null);
Pavlin Radoslavov74986ce2014-02-20 13:17:20 -0800890
891 apiRemovedLinkEvents.add(linkEvent);
Pavlin Radoslavov3c9cc552014-02-20 09:58:38 -0800892 }
893
894 // TODO: Device-related work is incomplete
895 private void addDevice(DeviceEvent deviceEvent) {
896 Device device = networkGraph.getDeviceByMac(deviceEvent.getMac());
897 if (device == null) {
898 device = new DeviceImpl(networkGraph, deviceEvent.getMac());
899 }
900 DeviceImpl deviceImpl = getDeviceImpl(device);
901
902 // Update the IP addresses
903 for (InetAddress ipAddr : deviceEvent.getIpAddresses())
904 deviceImpl.addIpAddress(ipAddr);
905
906 // Process each attachment point
907 boolean attachmentFound = false;
908 for (SwitchPort swp : deviceEvent.getAttachmentPoints()) {
909 // Attached Ports must exist
910 Port port = networkGraph.getPort(swp.dpid, swp.number);
911 if (port == null) {
Pavlin Radoslavov706add22014-02-20 12:15:59 -0800912 // Reordered event: delay the event in local cache
913 ByteBuffer id = ByteBuffer.wrap(deviceEvent.getID());
914 reorderedAddedDeviceEvents.put(id, deviceEvent);
Pavlin Radoslavov3c9cc552014-02-20 09:58:38 -0800915 continue;
916 }
917 // Attached Ports must not have Link
918 if (port.getOutgoingLink() != null ||
919 port.getIncomingLink() != null) {
920 log.warn("Link (Out:{},In:{}) exist on the attachment point, skipping mutation.",
921 port.getOutgoingLink(),
922 port.getIncomingLink());
923 continue;
924 }
925
926 // Add Device <-> Port attachment
927 PortImpl portImpl = getPortImpl(port);
928 portImpl.addDevice(device);
929 deviceImpl.addAttachmentPoint(port);
930 attachmentFound = true;
931 }
932
933 // Update the device in the Network Graph
Pavlin Radoslavov74986ce2014-02-20 13:17:20 -0800934 if (attachmentFound) {
Pavlin Radoslavov3c9cc552014-02-20 09:58:38 -0800935 networkGraph.putDevice(device);
Pavlin Radoslavov74986ce2014-02-20 13:17:20 -0800936 apiAddedDeviceEvents.add(deviceEvent);
937 }
Pavlin Radoslavov3c9cc552014-02-20 09:58:38 -0800938 }
939
940 private void removeDevice(DeviceEvent deviceEvent) {
941 Device device = networkGraph.getDeviceByMac(deviceEvent.getMac());
942 if (device == null) {
943 log.warn("Device {} already removed, ignoring", deviceEvent);
944 return;
945 }
946 DeviceImpl deviceImpl = getDeviceImpl(device);
947
948 // Process each attachment point
949 for (SwitchPort swp : deviceEvent.getAttachmentPoints()) {
950 // Attached Ports must exist
951 Port port = networkGraph.getPort(swp.dpid, swp.number);
952 if (port == null) {
953 log.warn("Port for the attachment point {} did not exist. skipping attachment point mutation", swp);
954 continue;
955 }
956
957 // Remove Device <-> Port attachment
958 PortImpl portImpl = getPortImpl(port);
959 portImpl.removeDevice(device);
960 deviceImpl.removeAttachmentPoint(port);
961 }
Pavlin Radoslavov74986ce2014-02-20 13:17:20 -0800962
Pavlin Radoslavov3c9cc552014-02-20 09:58:38 -0800963 networkGraph.removeDevice(device);
Pavlin Radoslavov74986ce2014-02-20 13:17:20 -0800964 apiRemovedDeviceEvents.add(deviceEvent);
Pavlin Radoslavov3c9cc552014-02-20 09:58:38 -0800965 }
Jonathan Hart22eb9882014-02-11 15:52:59 -0800966
Pavlin Radoslavovc1cfde52014-02-19 11:35:29 -0800967 /**
968 *
Pavlin Radoslavov74986ce2014-02-20 13:17:20 -0800969 * @param switchEvent
Pavlin Radoslavovc1cfde52014-02-19 11:35:29 -0800970 * @return true if ready to accept event.
971 */
Pavlin Radoslavov74986ce2014-02-20 13:17:20 -0800972 private boolean prepareForAddSwitchEvent(SwitchEvent switchEvent) {
Pavlin Radoslavovc1cfde52014-02-19 11:35:29 -0800973 // No show stopping precondition
Pavlin Radoslavovc1cfde52014-02-19 11:35:29 -0800974 return true;
975 }
Jonathan Hart22eb9882014-02-11 15:52:59 -0800976
Pavlin Radoslavov74986ce2014-02-20 13:17:20 -0800977 private boolean prepareForRemoveSwitchEvent(SwitchEvent switchEvent) {
Pavlin Radoslavovc1cfde52014-02-19 11:35:29 -0800978 // No show stopping precondition
Pavlin Radoslavovc1cfde52014-02-19 11:35:29 -0800979 return true;
980 }
Yuta HIGUCHI71e7a052014-02-17 22:14:15 -0800981
Pavlin Radoslavovc1cfde52014-02-19 11:35:29 -0800982 private boolean prepareForAddPortEvent(PortEvent portEvent) {
983 // Parent Switch must exist
984 if (networkGraph.getSwitch(portEvent.getDpid()) == null) {
985 log.warn("Dropping add port event because switch doesn't exist: {}",
986 portEvent);
987 return false;
988 }
989 // Prep: None
990 return true;
991 }
992
993 private boolean prepareForRemovePortEvent(PortEvent portEvent) {
994 Port port = networkGraph.getPort(portEvent.getDpid(),
995 portEvent.getNumber());
996 if (port == null) {
997 log.debug("Port already removed? {}", portEvent);
998 // let it pass
999 return true;
Jonathan Hart22eb9882014-02-11 15:52:59 -08001000 }
Yuta HIGUCHIcd922f42014-02-11 18:59:11 -08001001
Pavlin Radoslavovc1cfde52014-02-19 11:35:29 -08001002 // Prep: Remove Link and Device Attachment
1003 ArrayList<DeviceEvent> deviceEvents = new ArrayList<>();
1004 for (Device device : port.getDevices()) {
1005 log.debug("Removing Device {} on Port {}", device, portEvent);
1006 DeviceEvent devEvent = new DeviceEvent(device.getMacAddress());
1007 devEvent.addAttachmentPoint(new SwitchPort(port.getSwitch().getDpid(),
1008 port.getNumber()));
1009 deviceEvents.add(devEvent);
1010 }
1011 for (DeviceEvent devEvent : deviceEvents) {
1012 // calling Discovery API to wipe from DB, etc.
Pavlin Radoslavov6ea84a42014-02-19 15:50:01 -08001013 removeDeviceDiscoveryEvent(devEvent);
Jonathan Hart22eb9882014-02-11 15:52:59 -08001014 }
Yuta HIGUCHIcd922f42014-02-11 18:59:11 -08001015
Pavlin Radoslavovc1cfde52014-02-19 11:35:29 -08001016 Set<Link> links = new HashSet<>();
1017 links.add(port.getOutgoingLink());
1018 links.add(port.getIncomingLink());
1019 for (Link link : links) {
1020 if (link == null) {
1021 continue;
1022 }
1023 log.debug("Removing Link {} on Port {}", link, portEvent);
1024 LinkEvent linkEvent =
Pavlin Radoslavov7c8f69a2014-02-19 19:01:45 -08001025 new LinkEvent(link.getSrcSwitch().getDpid(),
1026 link.getSrcPort().getNumber(),
1027 link.getDstSwitch().getDpid(),
1028 link.getDstPort().getNumber());
Pavlin Radoslavovc1cfde52014-02-19 11:35:29 -08001029 // calling Discovery API to wipe from DB, etc.
Yuta HIGUCHI8d762e92014-02-12 14:10:25 -08001030
Pavlin Radoslavovc1cfde52014-02-19 11:35:29 -08001031 // Call internal remove Link, which will check
1032 // ownership of DST dpid and modify DB only if it is the owner
Pavlin Radoslavov6ea84a42014-02-19 15:50:01 -08001033 removeLinkDiscoveryEvent(linkEvent, true);
Jonathan Hart22eb9882014-02-11 15:52:59 -08001034 }
Pavlin Radoslavovc1cfde52014-02-19 11:35:29 -08001035 return true;
1036 }
Yuta HIGUCHIcd922f42014-02-11 18:59:11 -08001037
Pavlin Radoslavovc1cfde52014-02-19 11:35:29 -08001038 private boolean prepareForAddLinkEvent(LinkEvent linkEvent) {
1039 // Src/Dst Port must exist
1040 Port srcPort = networkGraph.getPort(linkEvent.getSrc().dpid,
1041 linkEvent.getSrc().number);
1042 Port dstPort = networkGraph.getPort(linkEvent.getDst().dpid,
1043 linkEvent.getDst().number);
1044 if (srcPort == null || dstPort == null) {
Jonathan Hart0a4846e2014-02-18 11:03:40 -08001045 log.warn("Dropping add link event because port doesn't exist: {}",
Pavlin Radoslavovc1cfde52014-02-19 11:35:29 -08001046 linkEvent);
1047 return false;
Jonathan Hart22eb9882014-02-11 15:52:59 -08001048 }
Yuta HIGUCHIcd922f42014-02-11 18:59:11 -08001049
Pavlin Radoslavovc1cfde52014-02-19 11:35:29 -08001050 // Prep: remove Device attachment on both Ports
1051 ArrayList<DeviceEvent> deviceEvents = new ArrayList<>();
1052 for (Device device : srcPort.getDevices()) {
1053 DeviceEvent devEvent = new DeviceEvent(device.getMacAddress());
1054 devEvent.addAttachmentPoint(new SwitchPort(srcPort.getSwitch().getDpid(), srcPort.getNumber()));
1055 deviceEvents.add(devEvent);
1056 }
1057 for (Device device : dstPort.getDevices()) {
1058 DeviceEvent devEvent = new DeviceEvent(device.getMacAddress());
1059 devEvent.addAttachmentPoint(new SwitchPort(dstPort.getSwitch().getDpid(),
1060 dstPort.getNumber()));
1061 deviceEvents.add(devEvent);
1062 }
1063 for (DeviceEvent devEvent : deviceEvents) {
1064 // calling Discovery API to wipe from DB, etc.
Pavlin Radoslavov6ea84a42014-02-19 15:50:01 -08001065 removeDeviceDiscoveryEvent(devEvent);
Jonathan Hart22eb9882014-02-11 15:52:59 -08001066 }
Yuta HIGUCHIcd922f42014-02-11 18:59:11 -08001067
Pavlin Radoslavovc1cfde52014-02-19 11:35:29 -08001068 return true;
1069 }
Yuta HIGUCHId02e9282014-02-12 09:24:41 -08001070
Pavlin Radoslavovc1cfde52014-02-19 11:35:29 -08001071 private boolean prepareForRemoveLinkEvent(LinkEvent linkEvent) {
1072 // Src/Dst Port must exist
1073 Port srcPort = networkGraph.getPort(linkEvent.getSrc().dpid,
1074 linkEvent.getSrc().number);
1075 Port dstPort = networkGraph.getPort(linkEvent.getDst().dpid,
1076 linkEvent.getDst().number);
1077 if (srcPort == null || dstPort == null) {
1078 log.warn("Dropping remove link event because port doesn't exist {}", linkEvent);
1079 return false;
1080 }
Yuta HIGUCHI8d762e92014-02-12 14:10:25 -08001081
Pavlin Radoslavovc1cfde52014-02-19 11:35:29 -08001082 Link link = srcPort.getOutgoingLink();
1083
1084 // Link is already gone, or different Link exist in memory
1085 // XXX Check if we should reject or just accept these cases.
1086 // it should be harmless to remove the Link on event from DB anyways
1087 if (link == null ||
Pavlin Radoslavov7c8f69a2014-02-19 19:01:45 -08001088 !link.getDstPort().getNumber().equals(linkEvent.getDst().number)
1089 || !link.getDstSwitch().getDpid().equals(linkEvent.getDst().dpid)) {
Pavlin Radoslavovc1cfde52014-02-19 11:35:29 -08001090 log.warn("Dropping remove link event because link doesn't exist: {}", linkEvent);
1091 return false;
1092 }
1093 // Prep: None
1094 return true;
1095 }
1096
1097 /**
1098 *
1099 * @param deviceEvent Event will be modified to remove inapplicable attachemntPoints/ipAddress
1100 * @return false if this event should be dropped.
1101 */
1102 private boolean prepareForAddDeviceEvent(DeviceEvent deviceEvent) {
1103 boolean preconditionBroken = false;
1104 ArrayList<PortEvent.SwitchPort> failedSwitchPort = new ArrayList<>();
1105 for ( PortEvent.SwitchPort swp : deviceEvent.getAttachmentPoints() ) {
1106 // Attached Ports must exist
1107 Port port = networkGraph.getPort(swp.dpid, swp.number);
1108 if (port == null) {
1109 preconditionBroken = true;
1110 failedSwitchPort.add(swp);
1111 continue;
Yuta HIGUCHI8d762e92014-02-12 14:10:25 -08001112 }
Pavlin Radoslavovc1cfde52014-02-19 11:35:29 -08001113 // Attached Ports must not have Link
1114 if (port.getOutgoingLink() != null ||
1115 port.getIncomingLink() != null) {
1116 preconditionBroken = true;
1117 failedSwitchPort.add(swp);
1118 continue;
1119 }
1120 }
1121
1122 // Rewriting event to exclude failed attachmentPoint
1123 // XXX Assumption behind this is that inapplicable device event should
1124 // be dropped, not deferred. If we decide to defer Device event,
1125 // rewriting can become a problem
1126 List<SwitchPort> attachmentPoints = deviceEvent.getAttachmentPoints();
1127 attachmentPoints.removeAll(failedSwitchPort);
1128 deviceEvent.setAttachmentPoints(attachmentPoints);
1129
1130 if (deviceEvent.getAttachmentPoints().isEmpty() &&
1131 deviceEvent.getIpAddresses().isEmpty()) {
1132 // return false to represent: Nothing left to do for this event.
1133 // Caller should drop event
1134 return false;
1135 }
Yuta HIGUCHI8d762e92014-02-12 14:10:25 -08001136
1137 // Should we return false to tell caller that the event was trimmed?
1138 // if ( preconditionBroken ) {
1139 // return false;
1140 // }
1141
Pavlin Radoslavovc1cfde52014-02-19 11:35:29 -08001142 return true;
1143 }
1144
1145 private boolean prepareForRemoveDeviceEvent(DeviceEvent deviceEvent) {
1146 // No show stopping precondition?
1147 // Prep: none
1148 return true;
1149 }
1150
Pavlin Radoslavovc1cfde52014-02-19 11:35:29 -08001151 private SwitchImpl getSwitchImpl(Switch sw) {
1152 if (sw instanceof SwitchImpl) {
1153 return (SwitchImpl) sw;
1154 }
1155 throw new ClassCastException("SwitchImpl expected, but found: " + sw);
1156 }
1157
1158 private PortImpl getPortImpl(Port p) {
1159 if (p instanceof PortImpl) {
1160 return (PortImpl) p;
1161 }
1162 throw new ClassCastException("PortImpl expected, but found: " + p);
1163 }
1164
1165 private LinkImpl getLinkImpl(Link l) {
1166 if (l instanceof LinkImpl) {
1167 return (LinkImpl) l;
1168 }
1169 throw new ClassCastException("LinkImpl expected, but found: " + l);
1170 }
1171
1172 private DeviceImpl getDeviceImpl(Device d) {
1173 if (d instanceof DeviceImpl) {
1174 return (DeviceImpl) d;
1175 }
1176 throw new ClassCastException("DeviceImpl expected, but found: " + d);
1177 }
1178
1179 @Deprecated
Pavlin Radoslavov018d5332014-02-19 23:08:35 -08001180 private Collection<EventEntry<TopologyEvent>> readWholeTopologyFromDB() {
1181 Collection<EventEntry<TopologyEvent>> collection =
1182 new LinkedList<EventEntry<TopologyEvent>>();
1183
Pavlin Radoslavovc1cfde52014-02-19 11:35:29 -08001184 // XXX May need to clear whole topology first, depending on
1185 // how we initially subscribe to replication events
1186
Pavlin Radoslavov018d5332014-02-19 23:08:35 -08001187 // Add all active switches
Pavlin Radoslavovc1cfde52014-02-19 11:35:29 -08001188 for (RCSwitch sw : RCSwitch.getAllSwitches()) {
1189 if (sw.getStatus() != RCSwitch.STATUS.ACTIVE) {
1190 continue;
1191 }
Pavlin Radoslavov018d5332014-02-19 23:08:35 -08001192
1193 SwitchEvent switchEvent = new SwitchEvent(sw.getDpid());
1194 TopologyEvent topologyEvent = new TopologyEvent(switchEvent);
1195 EventEntry<TopologyEvent> eventEntry =
1196 new EventEntry<TopologyEvent>(EventEntry.Type.ENTRY_ADD,
1197 topologyEvent);
1198 collection.add(eventEntry);
Yuta HIGUCHIa536e762014-02-17 21:47:28 -08001199 }
1200
Pavlin Radoslavov018d5332014-02-19 23:08:35 -08001201 // Add all active ports
Pavlin Radoslavovc1cfde52014-02-19 11:35:29 -08001202 for (RCPort p : RCPort.getAllPorts()) {
1203 if (p.getStatus() != RCPort.STATUS.ACTIVE) {
1204 continue;
Yuta HIGUCHIa536e762014-02-17 21:47:28 -08001205 }
Pavlin Radoslavov018d5332014-02-19 23:08:35 -08001206
1207 PortEvent portEvent = new PortEvent(p.getDpid(), p.getNumber());
1208 TopologyEvent topologyEvent = new TopologyEvent(portEvent);
1209 EventEntry<TopologyEvent> eventEntry =
1210 new EventEntry<TopologyEvent>(EventEntry.Type.ENTRY_ADD,
1211 topologyEvent);
1212 collection.add(eventEntry);
Yuta HIGUCHIa536e762014-02-17 21:47:28 -08001213 }
1214
Pavlin Radoslavovc1cfde52014-02-19 11:35:29 -08001215 // TODO Is Device going to be in DB? If so, read from DB.
1216 // for (RCDevice d : RCDevice.getAllDevices()) {
1217 // DeviceEvent devEvent = new DeviceEvent( MACAddress.valueOf(d.getMac()) );
1218 // for (byte[] portId : d.getAllPortIds() ) {
1219 // devEvent.addAttachmentPoint( new SwitchPort( RCPort.getDpidFromKey(portId), RCPort.getNumberFromKey(portId) ));
1220 // }
1221 // }
1222
1223 for (RCLink l : RCLink.getAllLinks()) {
1224 // check if src/dst switch/port exist before triggering event
1225 Port srcPort = networkGraph.getPort(l.getSrc().dpid,
1226 l.getSrc().number);
1227 Port dstPort = networkGraph.getPort(l.getDst().dpid,
1228 l.getDst().number);
1229 if (srcPort == null || dstPort == null) {
1230 continue;
Yuta HIGUCHI76df2472014-02-12 22:36:51 -08001231 }
Pavlin Radoslavov018d5332014-02-19 23:08:35 -08001232
1233 LinkEvent linkEvent = new LinkEvent(l.getSrc().dpid,
1234 l.getSrc().number,
1235 l.getDst().dpid,
1236 l.getDst().number);
1237 TopologyEvent topologyEvent = new TopologyEvent(linkEvent);
1238 EventEntry<TopologyEvent> eventEntry =
1239 new EventEntry<TopologyEvent>(EventEntry.Type.ENTRY_ADD,
1240 topologyEvent);
1241 collection.add(eventEntry);
Yuta HIGUCHI76df2472014-02-12 22:36:51 -08001242 }
Pavlin Radoslavov018d5332014-02-19 23:08:35 -08001243
1244 return collection;
Pavlin Radoslavovc1cfde52014-02-19 11:35:29 -08001245 }
Pavlin Radoslavov50cd1482014-02-19 16:57:03 -08001246
1247 @Deprecated
1248 private void removeLinkDiscoveryEvent(LinkEvent linkEvent,
1249 boolean dstCheckBeforeDBmodify) {
1250 if (prepareForRemoveLinkEvent(linkEvent)) {
1251 if (dstCheckBeforeDBmodify) {
1252 // write to DB only if it is owner of the dst dpid
1253 // XXX this will cause link remove events to be dropped
1254 // if the dst switch just disconnected
1255 if (registryService.hasControl(linkEvent.getDst().dpid)) {
1256 datastore.removeLink(linkEvent);
1257 }
1258 } else {
1259 datastore.removeLink(linkEvent);
1260 }
1261 removeLink(linkEvent);
1262 // Send out notification
1263 eventChannel.removeEntry(linkEvent.getID());
1264 }
1265 // TODO handle invariant violation
1266 }
Jonathan Hart062a2e82014-02-03 09:41:57 -08001267}