blob: 4788641ce4599abdc5da365b337913532e177ba7 [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
776 }
777 apiAddedSwitchEvents.add(switchEvent);
Pavlin Radoslavov3c9cc552014-02-20 09:58:38 -0800778 }
779
Pavlin Radoslavov734ff5a2014-02-26 10:20:43 -0800780 /**
781 * Remove a switch from the Network Graph.
782 *
783 * @param switchEvent the Switch Event with the switch to remove.
784 */
Pavlin Radoslavov74986ce2014-02-20 13:17:20 -0800785 private void removeSwitch(SwitchEvent switchEvent) {
Ray Milkey269ffb92014-04-03 14:43:30 -0700786 Switch sw = networkGraph.getSwitch(switchEvent.getDpid());
787 if (sw == null) {
788 log.warn("Switch {} already removed, ignoring", switchEvent);
789 return;
790 }
Pavlin Radoslavov3c9cc552014-02-20 09:58:38 -0800791
Ray Milkey269ffb92014-04-03 14:43:30 -0700792 //
793 // Remove all Ports on the Switch
794 //
795 ArrayList<PortEvent> portsToRemove = new ArrayList<>();
796 for (Port port : sw.getPorts()) {
797 log.warn("Port {} on Switch {} should be removed prior to removing Switch. Removing Port now.",
798 port, switchEvent);
799 PortEvent portEvent = new PortEvent(port.getDpid(),
800 port.getNumber());
801 portsToRemove.add(portEvent);
802 }
803 for (PortEvent portEvent : portsToRemove)
804 removePort(portEvent);
Pavlin Radoslavov3c9cc552014-02-20 09:58:38 -0800805
Ray Milkey269ffb92014-04-03 14:43:30 -0700806 networkGraph.removeSwitch(switchEvent.getDpid());
807 apiRemovedSwitchEvents.add(switchEvent);
Pavlin Radoslavov3c9cc552014-02-20 09:58:38 -0800808 }
809
Pavlin Radoslavov734ff5a2014-02-26 10:20:43 -0800810 /**
811 * Add a port to the Network Graph.
812 *
813 * @param portEvent the Port Event with the port to add.
814 */
Pavlin Radoslavov3c9cc552014-02-20 09:58:38 -0800815 private void addPort(PortEvent portEvent) {
Ray Milkey269ffb92014-04-03 14:43:30 -0700816 Switch sw = networkGraph.getSwitch(portEvent.getDpid());
817 if (sw == null) {
818 // Reordered event: delay the event in local cache
819 ByteBuffer id = portEvent.getIDasByteBuffer();
820 reorderedAddedPortEvents.put(id, portEvent);
821 return;
822 }
823 SwitchImpl switchImpl = getSwitchImpl(sw);
Pavlin Radoslavov3c9cc552014-02-20 09:58:38 -0800824
Ray Milkey269ffb92014-04-03 14:43:30 -0700825 Port port = sw.getPort(portEvent.getNumber());
826 if (port == null) {
827 port = new PortImpl(networkGraph, sw, portEvent.getNumber());
828 switchImpl.addPort(port);
829 } else {
830 // TODO: Update the port attributes
831 }
832 apiAddedPortEvents.add(portEvent);
Pavlin Radoslavov3c9cc552014-02-20 09:58:38 -0800833 }
834
Pavlin Radoslavov734ff5a2014-02-26 10:20:43 -0800835 /**
836 * Remove a port from the Network Graph.
837 *
838 * @param portEvent the Port Event with the port to remove.
839 */
Pavlin Radoslavov3c9cc552014-02-20 09:58:38 -0800840 private void removePort(PortEvent portEvent) {
Ray Milkey269ffb92014-04-03 14:43:30 -0700841 Switch sw = networkGraph.getSwitch(portEvent.getDpid());
842 if (sw == null) {
843 log.warn("Parent Switch for Port {} already removed, ignoring",
844 portEvent);
845 return;
846 }
Pavlin Radoslavov3c9cc552014-02-20 09:58:38 -0800847
Ray Milkey269ffb92014-04-03 14:43:30 -0700848 Port port = sw.getPort(portEvent.getNumber());
849 if (port == null) {
850 log.warn("Port {} already removed, ignoring", portEvent);
851 return;
852 }
Pavlin Radoslavov3c9cc552014-02-20 09:58:38 -0800853
Ray Milkey269ffb92014-04-03 14:43:30 -0700854 //
855 // Remove all Devices attached to the Port
856 //
857 ArrayList<DeviceEvent> devicesToRemove = new ArrayList<>();
858 for (Device device : port.getDevices()) {
859 log.debug("Removing Device {} on Port {}", device, portEvent);
860 DeviceEvent deviceEvent = new DeviceEvent(device.getMacAddress());
861 SwitchPort switchPort = new SwitchPort(port.getSwitch().getDpid(),
862 port.getNumber());
863 deviceEvent.addAttachmentPoint(switchPort);
864 devicesToRemove.add(deviceEvent);
865 }
866 for (DeviceEvent deviceEvent : devicesToRemove)
867 removeDevice(deviceEvent);
Pavlin Radoslavov3c9cc552014-02-20 09:58:38 -0800868
Ray Milkey269ffb92014-04-03 14:43:30 -0700869 //
870 // Remove all Links connected to the Port
871 //
872 Set<Link> links = new HashSet<>();
873 links.add(port.getOutgoingLink());
874 links.add(port.getIncomingLink());
875 ArrayList<LinkEvent> linksToRemove = new ArrayList<>();
876 for (Link link : links) {
877 if (link == null)
878 continue;
879 log.debug("Removing Link {} on Port {}", link, portEvent);
880 LinkEvent linkEvent = new LinkEvent(link.getSrcSwitch().getDpid(),
881 link.getSrcPort().getNumber(),
882 link.getDstSwitch().getDpid(),
883 link.getDstPort().getNumber());
884 linksToRemove.add(linkEvent);
885 }
886 for (LinkEvent linkEvent : linksToRemove)
887 removeLink(linkEvent);
Pavlin Radoslavov3c9cc552014-02-20 09:58:38 -0800888
Ray Milkey269ffb92014-04-03 14:43:30 -0700889 // Remove the Port from the Switch
890 SwitchImpl switchImpl = getSwitchImpl(sw);
891 switchImpl.removePort(port);
Pavlin Radoslavov74986ce2014-02-20 13:17:20 -0800892
Ray Milkey269ffb92014-04-03 14:43:30 -0700893 apiRemovedPortEvents.add(portEvent);
Pavlin Radoslavov3c9cc552014-02-20 09:58:38 -0800894 }
895
Pavlin Radoslavov734ff5a2014-02-26 10:20:43 -0800896 /**
897 * Add a link to the Network Graph.
898 *
899 * @param linkEvent the Link Event with the link to add.
900 */
Pavlin Radoslavov3c9cc552014-02-20 09:58:38 -0800901 private void addLink(LinkEvent linkEvent) {
Ray Milkey269ffb92014-04-03 14:43:30 -0700902 Port srcPort = networkGraph.getPort(linkEvent.getSrc().dpid,
903 linkEvent.getSrc().number);
904 Port dstPort = networkGraph.getPort(linkEvent.getDst().dpid,
905 linkEvent.getDst().number);
906 if ((srcPort == null) || (dstPort == null)) {
907 // Reordered event: delay the event in local cache
908 ByteBuffer id = linkEvent.getIDasByteBuffer();
909 reorderedAddedLinkEvents.put(id, linkEvent);
910 return;
911 }
Pavlin Radoslavov3c9cc552014-02-20 09:58:38 -0800912
Ray Milkey269ffb92014-04-03 14:43:30 -0700913 // Get the Link instance from the Destination Port Incoming Link
914 Link link = dstPort.getIncomingLink();
915 assert (link == srcPort.getOutgoingLink());
916 if (link == null) {
917 link = new LinkImpl(networkGraph, srcPort, dstPort);
918 PortImpl srcPortImpl = getPortImpl(srcPort);
919 PortImpl dstPortImpl = getPortImpl(dstPort);
920 srcPortImpl.setOutgoingLink(link);
921 dstPortImpl.setIncomingLink(link);
Pavlin Radoslavov3c9cc552014-02-20 09:58:38 -0800922
Ray Milkey269ffb92014-04-03 14:43:30 -0700923 // Remove all Devices attached to the Ports
924 ArrayList<DeviceEvent> devicesToRemove = new ArrayList<>();
925 ArrayList<Port> ports = new ArrayList<>();
926 ports.add(srcPort);
927 ports.add(dstPort);
928 for (Port port : ports) {
929 for (Device device : port.getDevices()) {
930 log.error("Device {} on Port {} should have been removed prior to adding Link {}",
931 device, port, linkEvent);
932 DeviceEvent deviceEvent =
933 new DeviceEvent(device.getMacAddress());
934 SwitchPort switchPort =
935 new SwitchPort(port.getSwitch().getDpid(),
936 port.getNumber());
937 deviceEvent.addAttachmentPoint(switchPort);
938 devicesToRemove.add(deviceEvent);
939 }
940 }
941 for (DeviceEvent deviceEvent : devicesToRemove)
942 removeDevice(deviceEvent);
943 } else {
944 // TODO: Update the link attributes
945 }
Pavlin Radoslavov74986ce2014-02-20 13:17:20 -0800946
Ray Milkey269ffb92014-04-03 14:43:30 -0700947 apiAddedLinkEvents.add(linkEvent);
Pavlin Radoslavov3c9cc552014-02-20 09:58:38 -0800948 }
949
Pavlin Radoslavov734ff5a2014-02-26 10:20:43 -0800950 /**
951 * Remove a link from the Network Graph.
952 *
953 * @param linkEvent the Link Event with the link to remove.
954 */
Pavlin Radoslavov3c9cc552014-02-20 09:58:38 -0800955 private void removeLink(LinkEvent linkEvent) {
Ray Milkey269ffb92014-04-03 14:43:30 -0700956 Port srcPort = networkGraph.getPort(linkEvent.getSrc().dpid,
957 linkEvent.getSrc().number);
958 if (srcPort == null) {
959 log.warn("Src Port for Link {} already removed, ignoring",
960 linkEvent);
961 return;
962 }
Pavlin Radoslavov3c9cc552014-02-20 09:58:38 -0800963
Ray Milkey269ffb92014-04-03 14:43:30 -0700964 Port dstPort = networkGraph.getPort(linkEvent.getDst().dpid,
965 linkEvent.getDst().number);
966 if (dstPort == null) {
967 log.warn("Dst Port for Link {} already removed, ignoring",
968 linkEvent);
969 return;
970 }
Pavlin Radoslavov3c9cc552014-02-20 09:58:38 -0800971
Ray Milkey269ffb92014-04-03 14:43:30 -0700972 //
973 // Remove the Link instance from the Destination Port Incoming Link
974 // and the Source Port Outgoing Link.
975 //
976 Link link = dstPort.getIncomingLink();
977 if (link == null) {
978 log.warn("Link {} already removed on destination Port", linkEvent);
979 }
980 link = srcPort.getOutgoingLink();
981 if (link == null) {
982 log.warn("Link {} already removed on src Port", linkEvent);
983 }
984 getPortImpl(dstPort).setIncomingLink(null);
985 getPortImpl(srcPort).setOutgoingLink(null);
Pavlin Radoslavov74986ce2014-02-20 13:17:20 -0800986
Ray Milkey269ffb92014-04-03 14:43:30 -0700987 apiRemovedLinkEvents.add(linkEvent);
Pavlin Radoslavov3c9cc552014-02-20 09:58:38 -0800988 }
989
Pavlin Radoslavov734ff5a2014-02-26 10:20:43 -0800990 /**
991 * Add a device to the Network Graph.
Ray Milkey269ffb92014-04-03 14:43:30 -0700992 * <p/>
Pavlin Radoslavov734ff5a2014-02-26 10:20:43 -0800993 * TODO: Device-related work is incomplete.
994 * TODO: Eventually, we might need to consider reordering
995 * or addLink() and addDevice() events on the same port.
996 *
997 * @param deviceEvent the Device Event with the device to add.
998 */
Pavlin Radoslavov3c9cc552014-02-20 09:58:38 -0800999 private void addDevice(DeviceEvent deviceEvent) {
Ray Milkey269ffb92014-04-03 14:43:30 -07001000 Device device = networkGraph.getDeviceByMac(deviceEvent.getMac());
Pavlin Radoslavov3c9cc552014-02-20 09:58:38 -08001001
Ray Milkey269ffb92014-04-03 14:43:30 -07001002 if (device == null) {
1003 log.debug("Existing device was not found in networkGraph. New device. mac {}", deviceEvent.getMac());
1004 device = new DeviceImpl(networkGraph, deviceEvent.getMac());
1005 }
Pavlin Radoslavov3c9cc552014-02-20 09:58:38 -08001006
Ray Milkey269ffb92014-04-03 14:43:30 -07001007 DeviceImpl deviceImpl = getDeviceImpl(device);
Pavlin Radoslavov3c9cc552014-02-20 09:58:38 -08001008
Ray Milkey269ffb92014-04-03 14:43:30 -07001009 // Update the IP addresses
1010 for (InetAddress ipAddr : deviceEvent.getIpAddresses())
1011 deviceImpl.addIpAddress(ipAddr);
Pavlin Radoslavov3c9cc552014-02-20 09:58:38 -08001012
Ray Milkey269ffb92014-04-03 14:43:30 -07001013 // Process each attachment point
1014 boolean attachmentFound = false;
1015 for (SwitchPort swp : deviceEvent.getAttachmentPoints()) {
1016 // Attached Ports must exist
1017 Port port = networkGraph.getPort(swp.dpid, swp.number);
1018 if (port == null) {
1019 // Reordered event: delay the event in local cache
1020 ByteBuffer id = deviceEvent.getIDasByteBuffer();
1021 reorderedAddedDeviceEvents.put(id, deviceEvent);
1022 continue;
1023 }
1024 // Attached Ports must not have Link
1025 if (port.getOutgoingLink() != null ||
1026 port.getIncomingLink() != null) {
1027 log.warn("Link (Out:{},In:{}) exist on the attachment point, skipping mutation.",
1028 port.getOutgoingLink(),
1029 port.getIncomingLink());
1030 continue;
1031 }
1032
1033 // Add Device <-> Port attachment
1034 PortImpl portImpl = getPortImpl(port);
1035 portImpl.addDevice(device);
1036 deviceImpl.addAttachmentPoint(port);
1037 attachmentFound = true;
1038 }
1039
1040 // Update the device in the Network Graph
1041 if (attachmentFound) {
1042 log.debug("Storing the info into networkGraph. mac {}", deviceEvent.getMac());
1043 networkGraph.putDevice(device);
1044 apiAddedDeviceEvents.add(deviceEvent);
1045 }
Pavlin Radoslavov3c9cc552014-02-20 09:58:38 -08001046 }
1047
Pavlin Radoslavov734ff5a2014-02-26 10:20:43 -08001048 /**
1049 * Remove a device from the Network Graph.
Ray Milkey269ffb92014-04-03 14:43:30 -07001050 * <p/>
Pavlin Radoslavov734ff5a2014-02-26 10:20:43 -08001051 * TODO: Device-related work is incomplete.
1052 *
1053 * @param deviceEvent the Device Event with the device to remove.
1054 */
Pavlin Radoslavov3c9cc552014-02-20 09:58:38 -08001055 private void removeDevice(DeviceEvent deviceEvent) {
Ray Milkey269ffb92014-04-03 14:43:30 -07001056 Device device = networkGraph.getDeviceByMac(deviceEvent.getMac());
1057 if (device == null) {
1058 log.warn("Device {} already removed, ignoring", deviceEvent);
1059 return;
1060 }
1061 DeviceImpl deviceImpl = getDeviceImpl(device);
Pavlin Radoslavov3c9cc552014-02-20 09:58:38 -08001062
Ray Milkey269ffb92014-04-03 14:43:30 -07001063 // Process each attachment point
1064 for (SwitchPort swp : deviceEvent.getAttachmentPoints()) {
1065 // Attached Ports must exist
1066 Port port = networkGraph.getPort(swp.dpid, swp.number);
1067 if (port == null) {
1068 log.warn("Port for the attachment point {} did not exist. skipping attachment point mutation", swp);
1069 continue;
1070 }
Pavlin Radoslavov3c9cc552014-02-20 09:58:38 -08001071
Ray Milkey269ffb92014-04-03 14:43:30 -07001072 // Remove Device <-> Port attachment
1073 PortImpl portImpl = getPortImpl(port);
1074 portImpl.removeDevice(device);
1075 deviceImpl.removeAttachmentPoint(port);
1076 }
Pavlin Radoslavov74986ce2014-02-20 13:17:20 -08001077
Ray Milkey269ffb92014-04-03 14:43:30 -07001078 networkGraph.removeDevice(device);
1079 apiRemovedDeviceEvents.add(deviceEvent);
Pavlin Radoslavov3c9cc552014-02-20 09:58:38 -08001080 }
Jonathan Hart22eb9882014-02-11 15:52:59 -08001081
Pavlin Radoslavovc1cfde52014-02-19 11:35:29 -08001082 /**
Pavlin Radoslavov734ff5a2014-02-26 10:20:43 -08001083 * Get the SwitchImpl-casted switch implementation.
Pavlin Radoslavovc1cfde52014-02-19 11:35:29 -08001084 *
Pavlin Radoslavov734ff5a2014-02-26 10:20:43 -08001085 * @param sw the Switch to cast.
1086 * @return the SwitchImpl-casted switch implementation.
Pavlin Radoslavovc1cfde52014-02-19 11:35:29 -08001087 */
Pavlin Radoslavovc1cfde52014-02-19 11:35:29 -08001088 private SwitchImpl getSwitchImpl(Switch sw) {
Ray Milkey269ffb92014-04-03 14:43:30 -07001089 if (sw instanceof SwitchImpl) {
1090 return (SwitchImpl) sw;
1091 }
1092 throw new ClassCastException("SwitchImpl expected, but found: " + sw);
Pavlin Radoslavovc1cfde52014-02-19 11:35:29 -08001093 }
1094
Pavlin Radoslavov734ff5a2014-02-26 10:20:43 -08001095 /**
1096 * Get the PortImpl-casted port implementation.
1097 *
1098 * @param port the Port to cast.
1099 * @return the PortImpl-casted port implementation.
1100 */
1101 private PortImpl getPortImpl(Port port) {
Ray Milkey269ffb92014-04-03 14:43:30 -07001102 if (port instanceof PortImpl) {
1103 return (PortImpl) port;
1104 }
1105 throw new ClassCastException("PortImpl expected, but found: " + port);
Pavlin Radoslavovc1cfde52014-02-19 11:35:29 -08001106 }
1107
Pavlin Radoslavov734ff5a2014-02-26 10:20:43 -08001108 /**
1109 * Get the LinkImpl-casted link implementation.
1110 *
1111 * @param link the Link to cast.
1112 * @return the LinkImpl-casted link implementation.
1113 */
1114 private LinkImpl getLinkImpl(Link link) {
Ray Milkey269ffb92014-04-03 14:43:30 -07001115 if (link instanceof LinkImpl) {
1116 return (LinkImpl) link;
1117 }
1118 throw new ClassCastException("LinkImpl expected, but found: " + link);
Pavlin Radoslavovc1cfde52014-02-19 11:35:29 -08001119 }
1120
Pavlin Radoslavov734ff5a2014-02-26 10:20:43 -08001121 /**
1122 * Get the DeviceImpl-casted device implementation.
1123 *
1124 * @param device the Device to cast.
1125 * @return the DeviceImpl-casted device implementation.
1126 */
1127 private DeviceImpl getDeviceImpl(Device device) {
Ray Milkey269ffb92014-04-03 14:43:30 -07001128 if (device instanceof DeviceImpl) {
1129 return (DeviceImpl) device;
1130 }
1131 throw new ClassCastException("DeviceImpl expected, but found: " + device);
Pavlin Radoslavovc1cfde52014-02-19 11:35:29 -08001132 }
1133
Pavlin Radoslavov734ff5a2014-02-26 10:20:43 -08001134 /**
1135 * Read the whole topology from the database.
1136 *
1137 * @return a collection of EventEntry-encapsulated Topology Events for
1138 * the whole topology.
1139 */
Pavlin Radoslavov018d5332014-02-19 23:08:35 -08001140 private Collection<EventEntry<TopologyEvent>> readWholeTopologyFromDB() {
Ray Milkey269ffb92014-04-03 14:43:30 -07001141 Collection<EventEntry<TopologyEvent>> collection =
1142 new LinkedList<EventEntry<TopologyEvent>>();
Pavlin Radoslavov018d5332014-02-19 23:08:35 -08001143
Ray Milkey269ffb92014-04-03 14:43:30 -07001144 // XXX May need to clear whole topology first, depending on
1145 // how we initially subscribe to replication events
Pavlin Radoslavovc1cfde52014-02-19 11:35:29 -08001146
Ray Milkey269ffb92014-04-03 14:43:30 -07001147 // Add all active switches
1148 for (KVSwitch sw : KVSwitch.getAllSwitches()) {
1149 if (sw.getStatus() != KVSwitch.STATUS.ACTIVE) {
1150 continue;
1151 }
Pavlin Radoslavov018d5332014-02-19 23:08:35 -08001152
Ray Milkey269ffb92014-04-03 14:43:30 -07001153 SwitchEvent switchEvent = new SwitchEvent(sw.getDpid());
1154 TopologyEvent topologyEvent = new TopologyEvent(switchEvent);
1155 EventEntry<TopologyEvent> eventEntry =
1156 new EventEntry<TopologyEvent>(EventEntry.Type.ENTRY_ADD,
1157 topologyEvent);
1158 collection.add(eventEntry);
1159 }
Yuta HIGUCHIa536e762014-02-17 21:47:28 -08001160
Ray Milkey269ffb92014-04-03 14:43:30 -07001161 // Add all active ports
1162 for (KVPort p : KVPort.getAllPorts()) {
1163 if (p.getStatus() != KVPort.STATUS.ACTIVE) {
1164 continue;
1165 }
Pavlin Radoslavov018d5332014-02-19 23:08:35 -08001166
Ray Milkey269ffb92014-04-03 14:43:30 -07001167 PortEvent portEvent = new PortEvent(p.getDpid(), p.getNumber());
1168 TopologyEvent topologyEvent = new TopologyEvent(portEvent);
1169 EventEntry<TopologyEvent> eventEntry =
1170 new EventEntry<TopologyEvent>(EventEntry.Type.ENTRY_ADD,
1171 topologyEvent);
1172 collection.add(eventEntry);
1173 }
Yuta HIGUCHIa536e762014-02-17 21:47:28 -08001174
Ray Milkey269ffb92014-04-03 14:43:30 -07001175 // TODO Is Device going to be in DB? If so, read from DB.
1176 // for (KVDevice d : KVDevice.getAllDevices()) {
1177 // DeviceEvent devEvent = new DeviceEvent( MACAddress.valueOf(d.getMac()) );
1178 // for (byte[] portId : d.getAllPortIds() ) {
1179 // devEvent.addAttachmentPoint( new SwitchPort( KVPort.getDpidFromKey(portId), KVPort.getNumberFromKey(portId) ));
1180 // }
1181 // }
Pavlin Radoslavovc1cfde52014-02-19 11:35:29 -08001182
Ray Milkey269ffb92014-04-03 14:43:30 -07001183 for (KVLink l : KVLink.getAllLinks()) {
1184 LinkEvent linkEvent = new LinkEvent(l.getSrc().dpid,
1185 l.getSrc().number,
1186 l.getDst().dpid,
1187 l.getDst().number);
1188 TopologyEvent topologyEvent = new TopologyEvent(linkEvent);
1189 EventEntry<TopologyEvent> eventEntry =
1190 new EventEntry<TopologyEvent>(EventEntry.Type.ENTRY_ADD,
1191 topologyEvent);
1192 collection.add(eventEntry);
1193 }
Pavlin Radoslavov018d5332014-02-19 23:08:35 -08001194
Ray Milkey269ffb92014-04-03 14:43:30 -07001195 return collection;
Pavlin Radoslavovc1cfde52014-02-19 11:35:29 -08001196 }
Jonathan Hart062a2e82014-02-03 09:41:57 -08001197}