blob: d915042bc86c36c220ac261fb499f2b120f1c44a [file] [log] [blame]
Jonathan Hart472062d2014-04-03 10:56:48 -07001package net.onrc.onos.core.topology;
Jonathan Hart062a2e82014-02-03 09:41:57 -08002
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
Jonathan Hart6df90172014-04-03 10:13:11 -070017import net.onrc.onos.core.datagrid.IDatagridService;
18import net.onrc.onos.core.datagrid.IEventChannel;
19import net.onrc.onos.core.datagrid.IEventChannelListener;
20import net.onrc.onos.core.datastore.topology.KVLink;
21import net.onrc.onos.core.datastore.topology.KVPort;
22import net.onrc.onos.core.datastore.topology.KVSwitch;
Jonathan Hartdeda0ba2014-04-03 11:14:12 -070023import net.onrc.onos.core.registry.IControllerRegistryService;
Jonathan Hart472062d2014-04-03 10:56:48 -070024import net.onrc.onos.core.topology.PortEvent.SwitchPort;
Jonathan Hart23701d12014-04-03 10:45:48 -070025import net.onrc.onos.core.util.EventEntry;
Jonathan Hart062a2e82014-02-03 09:41:57 -080026
27import org.slf4j.Logger;
28import org.slf4j.LoggerFactory;
29
Yuta HIGUCHI181d34d2014-02-05 15:05:46 -080030/**
31 * The "NB" read-only Network Map.
Ray Milkey269ffb92014-04-03 14:43:30 -070032 * <p/>
Yuta HIGUCHI4bfdd532014-02-07 13:47:36 -080033 * - Maintain Invariant/Relationships between Topology Objects.
Ray Milkey269ffb92014-04-03 14:43:30 -070034 * <p/>
Yuta HIGUCHI765cd0d2014-02-06 12:46:41 -080035 * TODO To be synchronized based on TopologyEvent Notification.
Ray Milkey269ffb92014-04-03 14:43:30 -070036 * <p/>
Yuta HIGUCHIcb951982014-02-11 13:31:44 -080037 * TODO TBD: Caller is expected to maintain parent/child calling order. Parent
Yuta HIGUCHI1c700102014-02-12 16:30:52 -080038 * Object must exist before adding sub component(Add Switch -> Port).
Ray Milkey269ffb92014-04-03 14:43:30 -070039 * <p/>
Yuta HIGUCHI4bfdd532014-02-07 13:47:36 -080040 * TODO TBD: This class may delay the requested change to handle event
41 * re-ordering. e.g.) Link Add came in, but Switch was not there.
Yuta HIGUCHI181d34d2014-02-05 15:05:46 -080042 */
Pavlin Radoslavov87dcc262014-02-19 21:13:23 -080043public class TopologyManager implements NetworkGraphDiscoveryInterface {
Jonathan Hart062a2e82014-02-03 09:41:57 -080044
Yuta HIGUCHI80829d12014-02-05 20:16:56 -080045 private static final Logger log = LoggerFactory
Ray Milkey269ffb92014-04-03 14:43:30 -070046 .getLogger(TopologyManager.class);
Yuta HIGUCHIcd922f42014-02-11 18:59:11 -080047
Pavlin Radoslavov721a2e02014-02-14 23:40:14 -080048 private IEventChannel<byte[], TopologyEvent> eventChannel;
Jonathan Hart10a7e2b2014-02-21 18:30:08 -080049 public static final String EVENT_CHANNEL_NAME = "onos.topology";
Pavlin Radoslavov721a2e02014-02-14 23:40:14 -080050 private EventHandler eventHandler = new EventHandler();
51
Jonathan Hart22eb9882014-02-11 15:52:59 -080052 private final NetworkGraphDatastore datastore;
Pavlin Radoslavov6d224ee2014-02-18 16:43:15 -080053 private final NetworkGraphImpl networkGraph = new NetworkGraphImpl();
Yuta HIGUCHI170229f2014-02-17 15:47:54 -080054 private final IControllerRegistryService registryService;
Yuta HIGUCHIa536e762014-02-17 21:47:28 -080055 private CopyOnWriteArrayList<INetworkGraphListener> networkGraphListeners;
Yuta HIGUCHI181d34d2014-02-05 15:05:46 -080056
Pavlin Radoslavov706add22014-02-20 12:15:59 -080057 //
58 // Local state for keeping track of reordered events.
59 // NOTE: Switch Events are not affected by the event reordering.
60 //
61 private Map<ByteBuffer, PortEvent> reorderedAddedPortEvents =
Ray Milkey269ffb92014-04-03 14:43:30 -070062 new HashMap<ByteBuffer, PortEvent>();
Pavlin Radoslavov706add22014-02-20 12:15:59 -080063 private Map<ByteBuffer, LinkEvent> reorderedAddedLinkEvents =
Ray Milkey269ffb92014-04-03 14:43:30 -070064 new HashMap<ByteBuffer, LinkEvent>();
Pavlin Radoslavov706add22014-02-20 12:15:59 -080065 private Map<ByteBuffer, DeviceEvent> reorderedAddedDeviceEvents =
Ray Milkey269ffb92014-04-03 14:43:30 -070066 new HashMap<ByteBuffer, DeviceEvent>();
Pavlin Radoslavov018d5332014-02-19 23:08:35 -080067
Pavlin Radoslavov74986ce2014-02-20 13:17:20 -080068 //
Pavlin Radoslavov26d83402014-02-20 15:24:30 -080069 // Local state for keeping track of locally discovered events so we can
70 // cleanup properly when a Switch or Port is removed.
71 //
72 // We keep all Port, Link and Device events per Switch DPID:
73 // - If a switch goes down, we remove all corresponding Port, Link and
74 // Device events.
75 // - If a port on a switch goes down, we remove all corresponding Link
76 // and Device events.
77 //
78 private Map<Long, Map<ByteBuffer, PortEvent>> discoveredAddedPortEvents =
Ray Milkey269ffb92014-04-03 14:43:30 -070079 new HashMap<>();
Pavlin Radoslavov26d83402014-02-20 15:24:30 -080080 private Map<Long, Map<ByteBuffer, LinkEvent>> discoveredAddedLinkEvents =
Ray Milkey269ffb92014-04-03 14:43:30 -070081 new HashMap<>();
Pavlin Radoslavov26d83402014-02-20 15:24:30 -080082 private Map<Long, Map<ByteBuffer, DeviceEvent>> discoveredAddedDeviceEvents =
Ray Milkey269ffb92014-04-03 14:43:30 -070083 new HashMap<>();
Pavlin Radoslavov26d83402014-02-20 15:24:30 -080084
85 //
Pavlin Radoslavov74986ce2014-02-20 13:17:20 -080086 // Local state for keeping track of the application event notifications
87 //
88 List<SwitchEvent> apiAddedSwitchEvents = new LinkedList<SwitchEvent>();
89 List<SwitchEvent> apiRemovedSwitchEvents = new LinkedList<SwitchEvent>();
90 List<PortEvent> apiAddedPortEvents = new LinkedList<PortEvent>();
91 List<PortEvent> apiRemovedPortEvents = new LinkedList<PortEvent>();
92 List<LinkEvent> apiAddedLinkEvents = new LinkedList<LinkEvent>();
93 List<LinkEvent> apiRemovedLinkEvents = new LinkedList<LinkEvent>();
94 List<DeviceEvent> apiAddedDeviceEvents = new LinkedList<DeviceEvent>();
95 List<DeviceEvent> apiRemovedDeviceEvents = new LinkedList<DeviceEvent>();
96
Pavlin Radoslavovc1cfde52014-02-19 11:35:29 -080097 /**
98 * Constructor.
99 *
Ray Milkey269ffb92014-04-03 14:43:30 -0700100 * @param registryService the Registry Service to use.
Pavlin Radoslavovc1cfde52014-02-19 11:35:29 -0800101 * @param networkGraphListeners the collection of Network Graph Listeners
Ray Milkey269ffb92014-04-03 14:43:30 -0700102 * to use.
Pavlin Radoslavovc1cfde52014-02-19 11:35:29 -0800103 */
104 public TopologyManager(IControllerRegistryService registryService,
Ray Milkey269ffb92014-04-03 14:43:30 -0700105 CopyOnWriteArrayList<INetworkGraphListener> networkGraphListeners) {
106 datastore = new NetworkGraphDatastore();
107 this.registryService = registryService;
108 this.networkGraphListeners = networkGraphListeners;
Yuta HIGUCHI80829d12014-02-05 20:16:56 -0800109 }
Yuta HIGUCHI181d34d2014-02-05 15:05:46 -0800110
Pavlin Radoslavovc1cfde52014-02-19 11:35:29 -0800111 /**
112 * Get the Network Graph.
113 *
114 * @return the Network Graph.
115 */
Pavlin Radoslavov6d224ee2014-02-18 16:43:15 -0800116 NetworkGraph getNetworkGraph() {
Ray Milkey269ffb92014-04-03 14:43:30 -0700117 return networkGraph;
Pavlin Radoslavov6d224ee2014-02-18 16:43:15 -0800118 }
119
Yuta HIGUCHI4bfdd532014-02-07 13:47:36 -0800120 /**
Pavlin Radoslavov721a2e02014-02-14 23:40:14 -0800121 * Event handler class.
122 */
123 private class EventHandler extends Thread implements
Ray Milkey269ffb92014-04-03 14:43:30 -0700124 IEventChannelListener<byte[], TopologyEvent> {
125 private BlockingQueue<EventEntry<TopologyEvent>> topologyEvents =
126 new LinkedBlockingQueue<EventEntry<TopologyEvent>>();
Pavlin Radoslavov721a2e02014-02-14 23:40:14 -0800127
Ray Milkey269ffb92014-04-03 14:43:30 -0700128 /**
129 * Startup processing.
130 */
131 private void startup() {
132 //
133 // TODO: Read all state from the database:
134 //
135 // Collection<EventEntry<TopologyEvent>> collection =
136 // readWholeTopologyFromDB();
137 //
138 // For now, as a shortcut we read it from the datagrid
139 //
140 Collection<TopologyEvent> topologyEvents =
141 eventChannel.getAllEntries();
142 Collection<EventEntry<TopologyEvent>> collection =
143 new LinkedList<EventEntry<TopologyEvent>>();
Pavlin Radoslavov721a2e02014-02-14 23:40:14 -0800144
Ray Milkey269ffb92014-04-03 14:43:30 -0700145 for (TopologyEvent topologyEvent : topologyEvents) {
146 EventEntry<TopologyEvent> eventEntry =
147 new EventEntry<TopologyEvent>(EventEntry.Type.ENTRY_ADD,
148 topologyEvent);
149 collection.add(eventEntry);
150 }
151 processEvents(collection);
152 }
Pavlin Radoslavov721a2e02014-02-14 23:40:14 -0800153
Ray Milkey269ffb92014-04-03 14:43:30 -0700154 /**
155 * Run the thread.
156 */
157 @Override
158 public void run() {
159 Collection<EventEntry<TopologyEvent>> collection =
160 new LinkedList<EventEntry<TopologyEvent>>();
Pavlin Radoslavov721a2e02014-02-14 23:40:14 -0800161
Ray Milkey269ffb92014-04-03 14:43:30 -0700162 this.setName("TopologyManager.EventHandler " + this.getId());
163 startup();
Pavlin Radoslavov721a2e02014-02-14 23:40:14 -0800164
Ray Milkey269ffb92014-04-03 14:43:30 -0700165 //
166 // The main loop
167 //
168 try {
169 while (true) {
170 EventEntry<TopologyEvent> eventEntry = topologyEvents.take();
171 collection.add(eventEntry);
172 topologyEvents.drainTo(collection);
Pavlin Radoslavov721a2e02014-02-14 23:40:14 -0800173
Ray Milkey269ffb92014-04-03 14:43:30 -0700174 processEvents(collection);
175 collection.clear();
176 }
177 } catch (Exception exception) {
178 log.debug("Exception processing Topology Events: ", exception);
179 }
180 }
Pavlin Radoslavov721a2e02014-02-14 23:40:14 -0800181
Ray Milkey269ffb92014-04-03 14:43:30 -0700182 /**
183 * Process all topology events.
184 *
185 * @param events the events to process.
186 */
187 private void processEvents(Collection<EventEntry<TopologyEvent>> events) {
188 // Local state for computing the final set of events
189 Map<ByteBuffer, SwitchEvent> addedSwitchEvents = new HashMap<>();
190 Map<ByteBuffer, SwitchEvent> removedSwitchEvents = new HashMap<>();
191 Map<ByteBuffer, PortEvent> addedPortEvents = new HashMap<>();
192 Map<ByteBuffer, PortEvent> removedPortEvents = new HashMap<>();
193 Map<ByteBuffer, LinkEvent> addedLinkEvents = new HashMap<>();
194 Map<ByteBuffer, LinkEvent> removedLinkEvents = new HashMap<>();
195 Map<ByteBuffer, DeviceEvent> addedDeviceEvents = new HashMap<>();
196 Map<ByteBuffer, DeviceEvent> removedDeviceEvents = new HashMap<>();
Pavlin Radoslavov3c9cc552014-02-20 09:58:38 -0800197
Ray Milkey269ffb92014-04-03 14:43:30 -0700198 //
199 // Classify and suppress matching events
200 //
201 for (EventEntry<TopologyEvent> event : events) {
202 TopologyEvent topologyEvent = event.eventData();
203 SwitchEvent switchEvent = topologyEvent.switchEvent;
204 PortEvent portEvent = topologyEvent.portEvent;
205 LinkEvent linkEvent = topologyEvent.linkEvent;
206 DeviceEvent deviceEvent = topologyEvent.deviceEvent;
Pavlin Radoslavov018d5332014-02-19 23:08:35 -0800207
Ray Milkey269ffb92014-04-03 14:43:30 -0700208 //
209 // Extract the events
210 //
211 switch (event.eventType()) {
212 case ENTRY_ADD:
213 log.debug("Topology event ENTRY_ADD: {}", topologyEvent);
214 if (switchEvent != null) {
215 ByteBuffer id = switchEvent.getIDasByteBuffer();
216 addedSwitchEvents.put(id, switchEvent);
217 removedSwitchEvents.remove(id);
218 // Switch Events are not affected by event reordering
219 }
220 if (portEvent != null) {
221 ByteBuffer id = portEvent.getIDasByteBuffer();
222 addedPortEvents.put(id, portEvent);
223 removedPortEvents.remove(id);
224 reorderedAddedPortEvents.remove(id);
225 }
226 if (linkEvent != null) {
227 ByteBuffer id = linkEvent.getIDasByteBuffer();
228 addedLinkEvents.put(id, linkEvent);
229 removedLinkEvents.remove(id);
230 reorderedAddedLinkEvents.remove(id);
231 }
232 if (deviceEvent != null) {
233 ByteBuffer id = deviceEvent.getIDasByteBuffer();
234 addedDeviceEvents.put(id, deviceEvent);
235 removedDeviceEvents.remove(id);
236 reorderedAddedDeviceEvents.remove(id);
237 }
238 break;
239 case ENTRY_REMOVE:
240 log.debug("Topology event ENTRY_REMOVE: {}", topologyEvent);
241 if (switchEvent != null) {
242 ByteBuffer id = switchEvent.getIDasByteBuffer();
243 addedSwitchEvents.remove(id);
244 removedSwitchEvents.put(id, switchEvent);
245 // Switch Events are not affected by event reordering
246 }
247 if (portEvent != null) {
248 ByteBuffer id = portEvent.getIDasByteBuffer();
249 addedPortEvents.remove(id);
250 removedPortEvents.put(id, portEvent);
251 reorderedAddedPortEvents.remove(id);
252 }
253 if (linkEvent != null) {
254 ByteBuffer id = linkEvent.getIDasByteBuffer();
255 addedLinkEvents.remove(id);
256 removedLinkEvents.put(id, linkEvent);
257 reorderedAddedLinkEvents.remove(id);
258 }
259 if (deviceEvent != null) {
260 ByteBuffer id = deviceEvent.getIDasByteBuffer();
261 addedDeviceEvents.remove(id);
262 removedDeviceEvents.put(id, deviceEvent);
263 reorderedAddedDeviceEvents.remove(id);
264 }
265 break;
266 }
267 }
Pavlin Radoslavov3c9cc552014-02-20 09:58:38 -0800268
Ray Milkey269ffb92014-04-03 14:43:30 -0700269 //
270 // Lock the Network Graph while it is modified
271 //
272 networkGraph.acquireWriteLock();
Pavlin Radoslavov8ffb8bf2014-02-20 15:34:26 -0800273
Ray Milkey269ffb92014-04-03 14:43:30 -0700274 try {
275 //
276 // Apply the classified events.
277 //
278 // Apply the "add" events in the proper order:
279 // switch, port, link, device
280 //
281 for (SwitchEvent switchEvent : addedSwitchEvents.values())
282 addSwitch(switchEvent);
283 for (PortEvent portEvent : addedPortEvents.values())
284 addPort(portEvent);
285 for (LinkEvent linkEvent : addedLinkEvents.values())
286 addLink(linkEvent);
287 for (DeviceEvent deviceEvent : addedDeviceEvents.values())
288 addDevice(deviceEvent);
289 //
290 // Apply the "remove" events in the reverse order:
291 // device, link, port, switch
292 //
293 for (DeviceEvent deviceEvent : removedDeviceEvents.values())
294 removeDevice(deviceEvent);
295 for (LinkEvent linkEvent : removedLinkEvents.values())
296 removeLink(linkEvent);
297 for (PortEvent portEvent : removedPortEvents.values())
298 removePort(portEvent);
299 for (SwitchEvent switchEvent : removedSwitchEvents.values())
300 removeSwitch(switchEvent);
Yuta HIGUCHI3aca81a2014-02-23 12:41:19 -0800301
Ray Milkey269ffb92014-04-03 14:43:30 -0700302 //
303 // Apply reordered events
304 //
305 applyReorderedEvents(!addedSwitchEvents.isEmpty(),
306 !addedPortEvents.isEmpty());
Yuta HIGUCHI3aca81a2014-02-23 12:41:19 -0800307
Ray Milkey269ffb92014-04-03 14:43:30 -0700308 } finally {
309 //
310 // Network Graph modifications completed: Release the lock
311 //
312 networkGraph.releaseWriteLock();
313 }
Yuta HIGUCHI3aca81a2014-02-23 12:41:19 -0800314
Ray Milkey269ffb92014-04-03 14:43:30 -0700315 //
316 // Dispatch the Topology Notification Events to the applications
317 //
318 dispatchNetworkGraphEvents();
319 }
Pavlin Radoslavov721a2e02014-02-14 23:40:14 -0800320
Ray Milkey269ffb92014-04-03 14:43:30 -0700321 /**
322 * Receive a notification that an entry is added.
323 *
324 * @param value the value for the entry.
325 */
326 @Override
327 public void entryAdded(TopologyEvent value) {
328 EventEntry<TopologyEvent> eventEntry =
329 new EventEntry<TopologyEvent>(EventEntry.Type.ENTRY_ADD,
330 value);
331 topologyEvents.add(eventEntry);
332 }
Pavlin Radoslavov721a2e02014-02-14 23:40:14 -0800333
Ray Milkey269ffb92014-04-03 14:43:30 -0700334 /**
335 * Receive a notification that an entry is removed.
336 *
337 * @param value the value for the entry.
338 */
339 @Override
340 public void entryRemoved(TopologyEvent value) {
341 EventEntry<TopologyEvent> eventEntry =
342 new EventEntry<TopologyEvent>(EventEntry.Type.ENTRY_REMOVE,
343 value);
344 topologyEvents.add(eventEntry);
345 }
Pavlin Radoslavov721a2e02014-02-14 23:40:14 -0800346
Ray Milkey269ffb92014-04-03 14:43:30 -0700347 /**
348 * Receive a notification that an entry is updated.
349 *
350 * @param value the value for the entry.
351 */
352 @Override
353 public void entryUpdated(TopologyEvent value) {
354 // NOTE: The ADD and UPDATE events are processed in same way
355 entryAdded(value);
356 }
Pavlin Radoslavov721a2e02014-02-14 23:40:14 -0800357 }
358
359 /**
360 * Startup processing.
361 *
362 * @param datagridService the datagrid service to use.
363 */
364 void startup(IDatagridService datagridService) {
Ray Milkey269ffb92014-04-03 14:43:30 -0700365 eventChannel = datagridService.addListener(EVENT_CHANNEL_NAME,
366 eventHandler,
367 byte[].class,
368 TopologyEvent.class);
369 eventHandler.start();
Pavlin Radoslavov721a2e02014-02-14 23:40:14 -0800370 }
371
Pavlin Radoslavov74986ce2014-02-20 13:17:20 -0800372 /**
373 * Dispatch Network Graph Events to the listeners.
374 */
375 private void dispatchNetworkGraphEvents() {
Ray Milkey269ffb92014-04-03 14:43:30 -0700376 if (apiAddedSwitchEvents.isEmpty() &&
377 apiRemovedSwitchEvents.isEmpty() &&
378 apiAddedPortEvents.isEmpty() &&
379 apiRemovedPortEvents.isEmpty() &&
380 apiAddedLinkEvents.isEmpty() &&
381 apiRemovedLinkEvents.isEmpty() &&
382 apiAddedDeviceEvents.isEmpty() &&
383 apiRemovedDeviceEvents.isEmpty()) {
384 return; // No events to dispatch
385 }
Pavlin Radoslavov74986ce2014-02-20 13:17:20 -0800386
Ray Milkey269ffb92014-04-03 14:43:30 -0700387 if (log.isDebugEnabled()) {
388 //
389 // Debug statements
390 // TODO: Those statements should be removed in the future
391 //
392 for (SwitchEvent switchEvent : apiAddedSwitchEvents)
393 log.debug("Dispatch Network Graph Event: ADDED {}", switchEvent);
394 for (SwitchEvent switchEvent : apiRemovedSwitchEvents)
395 log.debug("Dispatch Network Graph Event: REMOVED {}", switchEvent);
396 for (PortEvent portEvent : apiAddedPortEvents)
397 log.debug("Dispatch Network Graph Event: ADDED {}", portEvent);
398 for (PortEvent portEvent : apiRemovedPortEvents)
399 log.debug("Dispatch Network Graph Event: REMOVED {}", portEvent);
400 for (LinkEvent linkEvent : apiAddedLinkEvents)
401 log.debug("Dispatch Network Graph Event: ADDED {}", linkEvent);
402 for (LinkEvent linkEvent : apiRemovedLinkEvents)
403 log.debug("Dispatch Network Graph Event: REMOVED {}", linkEvent);
404 for (DeviceEvent deviceEvent : apiAddedDeviceEvents)
405 log.debug("Dispatch Network Graph Event: ADDED {}", deviceEvent);
406 for (DeviceEvent deviceEvent : apiRemovedDeviceEvents)
407 log.debug("Dispatch Network Graph Event: REMOVED {}", deviceEvent);
408 }
adminbc181552014-02-21 18:36:42 -0800409
Ray Milkey269ffb92014-04-03 14:43:30 -0700410 // Deliver the events
411 for (INetworkGraphListener listener : this.networkGraphListeners) {
412 // TODO: Should copy before handing them over to listener?
413 listener.networkGraphEvents(apiAddedSwitchEvents,
414 apiRemovedSwitchEvents,
415 apiAddedPortEvents,
416 apiRemovedPortEvents,
417 apiAddedLinkEvents,
418 apiRemovedLinkEvents,
419 apiAddedDeviceEvents,
420 apiRemovedDeviceEvents);
421 }
Pavlin Radoslavov74986ce2014-02-20 13:17:20 -0800422
Ray Milkey269ffb92014-04-03 14:43:30 -0700423 //
424 // Cleanup
425 //
426 apiAddedSwitchEvents.clear();
427 apiRemovedSwitchEvents.clear();
428 apiAddedPortEvents.clear();
429 apiRemovedPortEvents.clear();
430 apiAddedLinkEvents.clear();
431 apiRemovedLinkEvents.clear();
432 apiAddedDeviceEvents.clear();
433 apiRemovedDeviceEvents.clear();
Pavlin Radoslavov74986ce2014-02-20 13:17:20 -0800434 }
435
436 /**
437 * Apply reordered events.
438 *
439 * @param hasAddedSwitchEvents true if there were Added Switch Events.
Ray Milkey269ffb92014-04-03 14:43:30 -0700440 * @param hasAddedPortEvents true if there were Added Port Events.
Pavlin Radoslavov74986ce2014-02-20 13:17:20 -0800441 */
442 private void applyReorderedEvents(boolean hasAddedSwitchEvents,
Ray Milkey269ffb92014-04-03 14:43:30 -0700443 boolean hasAddedPortEvents) {
444 if (!(hasAddedSwitchEvents || hasAddedPortEvents))
445 return; // Nothing to do
Pavlin Radoslavov74986ce2014-02-20 13:17:20 -0800446
Ray Milkey269ffb92014-04-03 14:43:30 -0700447 //
448 // Try to apply the reordered events.
449 //
450 // NOTE: For simplicity we try to apply all events of a particular
451 // type if any "parent" type event was processed:
452 // - Apply reordered Port Events if Switches were added
453 // - Apply reordered Link and Device Events if Switches or Ports
454 // were added
455 //
adminbc181552014-02-21 18:36:42 -0800456
Ray Milkey269ffb92014-04-03 14:43:30 -0700457 //
458 // Apply reordered Port Events if Switches were added
459 //
460 if (hasAddedSwitchEvents) {
461 Map<ByteBuffer, PortEvent> portEvents = reorderedAddedPortEvents;
462 reorderedAddedPortEvents = new HashMap<>();
463 for (PortEvent portEvent : portEvents.values())
464 addPort(portEvent);
465 }
466 //
467 // Apply reordered Link and Device Events if Switches or Ports
468 // were added.
469 //
470 Map<ByteBuffer, LinkEvent> linkEvents = reorderedAddedLinkEvents;
471 reorderedAddedLinkEvents = new HashMap<>();
472 for (LinkEvent linkEvent : linkEvents.values())
473 addLink(linkEvent);
474 //
475 Map<ByteBuffer, DeviceEvent> deviceEvents = reorderedAddedDeviceEvents;
476 reorderedAddedDeviceEvents = new HashMap<>();
477 for (DeviceEvent deviceEvent : deviceEvents.values())
478 addDevice(deviceEvent);
Pavlin Radoslavov74986ce2014-02-20 13:17:20 -0800479 }
480
Pavlin Radoslavov734ff5a2014-02-26 10:20:43 -0800481 /**
482 * Switch discovered event.
483 *
484 * @param switchEvent the switch event.
Ray Milkey269ffb92014-04-03 14:43:30 -0700485 * @param portEvents the corresponding port events for the switch.
Pavlin Radoslavov734ff5a2014-02-26 10:20:43 -0800486 */
Pavlin Radoslavovc1cfde52014-02-19 11:35:29 -0800487 @Override
Pavlin Radoslavov018d5332014-02-19 23:08:35 -0800488 public void putSwitchDiscoveryEvent(SwitchEvent switchEvent,
Ray Milkey269ffb92014-04-03 14:43:30 -0700489 Collection<PortEvent> portEvents) {
490 if (datastore.addSwitch(switchEvent, portEvents)) {
491 // Send out notification
492 TopologyEvent topologyEvent = new TopologyEvent(switchEvent);
493 eventChannel.addEntry(topologyEvent.getID(), topologyEvent);
Pavlin Radoslavov26d83402014-02-20 15:24:30 -0800494
Ray Milkey269ffb92014-04-03 14:43:30 -0700495 // Send out notification for each port
496 for (PortEvent portEvent : portEvents) {
497 topologyEvent = new TopologyEvent(portEvent);
498 eventChannel.addEntry(topologyEvent.getID(), topologyEvent);
499 }
Pavlin Radoslavov26d83402014-02-20 15:24:30 -0800500
Ray Milkey269ffb92014-04-03 14:43:30 -0700501 //
502 // Keep track of the added ports
503 //
504 // Get the old Port Events
505 Map<ByteBuffer, PortEvent> oldPortEvents =
506 discoveredAddedPortEvents.get(switchEvent.getDpid());
507 if (oldPortEvents == null)
508 oldPortEvents = new HashMap<>();
Pavlin Radoslavov26d83402014-02-20 15:24:30 -0800509
Ray Milkey269ffb92014-04-03 14:43:30 -0700510 // Store the new Port Events in the local cache
511 Map<ByteBuffer, PortEvent> newPortEvents = new HashMap<>();
512 for (PortEvent portEvent : portEvents) {
513 ByteBuffer id = portEvent.getIDasByteBuffer();
514 newPortEvents.put(id, portEvent);
515 }
516 discoveredAddedPortEvents.put(switchEvent.getDpid(),
517 newPortEvents);
Pavlin Radoslavov26d83402014-02-20 15:24:30 -0800518
Ray Milkey269ffb92014-04-03 14:43:30 -0700519 //
520 // Extract the removed ports
521 //
522 List<PortEvent> removedPortEvents = new LinkedList<>();
523 for (Map.Entry<ByteBuffer, PortEvent> entry : oldPortEvents.entrySet()) {
524 ByteBuffer key = entry.getKey();
525 PortEvent portEvent = entry.getValue();
526 if (!newPortEvents.containsKey(key))
527 removedPortEvents.add(portEvent);
528 }
529
530 // Cleanup old removed ports
531 for (PortEvent portEvent : removedPortEvents)
532 removePortDiscoveryEvent(portEvent);
533 }
Pavlin Radoslavovc1cfde52014-02-19 11:35:29 -0800534 }
535
Pavlin Radoslavov734ff5a2014-02-26 10:20:43 -0800536 /**
537 * Switch removed event.
538 *
539 * @param switchEvent the switch event.
540 */
Pavlin Radoslavovc1cfde52014-02-19 11:35:29 -0800541 @Override
Pavlin Radoslavov6ea84a42014-02-19 15:50:01 -0800542 public void removeSwitchDiscoveryEvent(SwitchEvent switchEvent) {
Ray Milkey269ffb92014-04-03 14:43:30 -0700543 // Get the old Port Events
544 Map<ByteBuffer, PortEvent> oldPortEvents =
545 discoveredAddedPortEvents.get(switchEvent.getDpid());
546 if (oldPortEvents == null)
547 oldPortEvents = new HashMap<>();
Pavlin Radoslavov018d5332014-02-19 23:08:35 -0800548
Ray Milkey269ffb92014-04-03 14:43:30 -0700549 if (datastore.deactivateSwitch(switchEvent, oldPortEvents.values())) {
550 // Send out notification
551 eventChannel.removeEntry(switchEvent.getID());
Pavlin Radoslavov018d5332014-02-19 23:08:35 -0800552
Ray Milkey269ffb92014-04-03 14:43:30 -0700553 //
554 // Send out notification for each port.
555 //
556 // NOTE: We don't use removePortDiscoveryEvent() for the cleanup,
557 // because it will attempt to remove the port from the database,
558 // and the deactiveSwitch() call above already removed all ports.
559 //
560 for (PortEvent portEvent : oldPortEvents.values())
561 eventChannel.removeEntry(portEvent.getID());
562 discoveredAddedPortEvents.remove(switchEvent.getDpid());
Pavlin Radoslavov26d83402014-02-20 15:24:30 -0800563
Ray Milkey269ffb92014-04-03 14:43:30 -0700564 // Cleanup for each link
565 Map<ByteBuffer, LinkEvent> oldLinkEvents =
566 discoveredAddedLinkEvents.get(switchEvent.getDpid());
567 if (oldLinkEvents != null) {
568 for (LinkEvent linkEvent : new ArrayList<>(oldLinkEvents.values())) {
569 removeLinkDiscoveryEvent(linkEvent);
570 }
571 discoveredAddedLinkEvents.remove(switchEvent.getDpid());
572 }
Pavlin Radoslavov26d83402014-02-20 15:24:30 -0800573
Ray Milkey269ffb92014-04-03 14:43:30 -0700574 // Cleanup for each device
575 Map<ByteBuffer, DeviceEvent> oldDeviceEvents =
576 discoveredAddedDeviceEvents.get(switchEvent.getDpid());
577 if (oldDeviceEvents != null) {
578 for (DeviceEvent deviceEvent : new ArrayList<>(oldDeviceEvents.values())) {
579 removeDeviceDiscoveryEvent(deviceEvent);
580 }
581 discoveredAddedDeviceEvents.remove(switchEvent.getDpid());
582 }
583 }
Pavlin Radoslavovc1cfde52014-02-19 11:35:29 -0800584 }
585
Pavlin Radoslavov734ff5a2014-02-26 10:20:43 -0800586 /**
587 * Port discovered event.
588 *
589 * @param portEvent the port event.
590 */
Pavlin Radoslavovc1cfde52014-02-19 11:35:29 -0800591 @Override
Pavlin Radoslavov6ea84a42014-02-19 15:50:01 -0800592 public void putPortDiscoveryEvent(PortEvent portEvent) {
Ray Milkey269ffb92014-04-03 14:43:30 -0700593 if (datastore.addPort(portEvent)) {
594 // Send out notification
595 TopologyEvent topologyEvent = new TopologyEvent(portEvent);
596 eventChannel.addEntry(topologyEvent.getID(), topologyEvent);
Pavlin Radoslavov26d83402014-02-20 15:24:30 -0800597
Ray Milkey269ffb92014-04-03 14:43:30 -0700598 // Store the new Port Event in the local cache
599 Map<ByteBuffer, PortEvent> oldPortEvents =
600 discoveredAddedPortEvents.get(portEvent.getDpid());
601 if (oldPortEvents == null) {
602 oldPortEvents = new HashMap<>();
603 discoveredAddedPortEvents.put(portEvent.getDpid(),
604 oldPortEvents);
605 }
606 ByteBuffer id = portEvent.getIDasByteBuffer();
607 oldPortEvents.put(id, portEvent);
608 }
Pavlin Radoslavovc1cfde52014-02-19 11:35:29 -0800609 }
610
Pavlin Radoslavov734ff5a2014-02-26 10:20:43 -0800611 /**
612 * Port removed event.
613 *
614 * @param portEvent the port event.
615 */
Pavlin Radoslavovc1cfde52014-02-19 11:35:29 -0800616 @Override
Pavlin Radoslavov6ea84a42014-02-19 15:50:01 -0800617 public void removePortDiscoveryEvent(PortEvent portEvent) {
Ray Milkey269ffb92014-04-03 14:43:30 -0700618 if (datastore.deactivatePort(portEvent)) {
619 // Send out notification
620 eventChannel.removeEntry(portEvent.getID());
Pavlin Radoslavov26d83402014-02-20 15:24:30 -0800621
Ray Milkey269ffb92014-04-03 14:43:30 -0700622 // Cleanup the Port Event from the local cache
623 Map<ByteBuffer, PortEvent> oldPortEvents =
624 discoveredAddedPortEvents.get(portEvent.getDpid());
625 if (oldPortEvents != null) {
626 ByteBuffer id = portEvent.getIDasByteBuffer();
627 oldPortEvents.remove(id);
628 }
Pavlin Radoslavov26d83402014-02-20 15:24:30 -0800629
Ray Milkey269ffb92014-04-03 14:43:30 -0700630 // Cleanup for the incoming link
631 Map<ByteBuffer, LinkEvent> oldLinkEvents =
632 discoveredAddedLinkEvents.get(portEvent.getDpid());
633 if (oldLinkEvents != null) {
634 for (LinkEvent linkEvent : new ArrayList<>(oldLinkEvents.values())) {
635 if (linkEvent.getDst().equals(portEvent.id)) {
636 removeLinkDiscoveryEvent(linkEvent);
637 // XXX If we change our model to allow multiple Link on
638 // a Port, this loop must be fixed to allow continuing.
639 break;
640 }
641 }
642 }
Pavlin Radoslavov26d83402014-02-20 15:24:30 -0800643
Ray Milkey269ffb92014-04-03 14:43:30 -0700644 // Cleanup for the connected devices
645 // TODO: The implementation below is probably wrong
646 List<DeviceEvent> removedDeviceEvents = new LinkedList<>();
647 Map<ByteBuffer, DeviceEvent> oldDeviceEvents =
648 discoveredAddedDeviceEvents.get(portEvent.getDpid());
649 if (oldDeviceEvents != null) {
650 for (DeviceEvent deviceEvent : new ArrayList<>(oldDeviceEvents.values())) {
651 for (SwitchPort swp : deviceEvent.getAttachmentPoints()) {
652 if (swp.equals(portEvent.id)) {
653 removedDeviceEvents.add(deviceEvent);
654 }
655 }
656 }
657 for (DeviceEvent deviceEvent : removedDeviceEvents)
658 removeDeviceDiscoveryEvent(deviceEvent);
659 }
660 }
Pavlin Radoslavovc1cfde52014-02-19 11:35:29 -0800661 }
662
Pavlin Radoslavov734ff5a2014-02-26 10:20:43 -0800663 /**
664 * Link discovered event.
665 *
666 * @param linkEvent the link event.
667 */
Pavlin Radoslavovc1cfde52014-02-19 11:35:29 -0800668 @Override
Pavlin Radoslavov6ea84a42014-02-19 15:50:01 -0800669 public void putLinkDiscoveryEvent(LinkEvent linkEvent) {
Ray Milkey269ffb92014-04-03 14:43:30 -0700670 if (datastore.addLink(linkEvent)) {
671 // Send out notification
672 TopologyEvent topologyEvent = new TopologyEvent(linkEvent);
673 eventChannel.addEntry(topologyEvent.getID(), topologyEvent);
Pavlin Radoslavov26d83402014-02-20 15:24:30 -0800674
Ray Milkey269ffb92014-04-03 14:43:30 -0700675 // Store the new Link Event in the local cache
676 Map<ByteBuffer, LinkEvent> oldLinkEvents =
677 discoveredAddedLinkEvents.get(linkEvent.getDst().getDpid());
678 if (oldLinkEvents == null) {
679 oldLinkEvents = new HashMap<>();
680 discoveredAddedLinkEvents.put(linkEvent.getDst().getDpid(),
681 oldLinkEvents);
682 }
683 ByteBuffer id = linkEvent.getIDasByteBuffer();
684 oldLinkEvents.put(id, linkEvent);
685 }
Pavlin Radoslavovc1cfde52014-02-19 11:35:29 -0800686 }
687
Pavlin Radoslavov734ff5a2014-02-26 10:20:43 -0800688 /**
689 * Link removed event.
690 *
691 * @param linkEvent the link event.
692 */
Pavlin Radoslavovc1cfde52014-02-19 11:35:29 -0800693 @Override
Pavlin Radoslavov6ea84a42014-02-19 15:50:01 -0800694 public void removeLinkDiscoveryEvent(LinkEvent linkEvent) {
Ray Milkey269ffb92014-04-03 14:43:30 -0700695 if (datastore.removeLink(linkEvent)) {
696 // Send out notification
697 eventChannel.removeEntry(linkEvent.getID());
Pavlin Radoslavov26d83402014-02-20 15:24:30 -0800698
Ray Milkey269ffb92014-04-03 14:43:30 -0700699 // Cleanup the Link Event from the local cache
700 Map<ByteBuffer, LinkEvent> oldLinkEvents =
701 discoveredAddedLinkEvents.get(linkEvent.getDst().getDpid());
702 if (oldLinkEvents != null) {
703 ByteBuffer id = linkEvent.getIDasByteBuffer();
704 oldLinkEvents.remove(id);
705 }
706 }
Pavlin Radoslavovc1cfde52014-02-19 11:35:29 -0800707 }
Jonathan Hart22eb9882014-02-11 15:52:59 -0800708
Pavlin Radoslavov734ff5a2014-02-26 10:20:43 -0800709 /**
710 * Device discovered event.
711 *
712 * @param deviceEvent the device event.
713 */
Pavlin Radoslavovc1cfde52014-02-19 11:35:29 -0800714 @Override
Pavlin Radoslavov6ea84a42014-02-19 15:50:01 -0800715 public void putDeviceDiscoveryEvent(DeviceEvent deviceEvent) {
Ray Milkey269ffb92014-04-03 14:43:30 -0700716 if (datastore.addDevice(deviceEvent)) {
717 // Send out notification
718 TopologyEvent topologyEvent = new TopologyEvent(deviceEvent);
719 eventChannel.addEntry(topologyEvent.getID(), topologyEvent);
720 log.debug("Put the device info into the cache of the graph. mac {}", deviceEvent.getMac());
721
722 // Store the new Device Event in the local cache
723 // TODO: The implementation below is probably wrong
724 for (SwitchPort swp : deviceEvent.getAttachmentPoints()) {
725 Map<ByteBuffer, DeviceEvent> oldDeviceEvents =
726 discoveredAddedDeviceEvents.get(swp.getDpid());
727 if (oldDeviceEvents == null) {
728 oldDeviceEvents = new HashMap<>();
729 discoveredAddedDeviceEvents.put(swp.getDpid(),
730 oldDeviceEvents);
731 }
732 ByteBuffer id = deviceEvent.getIDasByteBuffer();
733 oldDeviceEvents.put(id, deviceEvent);
734 }
735 }
Pavlin Radoslavovc1cfde52014-02-19 11:35:29 -0800736 }
Jonathan Hart22eb9882014-02-11 15:52:59 -0800737
Pavlin Radoslavov734ff5a2014-02-26 10:20:43 -0800738 /**
739 * Device removed event.
740 *
741 * @param deviceEvent the device event.
742 */
Pavlin Radoslavovc1cfde52014-02-19 11:35:29 -0800743 @Override
Pavlin Radoslavov6ea84a42014-02-19 15:50:01 -0800744 public void removeDeviceDiscoveryEvent(DeviceEvent deviceEvent) {
Ray Milkey269ffb92014-04-03 14:43:30 -0700745 if (datastore.removeDevice(deviceEvent)) {
746 // Send out notification
747 eventChannel.removeEntry(deviceEvent.getID());
748 log.debug("Remove the device info into the cache of the graph. mac {}", deviceEvent.getMac());
Pavlin Radoslavov26d83402014-02-20 15:24:30 -0800749
Ray Milkey269ffb92014-04-03 14:43:30 -0700750 // Cleanup the Device Event from the local cache
751 // TODO: The implementation below is probably wrong
752 ByteBuffer id = ByteBuffer.wrap(deviceEvent.getID());
753 for (SwitchPort swp : deviceEvent.getAttachmentPoints()) {
754 Map<ByteBuffer, DeviceEvent> oldDeviceEvents =
755 discoveredAddedDeviceEvents.get(swp.getDpid());
756 if (oldDeviceEvents != null) {
757 oldDeviceEvents.remove(id);
758 }
759 }
760 }
Pavlin Radoslavovc1cfde52014-02-19 11:35:29 -0800761 }
Jonathan Hart22eb9882014-02-11 15:52:59 -0800762
Pavlin Radoslavov734ff5a2014-02-26 10:20:43 -0800763 /**
764 * Add a switch to the Network Graph.
765 *
766 * @param switchEvent the Switch Event with the switch to add.
767 */
Pavlin Radoslavov74986ce2014-02-20 13:17:20 -0800768 private void addSwitch(SwitchEvent switchEvent) {
Ray Milkey269ffb92014-04-03 14:43:30 -0700769 Switch sw = networkGraph.getSwitch(switchEvent.getDpid());
770 if (sw == null) {
771 sw = new SwitchImpl(networkGraph, switchEvent.getDpid());
772 networkGraph.putSwitch(sw);
773 } else {
774 // TODO: Update the switch attributes
775 // TODO: Nothing to do for now
Ray Milkey1aa71f82014-04-08 16:23:24 -0700776 log.debug("Update switch attributes");
Ray Milkey269ffb92014-04-03 14:43:30 -0700777 }
778 apiAddedSwitchEvents.add(switchEvent);
Pavlin Radoslavov3c9cc552014-02-20 09:58:38 -0800779 }
780
Pavlin Radoslavov734ff5a2014-02-26 10:20:43 -0800781 /**
782 * Remove a switch from the Network Graph.
783 *
784 * @param switchEvent the Switch Event with the switch to remove.
785 */
Pavlin Radoslavov74986ce2014-02-20 13:17:20 -0800786 private void removeSwitch(SwitchEvent switchEvent) {
Ray Milkey269ffb92014-04-03 14:43:30 -0700787 Switch sw = networkGraph.getSwitch(switchEvent.getDpid());
788 if (sw == null) {
789 log.warn("Switch {} already removed, ignoring", switchEvent);
790 return;
791 }
Pavlin Radoslavov3c9cc552014-02-20 09:58:38 -0800792
Ray Milkey269ffb92014-04-03 14:43:30 -0700793 //
794 // Remove all Ports on the Switch
795 //
796 ArrayList<PortEvent> portsToRemove = new ArrayList<>();
797 for (Port port : sw.getPorts()) {
798 log.warn("Port {} on Switch {} should be removed prior to removing Switch. Removing Port now.",
799 port, switchEvent);
800 PortEvent portEvent = new PortEvent(port.getDpid(),
801 port.getNumber());
802 portsToRemove.add(portEvent);
803 }
804 for (PortEvent portEvent : portsToRemove)
805 removePort(portEvent);
Pavlin Radoslavov3c9cc552014-02-20 09:58:38 -0800806
Ray Milkey269ffb92014-04-03 14:43:30 -0700807 networkGraph.removeSwitch(switchEvent.getDpid());
808 apiRemovedSwitchEvents.add(switchEvent);
Pavlin Radoslavov3c9cc552014-02-20 09:58:38 -0800809 }
810
Pavlin Radoslavov734ff5a2014-02-26 10:20:43 -0800811 /**
812 * Add a port to the Network Graph.
813 *
814 * @param portEvent the Port Event with the port to add.
815 */
Pavlin Radoslavov3c9cc552014-02-20 09:58:38 -0800816 private void addPort(PortEvent portEvent) {
Ray Milkey269ffb92014-04-03 14:43:30 -0700817 Switch sw = networkGraph.getSwitch(portEvent.getDpid());
818 if (sw == null) {
819 // Reordered event: delay the event in local cache
820 ByteBuffer id = portEvent.getIDasByteBuffer();
821 reorderedAddedPortEvents.put(id, portEvent);
822 return;
823 }
824 SwitchImpl switchImpl = getSwitchImpl(sw);
Pavlin Radoslavov3c9cc552014-02-20 09:58:38 -0800825
Ray Milkey269ffb92014-04-03 14:43:30 -0700826 Port port = sw.getPort(portEvent.getNumber());
827 if (port == null) {
828 port = new PortImpl(networkGraph, sw, portEvent.getNumber());
829 switchImpl.addPort(port);
830 } else {
831 // TODO: Update the port attributes
Ray Milkey1aa71f82014-04-08 16:23:24 -0700832 log.debug("Update port attributes");
Ray Milkey269ffb92014-04-03 14:43:30 -0700833 }
834 apiAddedPortEvents.add(portEvent);
Pavlin Radoslavov3c9cc552014-02-20 09:58:38 -0800835 }
836
Pavlin Radoslavov734ff5a2014-02-26 10:20:43 -0800837 /**
838 * Remove a port from the Network Graph.
839 *
840 * @param portEvent the Port Event with the port to remove.
841 */
Pavlin Radoslavov3c9cc552014-02-20 09:58:38 -0800842 private void removePort(PortEvent portEvent) {
Ray Milkey269ffb92014-04-03 14:43:30 -0700843 Switch sw = networkGraph.getSwitch(portEvent.getDpid());
844 if (sw == null) {
845 log.warn("Parent Switch for Port {} already removed, ignoring",
846 portEvent);
847 return;
848 }
Pavlin Radoslavov3c9cc552014-02-20 09:58:38 -0800849
Ray Milkey269ffb92014-04-03 14:43:30 -0700850 Port port = sw.getPort(portEvent.getNumber());
851 if (port == null) {
852 log.warn("Port {} already removed, ignoring", portEvent);
853 return;
854 }
Pavlin Radoslavov3c9cc552014-02-20 09:58:38 -0800855
Ray Milkey269ffb92014-04-03 14:43:30 -0700856 //
857 // Remove all Devices attached to the Port
858 //
859 ArrayList<DeviceEvent> devicesToRemove = new ArrayList<>();
860 for (Device device : port.getDevices()) {
861 log.debug("Removing Device {} on Port {}", device, portEvent);
862 DeviceEvent deviceEvent = new DeviceEvent(device.getMacAddress());
863 SwitchPort switchPort = new SwitchPort(port.getSwitch().getDpid(),
864 port.getNumber());
865 deviceEvent.addAttachmentPoint(switchPort);
866 devicesToRemove.add(deviceEvent);
867 }
868 for (DeviceEvent deviceEvent : devicesToRemove)
869 removeDevice(deviceEvent);
Pavlin Radoslavov3c9cc552014-02-20 09:58:38 -0800870
Ray Milkey269ffb92014-04-03 14:43:30 -0700871 //
872 // Remove all Links connected to the Port
873 //
874 Set<Link> links = new HashSet<>();
875 links.add(port.getOutgoingLink());
876 links.add(port.getIncomingLink());
877 ArrayList<LinkEvent> linksToRemove = new ArrayList<>();
878 for (Link link : links) {
879 if (link == null)
880 continue;
881 log.debug("Removing Link {} on Port {}", link, portEvent);
882 LinkEvent linkEvent = new LinkEvent(link.getSrcSwitch().getDpid(),
883 link.getSrcPort().getNumber(),
884 link.getDstSwitch().getDpid(),
885 link.getDstPort().getNumber());
886 linksToRemove.add(linkEvent);
887 }
888 for (LinkEvent linkEvent : linksToRemove)
889 removeLink(linkEvent);
Pavlin Radoslavov3c9cc552014-02-20 09:58:38 -0800890
Ray Milkey269ffb92014-04-03 14:43:30 -0700891 // Remove the Port from the Switch
892 SwitchImpl switchImpl = getSwitchImpl(sw);
893 switchImpl.removePort(port);
Pavlin Radoslavov74986ce2014-02-20 13:17:20 -0800894
Ray Milkey269ffb92014-04-03 14:43:30 -0700895 apiRemovedPortEvents.add(portEvent);
Pavlin Radoslavov3c9cc552014-02-20 09:58:38 -0800896 }
897
Pavlin Radoslavov734ff5a2014-02-26 10:20:43 -0800898 /**
899 * Add a link to the Network Graph.
900 *
901 * @param linkEvent the Link Event with the link to add.
902 */
Pavlin Radoslavov3c9cc552014-02-20 09:58:38 -0800903 private void addLink(LinkEvent linkEvent) {
Ray Milkey269ffb92014-04-03 14:43:30 -0700904 Port srcPort = networkGraph.getPort(linkEvent.getSrc().dpid,
905 linkEvent.getSrc().number);
906 Port dstPort = networkGraph.getPort(linkEvent.getDst().dpid,
907 linkEvent.getDst().number);
908 if ((srcPort == null) || (dstPort == null)) {
909 // Reordered event: delay the event in local cache
910 ByteBuffer id = linkEvent.getIDasByteBuffer();
911 reorderedAddedLinkEvents.put(id, linkEvent);
912 return;
913 }
Pavlin Radoslavov3c9cc552014-02-20 09:58:38 -0800914
Ray Milkey269ffb92014-04-03 14:43:30 -0700915 // Get the Link instance from the Destination Port Incoming Link
916 Link link = dstPort.getIncomingLink();
917 assert (link == srcPort.getOutgoingLink());
918 if (link == null) {
919 link = new LinkImpl(networkGraph, srcPort, dstPort);
920 PortImpl srcPortImpl = getPortImpl(srcPort);
921 PortImpl dstPortImpl = getPortImpl(dstPort);
922 srcPortImpl.setOutgoingLink(link);
923 dstPortImpl.setIncomingLink(link);
Pavlin Radoslavov3c9cc552014-02-20 09:58:38 -0800924
Ray Milkey269ffb92014-04-03 14:43:30 -0700925 // Remove all Devices attached to the Ports
926 ArrayList<DeviceEvent> devicesToRemove = new ArrayList<>();
927 ArrayList<Port> ports = new ArrayList<>();
928 ports.add(srcPort);
929 ports.add(dstPort);
930 for (Port port : ports) {
931 for (Device device : port.getDevices()) {
932 log.error("Device {} on Port {} should have been removed prior to adding Link {}",
933 device, port, linkEvent);
934 DeviceEvent deviceEvent =
935 new DeviceEvent(device.getMacAddress());
936 SwitchPort switchPort =
937 new SwitchPort(port.getSwitch().getDpid(),
938 port.getNumber());
939 deviceEvent.addAttachmentPoint(switchPort);
940 devicesToRemove.add(deviceEvent);
941 }
942 }
943 for (DeviceEvent deviceEvent : devicesToRemove)
944 removeDevice(deviceEvent);
945 } else {
946 // TODO: Update the link attributes
Ray Milkey1aa71f82014-04-08 16:23:24 -0700947 log.debug("Update link attributes");
Ray Milkey269ffb92014-04-03 14:43:30 -0700948 }
Pavlin Radoslavov74986ce2014-02-20 13:17:20 -0800949
Ray Milkey269ffb92014-04-03 14:43:30 -0700950 apiAddedLinkEvents.add(linkEvent);
Pavlin Radoslavov3c9cc552014-02-20 09:58:38 -0800951 }
952
Pavlin Radoslavov734ff5a2014-02-26 10:20:43 -0800953 /**
954 * Remove a link from the Network Graph.
955 *
956 * @param linkEvent the Link Event with the link to remove.
957 */
Pavlin Radoslavov3c9cc552014-02-20 09:58:38 -0800958 private void removeLink(LinkEvent linkEvent) {
Ray Milkey269ffb92014-04-03 14:43:30 -0700959 Port srcPort = networkGraph.getPort(linkEvent.getSrc().dpid,
960 linkEvent.getSrc().number);
961 if (srcPort == null) {
962 log.warn("Src Port for Link {} already removed, ignoring",
963 linkEvent);
964 return;
965 }
Pavlin Radoslavov3c9cc552014-02-20 09:58:38 -0800966
Ray Milkey269ffb92014-04-03 14:43:30 -0700967 Port dstPort = networkGraph.getPort(linkEvent.getDst().dpid,
968 linkEvent.getDst().number);
969 if (dstPort == null) {
970 log.warn("Dst Port for Link {} already removed, ignoring",
971 linkEvent);
972 return;
973 }
Pavlin Radoslavov3c9cc552014-02-20 09:58:38 -0800974
Ray Milkey269ffb92014-04-03 14:43:30 -0700975 //
976 // Remove the Link instance from the Destination Port Incoming Link
977 // and the Source Port Outgoing Link.
978 //
979 Link link = dstPort.getIncomingLink();
980 if (link == null) {
981 log.warn("Link {} already removed on destination Port", linkEvent);
982 }
983 link = srcPort.getOutgoingLink();
984 if (link == null) {
985 log.warn("Link {} already removed on src Port", linkEvent);
986 }
987 getPortImpl(dstPort).setIncomingLink(null);
988 getPortImpl(srcPort).setOutgoingLink(null);
Pavlin Radoslavov74986ce2014-02-20 13:17:20 -0800989
Ray Milkey269ffb92014-04-03 14:43:30 -0700990 apiRemovedLinkEvents.add(linkEvent);
Pavlin Radoslavov3c9cc552014-02-20 09:58:38 -0800991 }
992
Pavlin Radoslavov734ff5a2014-02-26 10:20:43 -0800993 /**
994 * Add a device to the Network Graph.
Ray Milkey269ffb92014-04-03 14:43:30 -0700995 * <p/>
Pavlin Radoslavov734ff5a2014-02-26 10:20:43 -0800996 * TODO: Device-related work is incomplete.
997 * TODO: Eventually, we might need to consider reordering
998 * or addLink() and addDevice() events on the same port.
999 *
1000 * @param deviceEvent the Device Event with the device to add.
1001 */
Pavlin Radoslavov3c9cc552014-02-20 09:58:38 -08001002 private void addDevice(DeviceEvent deviceEvent) {
Ray Milkey269ffb92014-04-03 14:43:30 -07001003 Device device = networkGraph.getDeviceByMac(deviceEvent.getMac());
Pavlin Radoslavov3c9cc552014-02-20 09:58:38 -08001004
Ray Milkey269ffb92014-04-03 14:43:30 -07001005 if (device == null) {
1006 log.debug("Existing device was not found in networkGraph. New device. mac {}", deviceEvent.getMac());
1007 device = new DeviceImpl(networkGraph, deviceEvent.getMac());
1008 }
Pavlin Radoslavov3c9cc552014-02-20 09:58:38 -08001009
Ray Milkey269ffb92014-04-03 14:43:30 -07001010 DeviceImpl deviceImpl = getDeviceImpl(device);
Pavlin Radoslavov3c9cc552014-02-20 09:58:38 -08001011
Ray Milkey269ffb92014-04-03 14:43:30 -07001012 // Update the IP addresses
1013 for (InetAddress ipAddr : deviceEvent.getIpAddresses())
1014 deviceImpl.addIpAddress(ipAddr);
Pavlin Radoslavov3c9cc552014-02-20 09:58:38 -08001015
Ray Milkey269ffb92014-04-03 14:43:30 -07001016 // Process each attachment point
1017 boolean attachmentFound = false;
1018 for (SwitchPort swp : deviceEvent.getAttachmentPoints()) {
1019 // Attached Ports must exist
1020 Port port = networkGraph.getPort(swp.dpid, swp.number);
1021 if (port == null) {
1022 // Reordered event: delay the event in local cache
1023 ByteBuffer id = deviceEvent.getIDasByteBuffer();
1024 reorderedAddedDeviceEvents.put(id, deviceEvent);
1025 continue;
1026 }
1027 // Attached Ports must not have Link
1028 if (port.getOutgoingLink() != null ||
1029 port.getIncomingLink() != null) {
1030 log.warn("Link (Out:{},In:{}) exist on the attachment point, skipping mutation.",
1031 port.getOutgoingLink(),
1032 port.getIncomingLink());
1033 continue;
1034 }
1035
1036 // Add Device <-> Port attachment
1037 PortImpl portImpl = getPortImpl(port);
1038 portImpl.addDevice(device);
1039 deviceImpl.addAttachmentPoint(port);
1040 attachmentFound = true;
1041 }
1042
1043 // Update the device in the Network Graph
1044 if (attachmentFound) {
1045 log.debug("Storing the info into networkGraph. mac {}", deviceEvent.getMac());
1046 networkGraph.putDevice(device);
1047 apiAddedDeviceEvents.add(deviceEvent);
1048 }
Pavlin Radoslavov3c9cc552014-02-20 09:58:38 -08001049 }
1050
Pavlin Radoslavov734ff5a2014-02-26 10:20:43 -08001051 /**
1052 * Remove a device from the Network Graph.
Ray Milkey269ffb92014-04-03 14:43:30 -07001053 * <p/>
Pavlin Radoslavov734ff5a2014-02-26 10:20:43 -08001054 * TODO: Device-related work is incomplete.
1055 *
1056 * @param deviceEvent the Device Event with the device to remove.
1057 */
Pavlin Radoslavov3c9cc552014-02-20 09:58:38 -08001058 private void removeDevice(DeviceEvent deviceEvent) {
Ray Milkey269ffb92014-04-03 14:43:30 -07001059 Device device = networkGraph.getDeviceByMac(deviceEvent.getMac());
1060 if (device == null) {
1061 log.warn("Device {} already removed, ignoring", deviceEvent);
1062 return;
1063 }
1064 DeviceImpl deviceImpl = getDeviceImpl(device);
Pavlin Radoslavov3c9cc552014-02-20 09:58:38 -08001065
Ray Milkey269ffb92014-04-03 14:43:30 -07001066 // Process each attachment point
1067 for (SwitchPort swp : deviceEvent.getAttachmentPoints()) {
1068 // Attached Ports must exist
1069 Port port = networkGraph.getPort(swp.dpid, swp.number);
1070 if (port == null) {
1071 log.warn("Port for the attachment point {} did not exist. skipping attachment point mutation", swp);
1072 continue;
1073 }
Pavlin Radoslavov3c9cc552014-02-20 09:58:38 -08001074
Ray Milkey269ffb92014-04-03 14:43:30 -07001075 // Remove Device <-> Port attachment
1076 PortImpl portImpl = getPortImpl(port);
1077 portImpl.removeDevice(device);
1078 deviceImpl.removeAttachmentPoint(port);
1079 }
Pavlin Radoslavov74986ce2014-02-20 13:17:20 -08001080
Ray Milkey269ffb92014-04-03 14:43:30 -07001081 networkGraph.removeDevice(device);
1082 apiRemovedDeviceEvents.add(deviceEvent);
Pavlin Radoslavov3c9cc552014-02-20 09:58:38 -08001083 }
Jonathan Hart22eb9882014-02-11 15:52:59 -08001084
Pavlin Radoslavovc1cfde52014-02-19 11:35:29 -08001085 /**
Pavlin Radoslavov734ff5a2014-02-26 10:20:43 -08001086 * Get the SwitchImpl-casted switch implementation.
Pavlin Radoslavovc1cfde52014-02-19 11:35:29 -08001087 *
Pavlin Radoslavov734ff5a2014-02-26 10:20:43 -08001088 * @param sw the Switch to cast.
1089 * @return the SwitchImpl-casted switch implementation.
Pavlin Radoslavovc1cfde52014-02-19 11:35:29 -08001090 */
Pavlin Radoslavovc1cfde52014-02-19 11:35:29 -08001091 private SwitchImpl getSwitchImpl(Switch sw) {
Ray Milkey269ffb92014-04-03 14:43:30 -07001092 if (sw instanceof SwitchImpl) {
1093 return (SwitchImpl) sw;
1094 }
1095 throw new ClassCastException("SwitchImpl expected, but found: " + sw);
Pavlin Radoslavovc1cfde52014-02-19 11:35:29 -08001096 }
1097
Pavlin Radoslavov734ff5a2014-02-26 10:20:43 -08001098 /**
1099 * Get the PortImpl-casted port implementation.
1100 *
1101 * @param port the Port to cast.
1102 * @return the PortImpl-casted port implementation.
1103 */
1104 private PortImpl getPortImpl(Port port) {
Ray Milkey269ffb92014-04-03 14:43:30 -07001105 if (port instanceof PortImpl) {
1106 return (PortImpl) port;
1107 }
1108 throw new ClassCastException("PortImpl expected, but found: " + port);
Pavlin Radoslavovc1cfde52014-02-19 11:35:29 -08001109 }
1110
Pavlin Radoslavov734ff5a2014-02-26 10:20:43 -08001111 /**
1112 * Get the LinkImpl-casted link implementation.
1113 *
1114 * @param link the Link to cast.
1115 * @return the LinkImpl-casted link implementation.
1116 */
1117 private LinkImpl getLinkImpl(Link link) {
Ray Milkey269ffb92014-04-03 14:43:30 -07001118 if (link instanceof LinkImpl) {
1119 return (LinkImpl) link;
1120 }
1121 throw new ClassCastException("LinkImpl expected, but found: " + link);
Pavlin Radoslavovc1cfde52014-02-19 11:35:29 -08001122 }
1123
Pavlin Radoslavov734ff5a2014-02-26 10:20:43 -08001124 /**
1125 * Get the DeviceImpl-casted device implementation.
1126 *
1127 * @param device the Device to cast.
1128 * @return the DeviceImpl-casted device implementation.
1129 */
1130 private DeviceImpl getDeviceImpl(Device device) {
Ray Milkey269ffb92014-04-03 14:43:30 -07001131 if (device instanceof DeviceImpl) {
1132 return (DeviceImpl) device;
1133 }
1134 throw new ClassCastException("DeviceImpl expected, but found: " + device);
Pavlin Radoslavovc1cfde52014-02-19 11:35:29 -08001135 }
1136
Pavlin Radoslavov734ff5a2014-02-26 10:20:43 -08001137 /**
1138 * Read the whole topology from the database.
1139 *
1140 * @return a collection of EventEntry-encapsulated Topology Events for
1141 * the whole topology.
1142 */
Pavlin Radoslavov018d5332014-02-19 23:08:35 -08001143 private Collection<EventEntry<TopologyEvent>> readWholeTopologyFromDB() {
Ray Milkey269ffb92014-04-03 14:43:30 -07001144 Collection<EventEntry<TopologyEvent>> collection =
1145 new LinkedList<EventEntry<TopologyEvent>>();
Pavlin Radoslavov018d5332014-02-19 23:08:35 -08001146
Ray Milkey269ffb92014-04-03 14:43:30 -07001147 // XXX May need to clear whole topology first, depending on
1148 // how we initially subscribe to replication events
Pavlin Radoslavovc1cfde52014-02-19 11:35:29 -08001149
Ray Milkey269ffb92014-04-03 14:43:30 -07001150 // Add all active switches
1151 for (KVSwitch sw : KVSwitch.getAllSwitches()) {
1152 if (sw.getStatus() != KVSwitch.STATUS.ACTIVE) {
1153 continue;
1154 }
Pavlin Radoslavov018d5332014-02-19 23:08:35 -08001155
Ray Milkey269ffb92014-04-03 14:43:30 -07001156 SwitchEvent switchEvent = new SwitchEvent(sw.getDpid());
1157 TopologyEvent topologyEvent = new TopologyEvent(switchEvent);
1158 EventEntry<TopologyEvent> eventEntry =
1159 new EventEntry<TopologyEvent>(EventEntry.Type.ENTRY_ADD,
1160 topologyEvent);
1161 collection.add(eventEntry);
1162 }
Yuta HIGUCHIa536e762014-02-17 21:47:28 -08001163
Ray Milkey269ffb92014-04-03 14:43:30 -07001164 // Add all active ports
1165 for (KVPort p : KVPort.getAllPorts()) {
1166 if (p.getStatus() != KVPort.STATUS.ACTIVE) {
1167 continue;
1168 }
Pavlin Radoslavov018d5332014-02-19 23:08:35 -08001169
Ray Milkey269ffb92014-04-03 14:43:30 -07001170 PortEvent portEvent = new PortEvent(p.getDpid(), p.getNumber());
1171 TopologyEvent topologyEvent = new TopologyEvent(portEvent);
1172 EventEntry<TopologyEvent> eventEntry =
1173 new EventEntry<TopologyEvent>(EventEntry.Type.ENTRY_ADD,
1174 topologyEvent);
1175 collection.add(eventEntry);
1176 }
Yuta HIGUCHIa536e762014-02-17 21:47:28 -08001177
Ray Milkey269ffb92014-04-03 14:43:30 -07001178 // TODO Is Device going to be in DB? If so, read from DB.
1179 // for (KVDevice d : KVDevice.getAllDevices()) {
1180 // DeviceEvent devEvent = new DeviceEvent( MACAddress.valueOf(d.getMac()) );
1181 // for (byte[] portId : d.getAllPortIds() ) {
1182 // devEvent.addAttachmentPoint( new SwitchPort( KVPort.getDpidFromKey(portId), KVPort.getNumberFromKey(portId) ));
1183 // }
1184 // }
Pavlin Radoslavovc1cfde52014-02-19 11:35:29 -08001185
Ray Milkey269ffb92014-04-03 14:43:30 -07001186 for (KVLink l : KVLink.getAllLinks()) {
1187 LinkEvent linkEvent = new LinkEvent(l.getSrc().dpid,
1188 l.getSrc().number,
1189 l.getDst().dpid,
1190 l.getDst().number);
1191 TopologyEvent topologyEvent = new TopologyEvent(linkEvent);
1192 EventEntry<TopologyEvent> eventEntry =
1193 new EventEntry<TopologyEvent>(EventEntry.Type.ENTRY_ADD,
1194 topologyEvent);
1195 collection.add(eventEntry);
1196 }
Pavlin Radoslavov018d5332014-02-19 23:08:35 -08001197
Ray Milkey269ffb92014-04-03 14:43:30 -07001198 return collection;
Pavlin Radoslavovc1cfde52014-02-19 11:35:29 -08001199 }
Jonathan Hart062a2e82014-02-03 09:41:57 -08001200}