blob: e484d88633096374c3840ddff98c78e67c83439d [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 //
272 // Apply the classified events.
273 //
274 // Apply the "add" events in the proper order:
275 // switch, port, link, device
276 //
277 for (SwitchEvent switchEvent : addedSwitchEvents.values())
278 addSwitch(switchEvent);
279 for (PortEvent portEvent : addedPortEvents.values())
280 addPort(portEvent);
281 for (LinkEvent linkEvent : addedLinkEvents.values())
282 addLink(linkEvent);
283 for (DeviceEvent deviceEvent : addedDeviceEvents.values())
284 addDevice(deviceEvent);
285 //
286 // Apply the "remove" events in the reverse order:
287 // device, link, port, switch
288 //
289 for (DeviceEvent deviceEvent : removedDeviceEvents.values())
290 removeDevice(deviceEvent);
291 for (LinkEvent linkEvent : removedLinkEvents.values())
292 removeLink(linkEvent);
293 for (PortEvent portEvent : removedPortEvents.values())
294 removePort(portEvent);
295 for (SwitchEvent switchEvent : removedSwitchEvents.values())
296 removeSwitch(switchEvent);
297
Pavlin Radoslavov3c9cc552014-02-20 09:58:38 -0800298 //
Pavlin Radoslavov74986ce2014-02-20 13:17:20 -0800299 // Apply reordered events
Pavlin Radoslavov3c9cc552014-02-20 09:58:38 -0800300 //
Pavlin Radoslavov74986ce2014-02-20 13:17:20 -0800301 applyReorderedEvents(! addedSwitchEvents.isEmpty(),
302 ! addedPortEvents.isEmpty());
303
Pavlin Radoslavov706add22014-02-20 12:15:59 -0800304 //
Pavlin Radoslavov74986ce2014-02-20 13:17:20 -0800305 // Dispatch the Topology Notification Events to the applications
306 //
307 dispatchNetworkGraphEvents();
Pavlin Radoslavov721a2e02014-02-14 23:40:14 -0800308 }
309
310 /**
311 * Receive a notification that an entry is added.
312 *
313 * @param value the value for the entry.
314 */
315 @Override
316 public void entryAdded(TopologyEvent value) {
317 EventEntry<TopologyEvent> eventEntry =
318 new EventEntry<TopologyEvent>(EventEntry.Type.ENTRY_ADD,
319 value);
320 topologyEvents.add(eventEntry);
321 }
322
323 /**
324 * Receive a notification that an entry is removed.
325 *
326 * @param value the value for the entry.
327 */
328 @Override
329 public void entryRemoved(TopologyEvent value) {
330 EventEntry<TopologyEvent> eventEntry =
331 new EventEntry<TopologyEvent>(EventEntry.Type.ENTRY_REMOVE,
332 value);
333 topologyEvents.add(eventEntry);
334 }
335
336 /**
337 * Receive a notification that an entry is updated.
338 *
339 * @param value the value for the entry.
340 */
341 @Override
342 public void entryUpdated(TopologyEvent value) {
343 // NOTE: The ADD and UPDATE events are processed in same way
344 entryAdded(value);
345 }
346 }
347
348 /**
349 * Startup processing.
350 *
351 * @param datagridService the datagrid service to use.
352 */
353 void startup(IDatagridService datagridService) {
354 eventChannel = datagridService.addListener(EVENT_CHANNEL_NAME,
355 eventHandler,
356 byte[].class,
357 TopologyEvent.class);
358 eventHandler.start();
359 }
360
Pavlin Radoslavov74986ce2014-02-20 13:17:20 -0800361 /**
362 * Dispatch Network Graph Events to the listeners.
363 */
364 private void dispatchNetworkGraphEvents() {
365 if (apiAddedSwitchEvents.isEmpty() &&
366 apiRemovedSwitchEvents.isEmpty() &&
367 apiAddedPortEvents.isEmpty() &&
368 apiRemovedPortEvents.isEmpty() &&
369 apiAddedLinkEvents.isEmpty() &&
370 apiRemovedLinkEvents.isEmpty() &&
371 apiAddedDeviceEvents.isEmpty() &&
372 apiRemovedDeviceEvents.isEmpty()) {
373 return; // No events to dispatch
374 }
375
376 // Deliver the events
377 for (INetworkGraphListener listener : this.networkGraphListeners) {
378 // TODO: Should copy before handing them over to listener?
379 listener.networkGraphEvents(apiAddedSwitchEvents,
380 apiRemovedSwitchEvents,
381 apiAddedPortEvents,
382 apiRemovedPortEvents,
383 apiAddedLinkEvents,
384 apiRemovedLinkEvents,
385 apiAddedDeviceEvents,
386 apiRemovedDeviceEvents);
387 }
388
389 //
390 // Cleanup
391 //
392 apiAddedSwitchEvents.clear();
393 apiRemovedSwitchEvents.clear();
394 apiAddedPortEvents.clear();
395 apiRemovedPortEvents.clear();
396 apiAddedLinkEvents.clear();
397 apiRemovedLinkEvents.clear();
398 apiAddedDeviceEvents.clear();
399 apiRemovedDeviceEvents.clear();
400 }
401
402 /**
403 * Apply reordered events.
404 *
405 * @param hasAddedSwitchEvents true if there were Added Switch Events.
406 * @param hasAddedPortEvents true if there were Added Port Events.
407 */
408 private void applyReorderedEvents(boolean hasAddedSwitchEvents,
409 boolean hasAddedPortEvents) {
410 if (! (hasAddedSwitchEvents || hasAddedPortEvents))
411 return; // Nothing to do
412
413 //
414 // Try to apply the reordered events.
415 //
416 // NOTE: For simplicity we try to apply all events of a particular
417 // type if any "parent" type event was processed:
418 // - Apply reordered Port Events if Switches were added
419 // - Apply reordered Link and Device Events if Switches or Ports
420 // were added
421 //
422 Map<ByteBuffer, PortEvent> portEvents = reorderedAddedPortEvents;
423 Map<ByteBuffer, LinkEvent> linkEvents = reorderedAddedLinkEvents;
424 Map<ByteBuffer, DeviceEvent> deviceEvents = reorderedAddedDeviceEvents;
425 reorderedAddedPortEvents = new HashMap<>();
426 reorderedAddedLinkEvents = new HashMap<>();
427 reorderedAddedDeviceEvents = new HashMap<>();
428 //
429 // Apply reordered Port Events if Switches were added
430 //
431 if (hasAddedSwitchEvents) {
432 for (PortEvent portEvent : portEvents.values())
433 addPort(portEvent);
434 }
435 //
436 // Apply reordered Link and Device Events if Switches or Ports
437 // were added.
438 //
439 for (LinkEvent linkEvent : linkEvents.values())
440 addLink(linkEvent);
441 for (DeviceEvent deviceEvent : deviceEvents.values())
442 addDevice(deviceEvent);
443 }
444
Jonathan Hart22eb9882014-02-11 15:52:59 -0800445 /* ******************************
446 * NetworkGraphDiscoveryInterface methods
447 * ******************************/
Yuta HIGUCHIcd922f42014-02-11 18:59:11 -0800448
Pavlin Radoslavovc1cfde52014-02-19 11:35:29 -0800449 @Override
Pavlin Radoslavov018d5332014-02-19 23:08:35 -0800450 public void putSwitchDiscoveryEvent(SwitchEvent switchEvent,
451 Collection<PortEvent> portEvents) {
452 if (datastore.addSwitch(switchEvent, portEvents)) {
Pavlin Radoslavovc1cfde52014-02-19 11:35:29 -0800453 // Send out notification
Pavlin Radoslavov87dcc262014-02-19 21:13:23 -0800454 TopologyEvent topologyEvent = new TopologyEvent(switchEvent);
Pavlin Radoslavovc1cfde52014-02-19 11:35:29 -0800455 eventChannel.addEntry(topologyEvent.getID(), topologyEvent);
Pavlin Radoslavov018d5332014-02-19 23:08:35 -0800456
Pavlin Radoslavov26d83402014-02-20 15:24:30 -0800457 // Send out notification for each port
Pavlin Radoslavov018d5332014-02-19 23:08:35 -0800458 for (PortEvent portEvent : portEvents) {
459 topologyEvent = new TopologyEvent(portEvent);
460 eventChannel.addEntry(topologyEvent.getID(), topologyEvent);
461 }
Pavlin Radoslavov26d83402014-02-20 15:24:30 -0800462
463 //
464 // Keep track of the added ports
465 //
466 // Get the old Port Events
467 Map<ByteBuffer, PortEvent> oldPortEvents =
468 discoveredAddedPortEvents.get(switchEvent.getDpid());
469 if (oldPortEvents == null)
470 oldPortEvents = new HashMap<>();
471
472 // Store the new Port Events in the local cache
473 Map<ByteBuffer, PortEvent> newPortEvents = new HashMap<>();
474 for (PortEvent portEvent : portEvents) {
475 ByteBuffer id = ByteBuffer.wrap(portEvent.getID());
476 newPortEvents.put(id, portEvent);
477 }
478 discoveredAddedPortEvents.put(switchEvent.getDpid(),
479 newPortEvents);
480
481 //
482 // Extract the removed ports
483 //
484 List<PortEvent> removedPortEvents = new LinkedList<>();
485 for (Map.Entry<ByteBuffer, PortEvent> entry : oldPortEvents.entrySet()) {
486 ByteBuffer key = entry.getKey();
487 PortEvent portEvent = entry.getValue();
488 if (! newPortEvents.containsKey(key))
489 removedPortEvents.add(portEvent);
490 }
491
492 // Cleanup old removed ports
493 for (PortEvent portEvent : removedPortEvents)
494 removePortDiscoveryEvent(portEvent);
Pavlin Radoslavovc1cfde52014-02-19 11:35:29 -0800495 }
Pavlin Radoslavovc1cfde52014-02-19 11:35:29 -0800496 }
497
498 @Override
Pavlin Radoslavov6ea84a42014-02-19 15:50:01 -0800499 public void removeSwitchDiscoveryEvent(SwitchEvent switchEvent) {
Pavlin Radoslavov26d83402014-02-20 15:24:30 -0800500 // Get the old Port Events
501 Map<ByteBuffer, PortEvent> oldPortEvents =
502 discoveredAddedPortEvents.get(switchEvent.getDpid());
503 if (oldPortEvents == null)
504 oldPortEvents = new HashMap<>();
Pavlin Radoslavov018d5332014-02-19 23:08:35 -0800505
Pavlin Radoslavov26d83402014-02-20 15:24:30 -0800506 if (datastore.deactivateSwitch(switchEvent, oldPortEvents.values())) {
Pavlin Radoslavovc1cfde52014-02-19 11:35:29 -0800507 // Send out notification
508 eventChannel.removeEntry(switchEvent.getID());
Pavlin Radoslavov018d5332014-02-19 23:08:35 -0800509
Pavlin Radoslavov26d83402014-02-20 15:24:30 -0800510 // Send out notification for each port
511 for (PortEvent portEvent : oldPortEvents.values())
Pavlin Radoslavov018d5332014-02-19 23:08:35 -0800512 eventChannel.removeEntry(portEvent.getID());
Pavlin Radoslavov26d83402014-02-20 15:24:30 -0800513 discoveredAddedPortEvents.remove(switchEvent.getDpid());
514
515 // Cleanup for each link
516 Map<ByteBuffer, LinkEvent> oldLinkEvents =
517 discoveredAddedLinkEvents.get(switchEvent.getDpid());
518 if (oldLinkEvents != null) {
519 for (LinkEvent linkEvent : oldLinkEvents.values())
520 removeLinkDiscoveryEvent(linkEvent);
521 discoveredAddedLinkEvents.remove(switchEvent.getDpid());
522 }
523
524 // Cleanup for each device
525 Map<ByteBuffer, DeviceEvent> oldDeviceEvents =
526 discoveredAddedDeviceEvents.get(switchEvent.getDpid());
527 if (oldDeviceEvents != null) {
528 for (DeviceEvent deviceEvent : oldDeviceEvents.values())
529 removeDeviceDiscoveryEvent(deviceEvent);
530 discoveredAddedDeviceEvents.remove(switchEvent.getDpid());
Pavlin Radoslavov018d5332014-02-19 23:08:35 -0800531 }
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 putPortDiscoveryEvent(PortEvent portEvent) {
Pavlin Radoslavov50cd1482014-02-19 16:57:03 -0800537 if (datastore.addPort(portEvent)) {
Pavlin Radoslavovc1cfde52014-02-19 11:35:29 -0800538 // Send out notification
Pavlin Radoslavov87dcc262014-02-19 21:13:23 -0800539 TopologyEvent topologyEvent = new TopologyEvent(portEvent);
Pavlin Radoslavov018d5332014-02-19 23:08:35 -0800540 eventChannel.addEntry(topologyEvent.getID(), topologyEvent);
Pavlin Radoslavov26d83402014-02-20 15:24:30 -0800541
542 // Store the new Port Event in the local cache
543 Map<ByteBuffer, PortEvent> oldPortEvents =
544 discoveredAddedPortEvents.get(portEvent.getDpid());
545 if (oldPortEvents == null) {
546 oldPortEvents = new HashMap<>();
547 discoveredAddedPortEvents.put(portEvent.getDpid(),
548 oldPortEvents);
549 }
550 ByteBuffer id = ByteBuffer.wrap(portEvent.getID());
551 oldPortEvents.put(id, portEvent);
Pavlin Radoslavovc1cfde52014-02-19 11:35:29 -0800552 }
Pavlin Radoslavovc1cfde52014-02-19 11:35:29 -0800553 }
554
555 @Override
Pavlin Radoslavov6ea84a42014-02-19 15:50:01 -0800556 public void removePortDiscoveryEvent(PortEvent portEvent) {
Pavlin Radoslavov50cd1482014-02-19 16:57:03 -0800557 if (datastore.deactivatePort(portEvent)) {
Pavlin Radoslavovc1cfde52014-02-19 11:35:29 -0800558 // Send out notification
559 eventChannel.removeEntry(portEvent.getID());
Pavlin Radoslavov26d83402014-02-20 15:24:30 -0800560
561 // Cleanup the Port Event from the local cache
562 Map<ByteBuffer, PortEvent> oldPortEvents =
563 discoveredAddedPortEvents.get(portEvent.getDpid());
564 if (oldPortEvents != null) {
565 ByteBuffer id = ByteBuffer.wrap(portEvent.getID());
566 oldPortEvents.remove(id);
567 }
568
569 // Cleanup for the incoming link
570 Map<ByteBuffer, LinkEvent> oldLinkEvents =
571 discoveredAddedLinkEvents.get(portEvent.getDpid());
572 if (oldLinkEvents != null) {
573 for (LinkEvent linkEvent : oldLinkEvents.values()) {
574 if (linkEvent.getDst().equals(portEvent.id)) {
575 removeLinkDiscoveryEvent(linkEvent);
576 //
577 // NOTE: oldLinkEvents was modified by
578 // removeLinkDiscoveryEvent() and cannot be iterated
579 // anymore.
580 //
581 break;
582 }
583 }
584 }
585
586 // Cleanup for the connected devices
587 // TODO: The implementation below is probably wrong
588 List<DeviceEvent> removedDeviceEvents = new LinkedList<>();
589 Map<ByteBuffer, DeviceEvent> oldDeviceEvents =
590 discoveredAddedDeviceEvents.get(portEvent.getDpid());
591 if (oldDeviceEvents != null) {
592 for (DeviceEvent deviceEvent : oldDeviceEvents.values()) {
593 for (SwitchPort swp : deviceEvent.getAttachmentPoints()) {
594 if (swp.equals(portEvent.id)) {
595 removedDeviceEvents.add(deviceEvent);
596 break;
597 }
598 }
599 }
600 for (DeviceEvent deviceEvent : removedDeviceEvents)
601 removeDeviceDiscoveryEvent(deviceEvent);
602 }
Pavlin Radoslavovc1cfde52014-02-19 11:35:29 -0800603 }
Pavlin Radoslavovc1cfde52014-02-19 11:35:29 -0800604 }
605
606 @Override
Pavlin Radoslavov6ea84a42014-02-19 15:50:01 -0800607 public void putLinkDiscoveryEvent(LinkEvent linkEvent) {
Pavlin Radoslavov50cd1482014-02-19 16:57:03 -0800608 if (datastore.addLink(linkEvent)) {
Pavlin Radoslavovc1cfde52014-02-19 11:35:29 -0800609 // Send out notification
Pavlin Radoslavov87dcc262014-02-19 21:13:23 -0800610 TopologyEvent topologyEvent = new TopologyEvent(linkEvent);
Pavlin Radoslavovc1cfde52014-02-19 11:35:29 -0800611 eventChannel.addEntry(topologyEvent.getID(), topologyEvent);
Pavlin Radoslavov26d83402014-02-20 15:24:30 -0800612
613 // Store the new Link Event in the local cache
614 Map<ByteBuffer, LinkEvent> oldLinkEvents =
615 discoveredAddedLinkEvents.get(linkEvent.getDst().getDpid());
616 if (oldLinkEvents == null) {
617 oldLinkEvents = new HashMap<>();
618 discoveredAddedLinkEvents.put(linkEvent.getDst().getDpid(),
619 oldLinkEvents);
620 }
621 ByteBuffer id = ByteBuffer.wrap(linkEvent.getID());
622 oldLinkEvents.put(id, linkEvent);
Pavlin Radoslavovc1cfde52014-02-19 11:35:29 -0800623 }
Pavlin Radoslavovc1cfde52014-02-19 11:35:29 -0800624 }
625
626 @Override
Pavlin Radoslavov6ea84a42014-02-19 15:50:01 -0800627 public void removeLinkDiscoveryEvent(LinkEvent linkEvent) {
Pavlin Radoslavov50cd1482014-02-19 16:57:03 -0800628 if (datastore.removeLink(linkEvent)) {
Pavlin Radoslavovc1cfde52014-02-19 11:35:29 -0800629 // Send out notification
630 eventChannel.removeEntry(linkEvent.getID());
Pavlin Radoslavov26d83402014-02-20 15:24:30 -0800631
632 // Cleanup the Link Event from the local cache
633 Map<ByteBuffer, LinkEvent> oldLinkEvents =
634 discoveredAddedLinkEvents.get(linkEvent.getDst().getDpid());
635 if (oldLinkEvents != null) {
636 ByteBuffer id = ByteBuffer.wrap(linkEvent.getID());
637 oldLinkEvents.remove(id);
638 }
Jonathan Hart22eb9882014-02-11 15:52:59 -0800639 }
Pavlin Radoslavovc1cfde52014-02-19 11:35:29 -0800640 }
Jonathan Hart22eb9882014-02-11 15:52:59 -0800641
Pavlin Radoslavovc1cfde52014-02-19 11:35:29 -0800642 @Override
Pavlin Radoslavov6ea84a42014-02-19 15:50:01 -0800643 public void putDeviceDiscoveryEvent(DeviceEvent deviceEvent) {
Pavlin Radoslavov50cd1482014-02-19 16:57:03 -0800644 if (datastore.addDevice(deviceEvent)) {
Pavlin Radoslavovc1cfde52014-02-19 11:35:29 -0800645 // Send out notification
Pavlin Radoslavov87dcc262014-02-19 21:13:23 -0800646 TopologyEvent topologyEvent = new TopologyEvent(deviceEvent);
Pavlin Radoslavov50cd1482014-02-19 16:57:03 -0800647 eventChannel.addEntry(topologyEvent.getID(), topologyEvent);
Pavlin Radoslavov26d83402014-02-20 15:24:30 -0800648
649 // Store the new Device Event in the local cache
650 // TODO: The implementation below is probably wrong
651 for (SwitchPort swp : deviceEvent.getAttachmentPoints()) {
652 Map<ByteBuffer, DeviceEvent> oldDeviceEvents =
653 discoveredAddedDeviceEvents.get(swp.getDpid());
654 if (oldDeviceEvents == null) {
655 oldDeviceEvents = new HashMap<>();
656 discoveredAddedDeviceEvents.put(swp.getDpid(),
657 oldDeviceEvents);
658 }
659 ByteBuffer id = ByteBuffer.wrap(deviceEvent.getID());
660 oldDeviceEvents.put(id, deviceEvent);
661 }
Jonathan Hart22eb9882014-02-11 15:52:59 -0800662 }
Pavlin Radoslavovc1cfde52014-02-19 11:35:29 -0800663 }
Jonathan Hart22eb9882014-02-11 15:52:59 -0800664
Pavlin Radoslavovc1cfde52014-02-19 11:35:29 -0800665 @Override
Pavlin Radoslavov6ea84a42014-02-19 15:50:01 -0800666 public void removeDeviceDiscoveryEvent(DeviceEvent deviceEvent) {
Pavlin Radoslavov50cd1482014-02-19 16:57:03 -0800667 if (datastore.removeDevice(deviceEvent)) {
Pavlin Radoslavovc1cfde52014-02-19 11:35:29 -0800668 // Send out notification
669 eventChannel.removeEntry(deviceEvent.getID());
Pavlin Radoslavov26d83402014-02-20 15:24:30 -0800670
671 // Cleanup the Device Event from the local cache
672 // TODO: The implementation below is probably wrong
673 ByteBuffer id = ByteBuffer.wrap(deviceEvent.getID());
674 for (SwitchPort swp : deviceEvent.getAttachmentPoints()) {
675 Map<ByteBuffer, DeviceEvent> oldDeviceEvents =
676 discoveredAddedDeviceEvents.get(swp.getDpid());
677 if (oldDeviceEvents != null) {
678 oldDeviceEvents.remove(id);
679 }
680 }
Jonathan Hart22eb9882014-02-11 15:52:59 -0800681 }
Pavlin Radoslavovc1cfde52014-02-19 11:35:29 -0800682 }
Jonathan Hart22eb9882014-02-11 15:52:59 -0800683
Pavlin Radoslavov3c9cc552014-02-20 09:58:38 -0800684 /* ************************************************
685 * Internal methods to maintain the network graph
686 * ************************************************/
Pavlin Radoslavov74986ce2014-02-20 13:17:20 -0800687 private void addSwitch(SwitchEvent switchEvent) {
688 Switch sw = networkGraph.getSwitch(switchEvent.getDpid());
Pavlin Radoslavov3c9cc552014-02-20 09:58:38 -0800689 if (sw == null) {
Pavlin Radoslavov74986ce2014-02-20 13:17:20 -0800690 sw = new SwitchImpl(networkGraph, switchEvent.getDpid());
Pavlin Radoslavov3c9cc552014-02-20 09:58:38 -0800691 networkGraph.putSwitch(sw);
692 } else {
693 // TODO: Update the switch attributes
694 // TODO: Nothing to do for now
695 }
Pavlin Radoslavov74986ce2014-02-20 13:17:20 -0800696 apiAddedSwitchEvents.add(switchEvent);
Pavlin Radoslavov3c9cc552014-02-20 09:58:38 -0800697 }
698
Pavlin Radoslavov74986ce2014-02-20 13:17:20 -0800699 private void removeSwitch(SwitchEvent switchEvent) {
700 Switch sw = networkGraph.getSwitch(switchEvent.getDpid());
Pavlin Radoslavov3c9cc552014-02-20 09:58:38 -0800701 if (sw == null) {
Pavlin Radoslavov74986ce2014-02-20 13:17:20 -0800702 log.warn("Switch {} already removed, ignoring", switchEvent);
Pavlin Radoslavov3c9cc552014-02-20 09:58:38 -0800703 return;
704 }
705
706 //
707 // Remove all Ports on the Switch
708 //
709 ArrayList<PortEvent> portsToRemove = new ArrayList<>();
710 for (Port port : sw.getPorts()) {
711 log.warn("Port {} on Switch {} should be removed prior to removing Switch. Removing Port now.",
Pavlin Radoslavov74986ce2014-02-20 13:17:20 -0800712 port, switchEvent);
Pavlin Radoslavov3c9cc552014-02-20 09:58:38 -0800713 PortEvent portEvent = new PortEvent(port.getDpid(),
714 port.getNumber());
715 portsToRemove.add(portEvent);
716 }
717 for (PortEvent portEvent : portsToRemove)
718 removePort(portEvent);
719
Pavlin Radoslavov74986ce2014-02-20 13:17:20 -0800720 networkGraph.removeSwitch(switchEvent.getDpid());
721 apiRemovedSwitchEvents.add(switchEvent);
Pavlin Radoslavov3c9cc552014-02-20 09:58:38 -0800722 }
723
724 private void addPort(PortEvent portEvent) {
725 Switch sw = networkGraph.getSwitch(portEvent.getDpid());
726 if (sw == null) {
Pavlin Radoslavov706add22014-02-20 12:15:59 -0800727 // Reordered event: delay the event in local cache
728 ByteBuffer id = ByteBuffer.wrap(portEvent.getID());
729 reorderedAddedPortEvents.put(id, portEvent);
Pavlin Radoslavov3c9cc552014-02-20 09:58:38 -0800730 return;
731 }
732 SwitchImpl switchImpl = getSwitchImpl(sw);
733
734 Port port = sw.getPort(portEvent.getNumber());
735 if (port == null) {
736 port = new PortImpl(networkGraph, sw, portEvent.getNumber());
737 switchImpl.addPort(port);
738 } else {
739 // TODO: Update the port attributes
740 }
Pavlin Radoslavov74986ce2014-02-20 13:17:20 -0800741 apiAddedPortEvents.add(portEvent);
Pavlin Radoslavov3c9cc552014-02-20 09:58:38 -0800742 }
743
744 private void removePort(PortEvent portEvent) {
745 Switch sw = networkGraph.getSwitch(portEvent.getDpid());
746 if (sw == null) {
747 log.warn("Parent Switch for Port {} already removed, ignoring",
748 portEvent);
749 return;
750 }
751
752 Port port = sw.getPort(portEvent.getNumber());
753 if (port == null) {
754 log.warn("Port {} already removed, ignoring", portEvent);
755 return;
756 }
757
758 //
759 // Remove all Devices attached to the Port
760 //
761 ArrayList<DeviceEvent> devicesToRemove = new ArrayList<>();
762 for (Device device : port.getDevices()) {
763 log.debug("Removing Device {} on Port {}", device, portEvent);
764 DeviceEvent deviceEvent = new DeviceEvent(device.getMacAddress());
765 SwitchPort switchPort = new SwitchPort(port.getSwitch().getDpid(),
766 port.getNumber());
767 deviceEvent.addAttachmentPoint(switchPort);
768 devicesToRemove.add(deviceEvent);
769 }
770 for (DeviceEvent deviceEvent : devicesToRemove)
771 removeDevice(deviceEvent);
772
773 //
774 // Remove all Links connected to the Port
775 //
776 Set<Link> links = new HashSet<>();
777 links.add(port.getOutgoingLink());
778 links.add(port.getIncomingLink());
779 ArrayList<LinkEvent> linksToRemove = new ArrayList<>();
780 for (Link link : links) {
781 if (link == null)
782 continue;
783 log.debug("Removing Link {} on Port {}", link, portEvent);
784 LinkEvent linkEvent = new LinkEvent(link.getSrcSwitch().getDpid(),
785 link.getSrcPort().getNumber(),
786 link.getDstSwitch().getDpid(),
787 link.getDstPort().getNumber());
788 linksToRemove.add(linkEvent);
789 }
790 for (LinkEvent linkEvent : linksToRemove)
791 removeLink(linkEvent);
792
793 // Remove the Port from the Switch
794 SwitchImpl switchImpl = getSwitchImpl(sw);
795 switchImpl.removePort(port);
Pavlin Radoslavov74986ce2014-02-20 13:17:20 -0800796
797 apiRemovedPortEvents.add(portEvent);
Pavlin Radoslavov3c9cc552014-02-20 09:58:38 -0800798 }
799
800 private void addLink(LinkEvent linkEvent) {
801 Port srcPort = networkGraph.getPort(linkEvent.getSrc().dpid,
802 linkEvent.getSrc().number);
Pavlin Radoslavov3c9cc552014-02-20 09:58:38 -0800803 Port dstPort = networkGraph.getPort(linkEvent.getDst().dpid,
804 linkEvent.getDst().number);
Pavlin Radoslavov706add22014-02-20 12:15:59 -0800805 if ((srcPort == null) || (dstPort == null)) {
806 // Reordered event: delay the event in local cache
807 ByteBuffer id = ByteBuffer.wrap(linkEvent.getID());
808 reorderedAddedLinkEvents.put(id, linkEvent);
Pavlin Radoslavov3c9cc552014-02-20 09:58:38 -0800809 return;
810 }
811
812 // Get the Link instance from the Destination Port Incoming Link
813 Link link = dstPort.getIncomingLink();
814 assert(link == srcPort.getOutgoingLink());
815 if (link == null) {
816 link = new LinkImpl(networkGraph, srcPort, dstPort);
817 PortImpl srcPortImpl = getPortImpl(srcPort);
818 PortImpl dstPortImpl = getPortImpl(dstPort);
819 srcPortImpl.setOutgoingLink(link);
820 dstPortImpl.setIncomingLink(link);
821
822 // Remove all Devices attached to the Ports
823 ArrayList<DeviceEvent> devicesToRemove = new ArrayList<>();
824 ArrayList<Port> ports = new ArrayList<>();
825 ports.add(srcPort);
826 ports.add(dstPort);
827 for (Port port : ports) {
828 for (Device device : port.getDevices()) {
829 log.error("Device {} on Port {} should have been removed prior to adding Link {}",
830 device, port, linkEvent);
831 DeviceEvent deviceEvent =
832 new DeviceEvent(device.getMacAddress());
833 SwitchPort switchPort =
834 new SwitchPort(port.getSwitch().getDpid(),
835 port.getNumber());
836 deviceEvent.addAttachmentPoint(switchPort);
837 devicesToRemove.add(deviceEvent);
838 }
839 }
840 for (DeviceEvent deviceEvent : devicesToRemove)
841 removeDevice(deviceEvent);
842 } else {
843 // TODO: Update the link attributes
844 }
Pavlin Radoslavov74986ce2014-02-20 13:17:20 -0800845
846 apiAddedLinkEvents.add(linkEvent);
Pavlin Radoslavov3c9cc552014-02-20 09:58:38 -0800847 }
848
849 private void removeLink(LinkEvent linkEvent) {
850 Port srcPort = networkGraph.getPort(linkEvent.getSrc().dpid,
851 linkEvent.getSrc().number);
852 if (srcPort == null) {
853 log.warn("Src Port for Link {} already removed, ignoring",
854 linkEvent);
855 return;
856 }
857
858 Port dstPort = networkGraph.getPort(linkEvent.getDst().dpid,
859 linkEvent.getDst().number);
860 if (dstPort == null) {
861 log.warn("Dst Port for Link {} already removed, ignoring",
862 linkEvent);
863 return;
864 }
865
866 //
867 // Remove the Link instance from the Destination Port Incoming Link
868 // and the Source Port Outgoing Link.
869 //
870 Link link = dstPort.getIncomingLink();
871 if (link == null) {
872 log.warn("Link {} already removed on destination Port", linkEvent);
873 }
874 link = srcPort.getOutgoingLink();
875 if (link == null) {
876 log.warn("Link {} already removed on src Port", linkEvent);
877 }
878 getPortImpl(dstPort).setIncomingLink(null);
879 getPortImpl(srcPort).setOutgoingLink(null);
Pavlin Radoslavov74986ce2014-02-20 13:17:20 -0800880
881 apiRemovedLinkEvents.add(linkEvent);
Pavlin Radoslavov3c9cc552014-02-20 09:58:38 -0800882 }
883
884 // TODO: Device-related work is incomplete
885 private void addDevice(DeviceEvent deviceEvent) {
886 Device device = networkGraph.getDeviceByMac(deviceEvent.getMac());
887 if (device == null) {
888 device = new DeviceImpl(networkGraph, deviceEvent.getMac());
889 }
890 DeviceImpl deviceImpl = getDeviceImpl(device);
891
892 // Update the IP addresses
893 for (InetAddress ipAddr : deviceEvent.getIpAddresses())
894 deviceImpl.addIpAddress(ipAddr);
895
896 // Process each attachment point
897 boolean attachmentFound = false;
898 for (SwitchPort swp : deviceEvent.getAttachmentPoints()) {
899 // Attached Ports must exist
900 Port port = networkGraph.getPort(swp.dpid, swp.number);
901 if (port == null) {
Pavlin Radoslavov706add22014-02-20 12:15:59 -0800902 // Reordered event: delay the event in local cache
903 ByteBuffer id = ByteBuffer.wrap(deviceEvent.getID());
904 reorderedAddedDeviceEvents.put(id, deviceEvent);
Pavlin Radoslavov3c9cc552014-02-20 09:58:38 -0800905 continue;
906 }
907 // Attached Ports must not have Link
908 if (port.getOutgoingLink() != null ||
909 port.getIncomingLink() != null) {
910 log.warn("Link (Out:{},In:{}) exist on the attachment point, skipping mutation.",
911 port.getOutgoingLink(),
912 port.getIncomingLink());
913 continue;
914 }
915
916 // Add Device <-> Port attachment
917 PortImpl portImpl = getPortImpl(port);
918 portImpl.addDevice(device);
919 deviceImpl.addAttachmentPoint(port);
920 attachmentFound = true;
921 }
922
923 // Update the device in the Network Graph
Pavlin Radoslavov74986ce2014-02-20 13:17:20 -0800924 if (attachmentFound) {
Pavlin Radoslavov3c9cc552014-02-20 09:58:38 -0800925 networkGraph.putDevice(device);
Pavlin Radoslavov74986ce2014-02-20 13:17:20 -0800926 apiAddedDeviceEvents.add(deviceEvent);
927 }
Pavlin Radoslavov3c9cc552014-02-20 09:58:38 -0800928 }
929
930 private void removeDevice(DeviceEvent deviceEvent) {
931 Device device = networkGraph.getDeviceByMac(deviceEvent.getMac());
932 if (device == null) {
933 log.warn("Device {} already removed, ignoring", deviceEvent);
934 return;
935 }
936 DeviceImpl deviceImpl = getDeviceImpl(device);
937
938 // Process each attachment point
939 for (SwitchPort swp : deviceEvent.getAttachmentPoints()) {
940 // Attached Ports must exist
941 Port port = networkGraph.getPort(swp.dpid, swp.number);
942 if (port == null) {
943 log.warn("Port for the attachment point {} did not exist. skipping attachment point mutation", swp);
944 continue;
945 }
946
947 // Remove Device <-> Port attachment
948 PortImpl portImpl = getPortImpl(port);
949 portImpl.removeDevice(device);
950 deviceImpl.removeAttachmentPoint(port);
951 }
Pavlin Radoslavov74986ce2014-02-20 13:17:20 -0800952
Pavlin Radoslavov3c9cc552014-02-20 09:58:38 -0800953 networkGraph.removeDevice(device);
Pavlin Radoslavov74986ce2014-02-20 13:17:20 -0800954 apiRemovedDeviceEvents.add(deviceEvent);
Pavlin Radoslavov3c9cc552014-02-20 09:58:38 -0800955 }
Jonathan Hart22eb9882014-02-11 15:52:59 -0800956
Pavlin Radoslavovc1cfde52014-02-19 11:35:29 -0800957 /**
958 *
Pavlin Radoslavov74986ce2014-02-20 13:17:20 -0800959 * @param switchEvent
Pavlin Radoslavovc1cfde52014-02-19 11:35:29 -0800960 * @return true if ready to accept event.
961 */
Pavlin Radoslavov74986ce2014-02-20 13:17:20 -0800962 private boolean prepareForAddSwitchEvent(SwitchEvent switchEvent) {
Pavlin Radoslavovc1cfde52014-02-19 11:35:29 -0800963 // No show stopping precondition
Pavlin Radoslavovc1cfde52014-02-19 11:35:29 -0800964 return true;
965 }
Jonathan Hart22eb9882014-02-11 15:52:59 -0800966
Pavlin Radoslavov74986ce2014-02-20 13:17:20 -0800967 private boolean prepareForRemoveSwitchEvent(SwitchEvent switchEvent) {
Pavlin Radoslavovc1cfde52014-02-19 11:35:29 -0800968 // No show stopping precondition
Pavlin Radoslavovc1cfde52014-02-19 11:35:29 -0800969 return true;
970 }
Yuta HIGUCHI71e7a052014-02-17 22:14:15 -0800971
Pavlin Radoslavovc1cfde52014-02-19 11:35:29 -0800972 private boolean prepareForAddPortEvent(PortEvent portEvent) {
973 // Parent Switch must exist
974 if (networkGraph.getSwitch(portEvent.getDpid()) == null) {
975 log.warn("Dropping add port event because switch doesn't exist: {}",
976 portEvent);
977 return false;
978 }
979 // Prep: None
980 return true;
981 }
982
983 private boolean prepareForRemovePortEvent(PortEvent portEvent) {
984 Port port = networkGraph.getPort(portEvent.getDpid(),
985 portEvent.getNumber());
986 if (port == null) {
987 log.debug("Port already removed? {}", portEvent);
988 // let it pass
989 return true;
Jonathan Hart22eb9882014-02-11 15:52:59 -0800990 }
Yuta HIGUCHIcd922f42014-02-11 18:59:11 -0800991
Pavlin Radoslavovc1cfde52014-02-19 11:35:29 -0800992 // Prep: Remove Link and Device Attachment
993 ArrayList<DeviceEvent> deviceEvents = new ArrayList<>();
994 for (Device device : port.getDevices()) {
995 log.debug("Removing Device {} on Port {}", device, portEvent);
996 DeviceEvent devEvent = new DeviceEvent(device.getMacAddress());
997 devEvent.addAttachmentPoint(new SwitchPort(port.getSwitch().getDpid(),
998 port.getNumber()));
999 deviceEvents.add(devEvent);
1000 }
1001 for (DeviceEvent devEvent : deviceEvents) {
1002 // calling Discovery API to wipe from DB, etc.
Pavlin Radoslavov6ea84a42014-02-19 15:50:01 -08001003 removeDeviceDiscoveryEvent(devEvent);
Jonathan Hart22eb9882014-02-11 15:52:59 -08001004 }
Yuta HIGUCHIcd922f42014-02-11 18:59:11 -08001005
Pavlin Radoslavovc1cfde52014-02-19 11:35:29 -08001006 Set<Link> links = new HashSet<>();
1007 links.add(port.getOutgoingLink());
1008 links.add(port.getIncomingLink());
1009 for (Link link : links) {
1010 if (link == null) {
1011 continue;
1012 }
1013 log.debug("Removing Link {} on Port {}", link, portEvent);
1014 LinkEvent linkEvent =
Pavlin Radoslavov7c8f69a2014-02-19 19:01:45 -08001015 new LinkEvent(link.getSrcSwitch().getDpid(),
1016 link.getSrcPort().getNumber(),
1017 link.getDstSwitch().getDpid(),
1018 link.getDstPort().getNumber());
Pavlin Radoslavovc1cfde52014-02-19 11:35:29 -08001019 // calling Discovery API to wipe from DB, etc.
Yuta HIGUCHI8d762e92014-02-12 14:10:25 -08001020
Pavlin Radoslavovc1cfde52014-02-19 11:35:29 -08001021 // Call internal remove Link, which will check
1022 // ownership of DST dpid and modify DB only if it is the owner
Pavlin Radoslavov6ea84a42014-02-19 15:50:01 -08001023 removeLinkDiscoveryEvent(linkEvent, true);
Jonathan Hart22eb9882014-02-11 15:52:59 -08001024 }
Pavlin Radoslavovc1cfde52014-02-19 11:35:29 -08001025 return true;
1026 }
Yuta HIGUCHIcd922f42014-02-11 18:59:11 -08001027
Pavlin Radoslavovc1cfde52014-02-19 11:35:29 -08001028 private boolean prepareForAddLinkEvent(LinkEvent linkEvent) {
1029 // Src/Dst Port must exist
1030 Port srcPort = networkGraph.getPort(linkEvent.getSrc().dpid,
1031 linkEvent.getSrc().number);
1032 Port dstPort = networkGraph.getPort(linkEvent.getDst().dpid,
1033 linkEvent.getDst().number);
1034 if (srcPort == null || dstPort == null) {
Jonathan Hart0a4846e2014-02-18 11:03:40 -08001035 log.warn("Dropping add link event because port doesn't exist: {}",
Pavlin Radoslavovc1cfde52014-02-19 11:35:29 -08001036 linkEvent);
1037 return false;
Jonathan Hart22eb9882014-02-11 15:52:59 -08001038 }
Yuta HIGUCHIcd922f42014-02-11 18:59:11 -08001039
Pavlin Radoslavovc1cfde52014-02-19 11:35:29 -08001040 // Prep: remove Device attachment on both Ports
1041 ArrayList<DeviceEvent> deviceEvents = new ArrayList<>();
1042 for (Device device : srcPort.getDevices()) {
1043 DeviceEvent devEvent = new DeviceEvent(device.getMacAddress());
1044 devEvent.addAttachmentPoint(new SwitchPort(srcPort.getSwitch().getDpid(), srcPort.getNumber()));
1045 deviceEvents.add(devEvent);
1046 }
1047 for (Device device : dstPort.getDevices()) {
1048 DeviceEvent devEvent = new DeviceEvent(device.getMacAddress());
1049 devEvent.addAttachmentPoint(new SwitchPort(dstPort.getSwitch().getDpid(),
1050 dstPort.getNumber()));
1051 deviceEvents.add(devEvent);
1052 }
1053 for (DeviceEvent devEvent : deviceEvents) {
1054 // calling Discovery API to wipe from DB, etc.
Pavlin Radoslavov6ea84a42014-02-19 15:50:01 -08001055 removeDeviceDiscoveryEvent(devEvent);
Jonathan Hart22eb9882014-02-11 15:52:59 -08001056 }
Yuta HIGUCHIcd922f42014-02-11 18:59:11 -08001057
Pavlin Radoslavovc1cfde52014-02-19 11:35:29 -08001058 return true;
1059 }
Yuta HIGUCHId02e9282014-02-12 09:24:41 -08001060
Pavlin Radoslavovc1cfde52014-02-19 11:35:29 -08001061 private boolean prepareForRemoveLinkEvent(LinkEvent linkEvent) {
1062 // Src/Dst Port must exist
1063 Port srcPort = networkGraph.getPort(linkEvent.getSrc().dpid,
1064 linkEvent.getSrc().number);
1065 Port dstPort = networkGraph.getPort(linkEvent.getDst().dpid,
1066 linkEvent.getDst().number);
1067 if (srcPort == null || dstPort == null) {
1068 log.warn("Dropping remove link event because port doesn't exist {}", linkEvent);
1069 return false;
1070 }
Yuta HIGUCHI8d762e92014-02-12 14:10:25 -08001071
Pavlin Radoslavovc1cfde52014-02-19 11:35:29 -08001072 Link link = srcPort.getOutgoingLink();
1073
1074 // Link is already gone, or different Link exist in memory
1075 // XXX Check if we should reject or just accept these cases.
1076 // it should be harmless to remove the Link on event from DB anyways
1077 if (link == null ||
Pavlin Radoslavov7c8f69a2014-02-19 19:01:45 -08001078 !link.getDstPort().getNumber().equals(linkEvent.getDst().number)
1079 || !link.getDstSwitch().getDpid().equals(linkEvent.getDst().dpid)) {
Pavlin Radoslavovc1cfde52014-02-19 11:35:29 -08001080 log.warn("Dropping remove link event because link doesn't exist: {}", linkEvent);
1081 return false;
1082 }
1083 // Prep: None
1084 return true;
1085 }
1086
1087 /**
1088 *
1089 * @param deviceEvent Event will be modified to remove inapplicable attachemntPoints/ipAddress
1090 * @return false if this event should be dropped.
1091 */
1092 private boolean prepareForAddDeviceEvent(DeviceEvent deviceEvent) {
1093 boolean preconditionBroken = false;
1094 ArrayList<PortEvent.SwitchPort> failedSwitchPort = new ArrayList<>();
1095 for ( PortEvent.SwitchPort swp : deviceEvent.getAttachmentPoints() ) {
1096 // Attached Ports must exist
1097 Port port = networkGraph.getPort(swp.dpid, swp.number);
1098 if (port == null) {
1099 preconditionBroken = true;
1100 failedSwitchPort.add(swp);
1101 continue;
Yuta HIGUCHI8d762e92014-02-12 14:10:25 -08001102 }
Pavlin Radoslavovc1cfde52014-02-19 11:35:29 -08001103 // Attached Ports must not have Link
1104 if (port.getOutgoingLink() != null ||
1105 port.getIncomingLink() != null) {
1106 preconditionBroken = true;
1107 failedSwitchPort.add(swp);
1108 continue;
1109 }
1110 }
1111
1112 // Rewriting event to exclude failed attachmentPoint
1113 // XXX Assumption behind this is that inapplicable device event should
1114 // be dropped, not deferred. If we decide to defer Device event,
1115 // rewriting can become a problem
1116 List<SwitchPort> attachmentPoints = deviceEvent.getAttachmentPoints();
1117 attachmentPoints.removeAll(failedSwitchPort);
1118 deviceEvent.setAttachmentPoints(attachmentPoints);
1119
1120 if (deviceEvent.getAttachmentPoints().isEmpty() &&
1121 deviceEvent.getIpAddresses().isEmpty()) {
1122 // return false to represent: Nothing left to do for this event.
1123 // Caller should drop event
1124 return false;
1125 }
Yuta HIGUCHI8d762e92014-02-12 14:10:25 -08001126
1127 // Should we return false to tell caller that the event was trimmed?
1128 // if ( preconditionBroken ) {
1129 // return false;
1130 // }
1131
Pavlin Radoslavovc1cfde52014-02-19 11:35:29 -08001132 return true;
1133 }
1134
1135 private boolean prepareForRemoveDeviceEvent(DeviceEvent deviceEvent) {
1136 // No show stopping precondition?
1137 // Prep: none
1138 return true;
1139 }
1140
Pavlin Radoslavovc1cfde52014-02-19 11:35:29 -08001141 private SwitchImpl getSwitchImpl(Switch sw) {
1142 if (sw instanceof SwitchImpl) {
1143 return (SwitchImpl) sw;
1144 }
1145 throw new ClassCastException("SwitchImpl expected, but found: " + sw);
1146 }
1147
1148 private PortImpl getPortImpl(Port p) {
1149 if (p instanceof PortImpl) {
1150 return (PortImpl) p;
1151 }
1152 throw new ClassCastException("PortImpl expected, but found: " + p);
1153 }
1154
1155 private LinkImpl getLinkImpl(Link l) {
1156 if (l instanceof LinkImpl) {
1157 return (LinkImpl) l;
1158 }
1159 throw new ClassCastException("LinkImpl expected, but found: " + l);
1160 }
1161
1162 private DeviceImpl getDeviceImpl(Device d) {
1163 if (d instanceof DeviceImpl) {
1164 return (DeviceImpl) d;
1165 }
1166 throw new ClassCastException("DeviceImpl expected, but found: " + d);
1167 }
1168
1169 @Deprecated
Pavlin Radoslavov018d5332014-02-19 23:08:35 -08001170 private Collection<EventEntry<TopologyEvent>> readWholeTopologyFromDB() {
1171 Collection<EventEntry<TopologyEvent>> collection =
1172 new LinkedList<EventEntry<TopologyEvent>>();
1173
Pavlin Radoslavovc1cfde52014-02-19 11:35:29 -08001174 // XXX May need to clear whole topology first, depending on
1175 // how we initially subscribe to replication events
1176
Pavlin Radoslavov018d5332014-02-19 23:08:35 -08001177 // Add all active switches
Pavlin Radoslavovc1cfde52014-02-19 11:35:29 -08001178 for (RCSwitch sw : RCSwitch.getAllSwitches()) {
1179 if (sw.getStatus() != RCSwitch.STATUS.ACTIVE) {
1180 continue;
1181 }
Pavlin Radoslavov018d5332014-02-19 23:08:35 -08001182
1183 SwitchEvent switchEvent = new SwitchEvent(sw.getDpid());
1184 TopologyEvent topologyEvent = new TopologyEvent(switchEvent);
1185 EventEntry<TopologyEvent> eventEntry =
1186 new EventEntry<TopologyEvent>(EventEntry.Type.ENTRY_ADD,
1187 topologyEvent);
1188 collection.add(eventEntry);
Yuta HIGUCHIa536e762014-02-17 21:47:28 -08001189 }
1190
Pavlin Radoslavov018d5332014-02-19 23:08:35 -08001191 // Add all active ports
Pavlin Radoslavovc1cfde52014-02-19 11:35:29 -08001192 for (RCPort p : RCPort.getAllPorts()) {
1193 if (p.getStatus() != RCPort.STATUS.ACTIVE) {
1194 continue;
Yuta HIGUCHIa536e762014-02-17 21:47:28 -08001195 }
Pavlin Radoslavov018d5332014-02-19 23:08:35 -08001196
1197 PortEvent portEvent = new PortEvent(p.getDpid(), p.getNumber());
1198 TopologyEvent topologyEvent = new TopologyEvent(portEvent);
1199 EventEntry<TopologyEvent> eventEntry =
1200 new EventEntry<TopologyEvent>(EventEntry.Type.ENTRY_ADD,
1201 topologyEvent);
1202 collection.add(eventEntry);
Yuta HIGUCHIa536e762014-02-17 21:47:28 -08001203 }
1204
Pavlin Radoslavovc1cfde52014-02-19 11:35:29 -08001205 // TODO Is Device going to be in DB? If so, read from DB.
1206 // for (RCDevice d : RCDevice.getAllDevices()) {
1207 // DeviceEvent devEvent = new DeviceEvent( MACAddress.valueOf(d.getMac()) );
1208 // for (byte[] portId : d.getAllPortIds() ) {
1209 // devEvent.addAttachmentPoint( new SwitchPort( RCPort.getDpidFromKey(portId), RCPort.getNumberFromKey(portId) ));
1210 // }
1211 // }
1212
1213 for (RCLink l : RCLink.getAllLinks()) {
1214 // check if src/dst switch/port exist before triggering event
1215 Port srcPort = networkGraph.getPort(l.getSrc().dpid,
1216 l.getSrc().number);
1217 Port dstPort = networkGraph.getPort(l.getDst().dpid,
1218 l.getDst().number);
1219 if (srcPort == null || dstPort == null) {
1220 continue;
Yuta HIGUCHI76df2472014-02-12 22:36:51 -08001221 }
Pavlin Radoslavov018d5332014-02-19 23:08:35 -08001222
1223 LinkEvent linkEvent = new LinkEvent(l.getSrc().dpid,
1224 l.getSrc().number,
1225 l.getDst().dpid,
1226 l.getDst().number);
1227 TopologyEvent topologyEvent = new TopologyEvent(linkEvent);
1228 EventEntry<TopologyEvent> eventEntry =
1229 new EventEntry<TopologyEvent>(EventEntry.Type.ENTRY_ADD,
1230 topologyEvent);
1231 collection.add(eventEntry);
Yuta HIGUCHI76df2472014-02-12 22:36:51 -08001232 }
Pavlin Radoslavov018d5332014-02-19 23:08:35 -08001233
1234 return collection;
Pavlin Radoslavovc1cfde52014-02-19 11:35:29 -08001235 }
Pavlin Radoslavov50cd1482014-02-19 16:57:03 -08001236
1237 @Deprecated
1238 private void removeLinkDiscoveryEvent(LinkEvent linkEvent,
1239 boolean dstCheckBeforeDBmodify) {
1240 if (prepareForRemoveLinkEvent(linkEvent)) {
1241 if (dstCheckBeforeDBmodify) {
1242 // write to DB only if it is owner of the dst dpid
1243 // XXX this will cause link remove events to be dropped
1244 // if the dst switch just disconnected
1245 if (registryService.hasControl(linkEvent.getDst().dpid)) {
1246 datastore.removeLink(linkEvent);
1247 }
1248 } else {
1249 datastore.removeLink(linkEvent);
1250 }
1251 removeLink(linkEvent);
1252 // Send out notification
1253 eventChannel.removeEntry(linkEvent.getID());
1254 }
1255 // TODO handle invariant violation
1256 }
Jonathan Hart062a2e82014-02-03 09:41:57 -08001257}