blob: 732265e942dc6a3561fbbc5d2b901cc066ad79f3 [file] [log] [blame]
Jonathan Hart062a2e82014-02-03 09:41:57 -08001package net.onrc.onos.ofcontroller.networkgraph;
2
Yuta HIGUCHI1c700102014-02-12 16:30:52 -08003import java.net.InetAddress;
Pavlin Radoslavov018d5332014-02-19 23:08:35 -08004import java.nio.ByteBuffer;
Yuta HIGUCHI8d762e92014-02-12 14:10:25 -08005import java.util.ArrayList;
Pavlin Radoslavov721a2e02014-02-14 23:40:14 -08006import java.util.Collection;
Pavlin Radoslavov018d5332014-02-19 23:08:35 -08007import java.util.HashMap;
Yuta HIGUCHI8d762e92014-02-12 14:10:25 -08008import java.util.HashSet;
Pavlin Radoslavov721a2e02014-02-14 23:40:14 -08009import java.util.LinkedList;
Yuta HIGUCHI8d762e92014-02-12 14:10:25 -080010import java.util.List;
Pavlin Radoslavov018d5332014-02-19 23:08:35 -080011import java.util.Map;
Yuta HIGUCHI8d762e92014-02-12 14:10:25 -080012import java.util.Set;
Pavlin Radoslavov721a2e02014-02-14 23:40:14 -080013import java.util.concurrent.BlockingQueue;
Yuta HIGUCHIa536e762014-02-17 21:47:28 -080014import java.util.concurrent.CopyOnWriteArrayList;
Pavlin Radoslavov721a2e02014-02-14 23:40:14 -080015import java.util.concurrent.LinkedBlockingQueue;
Yuta HIGUCHI8d762e92014-02-12 14:10:25 -080016
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;
Yuta HIGUCHI8d762e92014-02-12 14:10:25 -080023import net.onrc.onos.ofcontroller.networkgraph.PortEvent.SwitchPort;
Pavlin Radoslavov721a2e02014-02-14 23:40:14 -080024import net.onrc.onos.ofcontroller.util.EventEntry;
Yuta HIGUCHI170229f2014-02-17 15:47:54 -080025import net.onrc.onos.registry.controller.IControllerRegistryService;
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.
32 *
Yuta HIGUCHI4bfdd532014-02-07 13:47:36 -080033 * - Maintain Invariant/Relationships between Topology Objects.
34 *
Yuta HIGUCHI765cd0d2014-02-06 12:46:41 -080035 * TODO To be synchronized based on TopologyEvent Notification.
Yuta HIGUCHI181d34d2014-02-05 15:05:46 -080036 *
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).
Yuta HIGUCHIcb951982014-02-11 13:31:44 -080039 *
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 HIGUCHIcb951982014-02-11 13:31:44 -080042 *
Yuta HIGUCHI181d34d2014-02-05 15:05:46 -080043 */
Pavlin Radoslavov87dcc262014-02-19 21:13:23 -080044public class TopologyManager implements NetworkGraphDiscoveryInterface {
Jonathan Hart062a2e82014-02-03 09:41:57 -080045
Yuta HIGUCHI80829d12014-02-05 20:16:56 -080046 private static final Logger log = LoggerFactory
Pavlin Radoslavovdb7dbb22014-02-18 14:45:10 -080047 .getLogger(TopologyManager.class);
Yuta HIGUCHIcd922f42014-02-11 18:59:11 -080048
Pavlin Radoslavov721a2e02014-02-14 23:40:14 -080049 private IEventChannel<byte[], TopologyEvent> eventChannel;
Jonathan Hart10a7e2b2014-02-21 18:30:08 -080050 public static final String EVENT_CHANNEL_NAME = "onos.topology";
Pavlin Radoslavov721a2e02014-02-14 23:40:14 -080051 private EventHandler eventHandler = new EventHandler();
52
Jonathan Hart22eb9882014-02-11 15:52:59 -080053 private final NetworkGraphDatastore datastore;
Pavlin Radoslavov6d224ee2014-02-18 16:43:15 -080054 private final NetworkGraphImpl networkGraph = new NetworkGraphImpl();
Yuta HIGUCHI170229f2014-02-17 15:47:54 -080055 private final IControllerRegistryService registryService;
Yuta HIGUCHIa536e762014-02-17 21:47:28 -080056 private CopyOnWriteArrayList<INetworkGraphListener> networkGraphListeners;
Yuta HIGUCHI181d34d2014-02-05 15:05:46 -080057
Pavlin Radoslavov706add22014-02-20 12:15:59 -080058 //
59 // Local state for keeping track of reordered events.
60 // NOTE: Switch Events are not affected by the event reordering.
61 //
62 private Map<ByteBuffer, PortEvent> reorderedAddedPortEvents =
Pavlin Radoslavov018d5332014-02-19 23:08:35 -080063 new HashMap<ByteBuffer, PortEvent>();
Pavlin Radoslavov706add22014-02-20 12:15:59 -080064 private Map<ByteBuffer, LinkEvent> reorderedAddedLinkEvents =
Pavlin Radoslavov018d5332014-02-19 23:08:35 -080065 new HashMap<ByteBuffer, LinkEvent>();
Pavlin Radoslavov706add22014-02-20 12:15:59 -080066 private Map<ByteBuffer, DeviceEvent> reorderedAddedDeviceEvents =
Pavlin Radoslavov018d5332014-02-19 23:08:35 -080067 new HashMap<ByteBuffer, DeviceEvent>();
68
Pavlin Radoslavov74986ce2014-02-20 13:17:20 -080069 //
Pavlin Radoslavov26d83402014-02-20 15:24:30 -080070 // Local state for keeping track of locally discovered events so we can
71 // cleanup properly when a Switch or Port is removed.
72 //
73 // We keep all Port, Link and Device events per Switch DPID:
74 // - If a switch goes down, we remove all corresponding Port, Link and
75 // Device events.
76 // - If a port on a switch goes down, we remove all corresponding Link
77 // and Device events.
78 //
79 private Map<Long, Map<ByteBuffer, PortEvent>> discoveredAddedPortEvents =
80 new HashMap<>();
81 private Map<Long, Map<ByteBuffer, LinkEvent>> discoveredAddedLinkEvents =
82 new HashMap<>();
83 private Map<Long, Map<ByteBuffer, DeviceEvent>> discoveredAddedDeviceEvents =
84 new HashMap<>();
85
86 //
Pavlin Radoslavov74986ce2014-02-20 13:17:20 -080087 // Local state for keeping track of the application event notifications
88 //
89 List<SwitchEvent> apiAddedSwitchEvents = new LinkedList<SwitchEvent>();
90 List<SwitchEvent> apiRemovedSwitchEvents = new LinkedList<SwitchEvent>();
91 List<PortEvent> apiAddedPortEvents = new LinkedList<PortEvent>();
92 List<PortEvent> apiRemovedPortEvents = new LinkedList<PortEvent>();
93 List<LinkEvent> apiAddedLinkEvents = new LinkedList<LinkEvent>();
94 List<LinkEvent> apiRemovedLinkEvents = new LinkedList<LinkEvent>();
95 List<DeviceEvent> apiAddedDeviceEvents = new LinkedList<DeviceEvent>();
96 List<DeviceEvent> apiRemovedDeviceEvents = new LinkedList<DeviceEvent>();
97
Pavlin Radoslavovc1cfde52014-02-19 11:35:29 -080098 /**
99 * Constructor.
100 *
101 * @param registryService the Registry Service to use.
102 * @param networkGraphListeners the collection of Network Graph Listeners
103 * to use.
104 */
105 public TopologyManager(IControllerRegistryService registryService,
106 CopyOnWriteArrayList<INetworkGraphListener> networkGraphListeners) {
Jonathan Hartdaea86f2014-02-19 15:28:42 -0800107 datastore = new NetworkGraphDatastore();
Yuta HIGUCHI170229f2014-02-17 15:47:54 -0800108 this.registryService = registryService;
Yuta HIGUCHIa536e762014-02-17 21:47:28 -0800109 this.networkGraphListeners = networkGraphListeners;
Yuta HIGUCHI80829d12014-02-05 20:16:56 -0800110 }
Yuta HIGUCHI181d34d2014-02-05 15:05:46 -0800111
Pavlin Radoslavovc1cfde52014-02-19 11:35:29 -0800112 /**
113 * Get the Network Graph.
114 *
115 * @return the Network Graph.
116 */
Pavlin Radoslavov6d224ee2014-02-18 16:43:15 -0800117 NetworkGraph getNetworkGraph() {
118 return networkGraph;
119 }
120
Yuta HIGUCHI4bfdd532014-02-07 13:47:36 -0800121 /**
Pavlin Radoslavov721a2e02014-02-14 23:40:14 -0800122 * Event handler class.
123 */
124 private class EventHandler extends Thread implements
125 IEventChannelListener<byte[], TopologyEvent> {
126 private BlockingQueue<EventEntry<TopologyEvent>> topologyEvents =
127 new LinkedBlockingQueue<EventEntry<TopologyEvent>>();
128
129 /**
130 * Startup processing.
131 */
132 private void startup() {
133 //
Pavlin Radoslavov018d5332014-02-19 23:08:35 -0800134 // TODO: Read all state from the database:
135 //
136 // Collection<EventEntry<TopologyEvent>> collection =
137 // readWholeTopologyFromDB();
138 //
Pavlin Radoslavov721a2e02014-02-14 23:40:14 -0800139 // For now, as a shortcut we read it from the datagrid
140 //
141 Collection<TopologyEvent> topologyEvents =
142 eventChannel.getAllEntries();
143 Collection<EventEntry<TopologyEvent>> collection =
144 new LinkedList<EventEntry<TopologyEvent>>();
145
146 for (TopologyEvent topologyEvent : topologyEvents) {
147 EventEntry<TopologyEvent> eventEntry =
148 new EventEntry<TopologyEvent>(EventEntry.Type.ENTRY_ADD,
149 topologyEvent);
150 collection.add(eventEntry);
151 }
152 processEvents(collection);
153 }
154
155 /**
156 * Run the thread.
157 */
Yuta HIGUCHI240bf072014-02-17 10:55:21 -0800158 @Override
Pavlin Radoslavov721a2e02014-02-14 23:40:14 -0800159 public void run() {
160 Collection<EventEntry<TopologyEvent>> collection =
161 new LinkedList<EventEntry<TopologyEvent>>();
162
Pavlin Radoslavovdb7dbb22014-02-18 14:45:10 -0800163 this.setName("TopologyManager.EventHandler " + this.getId());
Pavlin Radoslavov721a2e02014-02-14 23:40:14 -0800164 startup();
165
166 //
167 // The main loop
168 //
169 try {
170 while (true) {
171 EventEntry<TopologyEvent> eventEntry = topologyEvents.take();
172 collection.add(eventEntry);
173 topologyEvents.drainTo(collection);
174
175 processEvents(collection);
176 collection.clear();
177 }
178 } catch (Exception exception) {
179 log.debug("Exception processing Topology Events: ", exception);
180 }
181 }
182
183 /**
184 * Process all topology events.
185 *
186 * @param events the events to process.
187 */
188 private void processEvents(Collection<EventEntry<TopologyEvent>> events) {
Pavlin Radoslavov706add22014-02-20 12:15:59 -0800189 // Local state for computing the final set of events
Pavlin Radoslavov26d83402014-02-20 15:24:30 -0800190 Map<ByteBuffer, SwitchEvent> addedSwitchEvents = new HashMap<>();
191 Map<ByteBuffer, SwitchEvent> removedSwitchEvents = new HashMap<>();
192 Map<ByteBuffer, PortEvent> addedPortEvents = new HashMap<>();
193 Map<ByteBuffer, PortEvent> removedPortEvents = new HashMap<>();
194 Map<ByteBuffer, LinkEvent> addedLinkEvents = new HashMap<>();
195 Map<ByteBuffer, LinkEvent> removedLinkEvents = new HashMap<>();
196 Map<ByteBuffer, DeviceEvent> addedDeviceEvents = new HashMap<>();
197 Map<ByteBuffer, DeviceEvent> removedDeviceEvents = new HashMap<>();
Pavlin Radoslavov3c9cc552014-02-20 09:58:38 -0800198
199 //
200 // Classify and suppress matching events
201 //
Pavlin Radoslavov721a2e02014-02-14 23:40:14 -0800202 for (EventEntry<TopologyEvent> event : events) {
203 TopologyEvent topologyEvent = event.eventData();
Pavlin Radoslavov018d5332014-02-19 23:08:35 -0800204 SwitchEvent switchEvent = topologyEvent.switchEvent;
205 PortEvent portEvent = topologyEvent.portEvent;
206 LinkEvent linkEvent = topologyEvent.linkEvent;
207 DeviceEvent deviceEvent = topologyEvent.deviceEvent;
208
209 //
Pavlin Radoslavov3c9cc552014-02-20 09:58:38 -0800210 // Extract the events
Pavlin Radoslavov018d5332014-02-19 23:08:35 -0800211 //
Pavlin Radoslavov721a2e02014-02-14 23:40:14 -0800212 switch (event.eventType()) {
213 case ENTRY_ADD:
214 log.debug("Topology event ENTRY_ADD: {}", topologyEvent);
Pavlin Radoslavov018d5332014-02-19 23:08:35 -0800215 if (switchEvent != null) {
Yuta HIGUCHIa341b112014-02-23 15:42:00 -0800216 ByteBuffer id = switchEvent.getIDasByteBuffer();
Pavlin Radoslavov018d5332014-02-19 23:08:35 -0800217 addedSwitchEvents.put(id, switchEvent);
218 removedSwitchEvents.remove(id);
Pavlin Radoslavov706add22014-02-20 12:15:59 -0800219 // Switch Events are not affected by event reordering
Pavlin Radoslavov018d5332014-02-19 23:08:35 -0800220 }
221 if (portEvent != null) {
Yuta HIGUCHIa341b112014-02-23 15:42:00 -0800222 ByteBuffer id = portEvent.getIDasByteBuffer();
Pavlin Radoslavov018d5332014-02-19 23:08:35 -0800223 addedPortEvents.put(id, portEvent);
224 removedPortEvents.remove(id);
Pavlin Radoslavov706add22014-02-20 12:15:59 -0800225 reorderedAddedPortEvents.remove(id);
Pavlin Radoslavov018d5332014-02-19 23:08:35 -0800226 }
227 if (linkEvent != null) {
Yuta HIGUCHIa341b112014-02-23 15:42:00 -0800228 ByteBuffer id = linkEvent.getIDasByteBuffer();
Pavlin Radoslavov018d5332014-02-19 23:08:35 -0800229 addedLinkEvents.put(id, linkEvent);
230 removedLinkEvents.remove(id);
Pavlin Radoslavov706add22014-02-20 12:15:59 -0800231 reorderedAddedLinkEvents.remove(id);
Pavlin Radoslavov018d5332014-02-19 23:08:35 -0800232 }
233 if (deviceEvent != null) {
Yuta HIGUCHIa341b112014-02-23 15:42:00 -0800234 ByteBuffer id = deviceEvent.getIDasByteBuffer();
Pavlin Radoslavov018d5332014-02-19 23:08:35 -0800235 addedDeviceEvents.put(id, deviceEvent);
236 removedDeviceEvents.remove(id);
Pavlin Radoslavov706add22014-02-20 12:15:59 -0800237 reorderedAddedDeviceEvents.remove(id);
Pavlin Radoslavov018d5332014-02-19 23:08:35 -0800238 }
Pavlin Radoslavov721a2e02014-02-14 23:40:14 -0800239 break;
240 case ENTRY_REMOVE:
241 log.debug("Topology event ENTRY_REMOVE: {}", topologyEvent);
Pavlin Radoslavov018d5332014-02-19 23:08:35 -0800242 if (switchEvent != null) {
Yuta HIGUCHIa341b112014-02-23 15:42:00 -0800243 ByteBuffer id = switchEvent.getIDasByteBuffer();
Pavlin Radoslavov018d5332014-02-19 23:08:35 -0800244 addedSwitchEvents.remove(id);
245 removedSwitchEvents.put(id, switchEvent);
Pavlin Radoslavov706add22014-02-20 12:15:59 -0800246 // Switch Events are not affected by event reordering
Pavlin Radoslavov018d5332014-02-19 23:08:35 -0800247 }
248 if (portEvent != null) {
Yuta HIGUCHIa341b112014-02-23 15:42:00 -0800249 ByteBuffer id = portEvent.getIDasByteBuffer();
Pavlin Radoslavov018d5332014-02-19 23:08:35 -0800250 addedPortEvents.remove(id);
251 removedPortEvents.put(id, portEvent);
Pavlin Radoslavov706add22014-02-20 12:15:59 -0800252 reorderedAddedPortEvents.remove(id);
Pavlin Radoslavov018d5332014-02-19 23:08:35 -0800253 }
254 if (linkEvent != null) {
Yuta HIGUCHIa341b112014-02-23 15:42:00 -0800255 ByteBuffer id = linkEvent.getIDasByteBuffer();
Pavlin Radoslavov018d5332014-02-19 23:08:35 -0800256 addedLinkEvents.remove(id);
257 removedLinkEvents.put(id, linkEvent);
Pavlin Radoslavov706add22014-02-20 12:15:59 -0800258 reorderedAddedLinkEvents.remove(id);
Pavlin Radoslavov018d5332014-02-19 23:08:35 -0800259 }
260 if (deviceEvent != null) {
Yuta HIGUCHIa341b112014-02-23 15:42:00 -0800261 ByteBuffer id = deviceEvent.getIDasByteBuffer();
Pavlin Radoslavov018d5332014-02-19 23:08:35 -0800262 addedDeviceEvents.remove(id);
263 removedDeviceEvents.put(id, deviceEvent);
Pavlin Radoslavov706add22014-02-20 12:15:59 -0800264 reorderedAddedDeviceEvents.remove(id);
Pavlin Radoslavov018d5332014-02-19 23:08:35 -0800265 }
Pavlin Radoslavov721a2e02014-02-14 23:40:14 -0800266 break;
267 }
268 }
Pavlin Radoslavov3c9cc552014-02-20 09:58:38 -0800269
270 //
Pavlin Radoslavov8ffb8bf2014-02-20 15:34:26 -0800271 // Lock the Network Graph while it is modified
272 //
273 networkGraph.acquireWriteLock();
274
Jonathan Hart26241692014-02-20 16:31:11 -0800275 try {
276 //
277 // Apply the classified events.
278 //
279 // Apply the "add" events in the proper order:
280 // switch, port, link, device
281 //
282 for (SwitchEvent switchEvent : addedSwitchEvents.values())
283 addSwitch(switchEvent);
284 for (PortEvent portEvent : addedPortEvents.values())
285 addPort(portEvent);
286 for (LinkEvent linkEvent : addedLinkEvents.values())
287 addLink(linkEvent);
288 for (DeviceEvent deviceEvent : addedDeviceEvents.values())
289 addDevice(deviceEvent);
290 //
291 // Apply the "remove" events in the reverse order:
292 // device, link, port, switch
293 //
294 for (DeviceEvent deviceEvent : removedDeviceEvents.values())
295 removeDevice(deviceEvent);
296 for (LinkEvent linkEvent : removedLinkEvents.values())
297 removeLink(linkEvent);
298 for (PortEvent portEvent : removedPortEvents.values())
299 removePort(portEvent);
300 for (SwitchEvent switchEvent : removedSwitchEvents.values())
301 removeSwitch(switchEvent);
Yuta HIGUCHI3aca81a2014-02-23 12:41:19 -0800302
Jonathan Hart26241692014-02-20 16:31:11 -0800303 //
304 // Apply reordered events
305 //
306 applyReorderedEvents(! addedSwitchEvents.isEmpty(),
307 ! addedPortEvents.isEmpty());
Yuta HIGUCHI3aca81a2014-02-23 12:41:19 -0800308
Jonathan Hart26241692014-02-20 16:31:11 -0800309 }
310 finally {
311 //
312 // Network Graph modifications completed: Release the lock
313 //
314 networkGraph.releaseWriteLock();
315 }
Yuta HIGUCHI3aca81a2014-02-23 12:41:19 -0800316
Pavlin Radoslavov8ffb8bf2014-02-20 15:34:26 -0800317 //
Pavlin Radoslavov74986ce2014-02-20 13:17:20 -0800318 // Dispatch the Topology Notification Events to the applications
319 //
320 dispatchNetworkGraphEvents();
Pavlin Radoslavov721a2e02014-02-14 23:40:14 -0800321 }
322
323 /**
324 * Receive a notification that an entry is added.
325 *
326 * @param value the value for the entry.
327 */
328 @Override
329 public void entryAdded(TopologyEvent value) {
330 EventEntry<TopologyEvent> eventEntry =
331 new EventEntry<TopologyEvent>(EventEntry.Type.ENTRY_ADD,
332 value);
333 topologyEvents.add(eventEntry);
334 }
335
336 /**
337 * Receive a notification that an entry is removed.
338 *
339 * @param value the value for the entry.
340 */
341 @Override
342 public void entryRemoved(TopologyEvent value) {
343 EventEntry<TopologyEvent> eventEntry =
344 new EventEntry<TopologyEvent>(EventEntry.Type.ENTRY_REMOVE,
345 value);
346 topologyEvents.add(eventEntry);
347 }
348
349 /**
350 * Receive a notification that an entry is updated.
351 *
352 * @param value the value for the entry.
353 */
354 @Override
355 public void entryUpdated(TopologyEvent value) {
356 // NOTE: The ADD and UPDATE events are processed in same way
357 entryAdded(value);
358 }
359 }
360
361 /**
362 * Startup processing.
363 *
364 * @param datagridService the datagrid service to use.
365 */
366 void startup(IDatagridService datagridService) {
367 eventChannel = datagridService.addListener(EVENT_CHANNEL_NAME,
368 eventHandler,
369 byte[].class,
370 TopologyEvent.class);
371 eventHandler.start();
372 }
373
Pavlin Radoslavov74986ce2014-02-20 13:17:20 -0800374 /**
375 * Dispatch Network Graph Events to the listeners.
376 */
377 private void dispatchNetworkGraphEvents() {
378 if (apiAddedSwitchEvents.isEmpty() &&
379 apiRemovedSwitchEvents.isEmpty() &&
380 apiAddedPortEvents.isEmpty() &&
381 apiRemovedPortEvents.isEmpty() &&
382 apiAddedLinkEvents.isEmpty() &&
383 apiRemovedLinkEvents.isEmpty() &&
384 apiAddedDeviceEvents.isEmpty() &&
385 apiRemovedDeviceEvents.isEmpty()) {
386 return; // No events to dispatch
387 }
388
Yuta HIGUCHI3aca81a2014-02-23 12:41:19 -0800389 if (log.isDebugEnabled()) {
390 //
391 // Debug statements
392 // TODO: Those statements should be removed in the future
393 //
394 for (SwitchEvent switchEvent : apiAddedSwitchEvents)
395 log.debug("Dispatch Network Graph Event: ADDED {}", switchEvent);
396 for (SwitchEvent switchEvent : apiRemovedSwitchEvents)
397 log.debug("Dispatch Network Graph Event: REMOVED {}", switchEvent);
398 for (PortEvent portEvent : apiAddedPortEvents)
399 log.debug("Dispatch Network Graph Event: ADDED {}", portEvent);
400 for (PortEvent portEvent : apiRemovedPortEvents)
401 log.debug("Dispatch Network Graph Event: REMOVED {}", portEvent);
402 for (LinkEvent linkEvent : apiAddedLinkEvents)
403 log.debug("Dispatch Network Graph Event: ADDED {}", linkEvent);
404 for (LinkEvent linkEvent : apiRemovedLinkEvents)
405 log.debug("Dispatch Network Graph Event: REMOVED {}", linkEvent);
406 for (DeviceEvent deviceEvent : apiAddedDeviceEvents)
407 log.debug("Dispatch Network Graph Event: ADDED {}", deviceEvent);
408 for (DeviceEvent deviceEvent : apiRemovedDeviceEvents)
409 log.debug("Dispatch Network Graph Event: REMOVED {}", deviceEvent);
410 }
adminbc181552014-02-21 18:36:42 -0800411
Pavlin Radoslavov74986ce2014-02-20 13:17:20 -0800412 // Deliver the events
413 for (INetworkGraphListener listener : this.networkGraphListeners) {
414 // TODO: Should copy before handing them over to listener?
415 listener.networkGraphEvents(apiAddedSwitchEvents,
416 apiRemovedSwitchEvents,
417 apiAddedPortEvents,
418 apiRemovedPortEvents,
419 apiAddedLinkEvents,
420 apiRemovedLinkEvents,
421 apiAddedDeviceEvents,
422 apiRemovedDeviceEvents);
423 }
424
425 //
426 // Cleanup
427 //
428 apiAddedSwitchEvents.clear();
429 apiRemovedSwitchEvents.clear();
430 apiAddedPortEvents.clear();
431 apiRemovedPortEvents.clear();
432 apiAddedLinkEvents.clear();
433 apiRemovedLinkEvents.clear();
434 apiAddedDeviceEvents.clear();
435 apiRemovedDeviceEvents.clear();
436 }
437
438 /**
439 * Apply reordered events.
440 *
441 * @param hasAddedSwitchEvents true if there were Added Switch Events.
442 * @param hasAddedPortEvents true if there were Added Port Events.
443 */
444 private void applyReorderedEvents(boolean hasAddedSwitchEvents,
445 boolean hasAddedPortEvents) {
446 if (! (hasAddedSwitchEvents || hasAddedPortEvents))
447 return; // Nothing to do
448
449 //
450 // Try to apply the reordered events.
451 //
452 // NOTE: For simplicity we try to apply all events of a particular
453 // type if any "parent" type event was processed:
454 // - Apply reordered Port Events if Switches were added
455 // - Apply reordered Link and Device Events if Switches or Ports
456 // were added
457 //
adminbc181552014-02-21 18:36:42 -0800458
Pavlin Radoslavov74986ce2014-02-20 13:17:20 -0800459 //
460 // Apply reordered Port Events if Switches were added
461 //
462 if (hasAddedSwitchEvents) {
adminbc181552014-02-21 18:36:42 -0800463 Map<ByteBuffer, PortEvent> portEvents = reorderedAddedPortEvents;
464 reorderedAddedPortEvents = new HashMap<>();
Pavlin Radoslavov74986ce2014-02-20 13:17:20 -0800465 for (PortEvent portEvent : portEvents.values())
466 addPort(portEvent);
467 }
468 //
469 // Apply reordered Link and Device Events if Switches or Ports
470 // were added.
471 //
adminbc181552014-02-21 18:36:42 -0800472 Map<ByteBuffer, LinkEvent> linkEvents = reorderedAddedLinkEvents;
473 reorderedAddedLinkEvents = new HashMap<>();
Pavlin Radoslavov74986ce2014-02-20 13:17:20 -0800474 for (LinkEvent linkEvent : linkEvents.values())
475 addLink(linkEvent);
adminbc181552014-02-21 18:36:42 -0800476 //
477 Map<ByteBuffer, DeviceEvent> deviceEvents = reorderedAddedDeviceEvents;
478 reorderedAddedDeviceEvents = new HashMap<>();
Pavlin Radoslavov74986ce2014-02-20 13:17:20 -0800479 for (DeviceEvent deviceEvent : deviceEvents.values())
480 addDevice(deviceEvent);
481 }
482
Pavlin Radoslavov734ff5a2014-02-26 10:20:43 -0800483 /**
484 * Switch discovered event.
485 *
486 * @param switchEvent the switch event.
487 * @param portEvents the corresponding port events for the switch.
488 */
Pavlin Radoslavovc1cfde52014-02-19 11:35:29 -0800489 @Override
Pavlin Radoslavov018d5332014-02-19 23:08:35 -0800490 public void putSwitchDiscoveryEvent(SwitchEvent switchEvent,
491 Collection<PortEvent> portEvents) {
492 if (datastore.addSwitch(switchEvent, portEvents)) {
Pavlin Radoslavovc1cfde52014-02-19 11:35:29 -0800493 // Send out notification
Pavlin Radoslavov87dcc262014-02-19 21:13:23 -0800494 TopologyEvent topologyEvent = new TopologyEvent(switchEvent);
Pavlin Radoslavovc1cfde52014-02-19 11:35:29 -0800495 eventChannel.addEntry(topologyEvent.getID(), topologyEvent);
TeruUd1c5b652014-03-24 13:58:46 -0700496
Pavlin Radoslavov26d83402014-02-20 15:24:30 -0800497 // Send out notification for each port
Pavlin Radoslavov018d5332014-02-19 23:08:35 -0800498 for (PortEvent portEvent : portEvents) {
499 topologyEvent = new TopologyEvent(portEvent);
500 eventChannel.addEntry(topologyEvent.getID(), topologyEvent);
501 }
Pavlin Radoslavov26d83402014-02-20 15:24:30 -0800502
503 //
504 // Keep track of the added ports
505 //
506 // Get the old Port Events
507 Map<ByteBuffer, PortEvent> oldPortEvents =
508 discoveredAddedPortEvents.get(switchEvent.getDpid());
509 if (oldPortEvents == null)
510 oldPortEvents = new HashMap<>();
511
512 // Store the new Port Events in the local cache
513 Map<ByteBuffer, PortEvent> newPortEvents = new HashMap<>();
514 for (PortEvent portEvent : portEvents) {
Yuta HIGUCHIa341b112014-02-23 15:42:00 -0800515 ByteBuffer id = portEvent.getIDasByteBuffer();
Pavlin Radoslavov26d83402014-02-20 15:24:30 -0800516 newPortEvents.put(id, portEvent);
517 }
518 discoveredAddedPortEvents.put(switchEvent.getDpid(),
519 newPortEvents);
520
521 //
522 // Extract the removed ports
523 //
524 List<PortEvent> removedPortEvents = new LinkedList<>();
525 for (Map.Entry<ByteBuffer, PortEvent> entry : oldPortEvents.entrySet()) {
526 ByteBuffer key = entry.getKey();
527 PortEvent portEvent = entry.getValue();
528 if (! newPortEvents.containsKey(key))
529 removedPortEvents.add(portEvent);
530 }
531
532 // Cleanup old removed ports
533 for (PortEvent portEvent : removedPortEvents)
534 removePortDiscoveryEvent(portEvent);
Pavlin Radoslavovc1cfde52014-02-19 11:35:29 -0800535 }
Pavlin Radoslavovc1cfde52014-02-19 11:35:29 -0800536 }
537
Pavlin Radoslavov734ff5a2014-02-26 10:20:43 -0800538 /**
539 * Switch removed event.
540 *
541 * @param switchEvent the switch event.
542 */
Pavlin Radoslavovc1cfde52014-02-19 11:35:29 -0800543 @Override
Pavlin Radoslavov6ea84a42014-02-19 15:50:01 -0800544 public void removeSwitchDiscoveryEvent(SwitchEvent switchEvent) {
Pavlin Radoslavov26d83402014-02-20 15:24:30 -0800545 // Get the old Port Events
546 Map<ByteBuffer, PortEvent> oldPortEvents =
547 discoveredAddedPortEvents.get(switchEvent.getDpid());
548 if (oldPortEvents == null)
549 oldPortEvents = new HashMap<>();
Pavlin Radoslavov018d5332014-02-19 23:08:35 -0800550
Pavlin Radoslavov26d83402014-02-20 15:24:30 -0800551 if (datastore.deactivateSwitch(switchEvent, oldPortEvents.values())) {
Pavlin Radoslavovc1cfde52014-02-19 11:35:29 -0800552 // Send out notification
553 eventChannel.removeEntry(switchEvent.getID());
Pavlin Radoslavov018d5332014-02-19 23:08:35 -0800554
Pavlin Radoslavov6f870a12014-02-24 14:25:54 -0800555 //
556 // Send out notification for each port.
557 //
558 // NOTE: We don't use removePortDiscoveryEvent() for the cleanup,
559 // because it will attempt to remove the port from the database,
560 // and the deactiveSwitch() call above already removed all ports.
561 //
Pavlin Radoslavov26d83402014-02-20 15:24:30 -0800562 for (PortEvent portEvent : oldPortEvents.values())
Pavlin Radoslavov018d5332014-02-19 23:08:35 -0800563 eventChannel.removeEntry(portEvent.getID());
Pavlin Radoslavov26d83402014-02-20 15:24:30 -0800564 discoveredAddedPortEvents.remove(switchEvent.getDpid());
565
566 // Cleanup for each link
567 Map<ByteBuffer, LinkEvent> oldLinkEvents =
568 discoveredAddedLinkEvents.get(switchEvent.getDpid());
569 if (oldLinkEvents != null) {
Yuta HIGUCHI95b20352014-02-24 12:06:27 -0800570 for (LinkEvent linkEvent : new ArrayList<>(oldLinkEvents.values())) {
Pavlin Radoslavov26d83402014-02-20 15:24:30 -0800571 removeLinkDiscoveryEvent(linkEvent);
Yuta HIGUCHI95b20352014-02-24 12:06:27 -0800572 }
Pavlin Radoslavov26d83402014-02-20 15:24:30 -0800573 discoveredAddedLinkEvents.remove(switchEvent.getDpid());
574 }
575
576 // Cleanup for each device
577 Map<ByteBuffer, DeviceEvent> oldDeviceEvents =
578 discoveredAddedDeviceEvents.get(switchEvent.getDpid());
579 if (oldDeviceEvents != null) {
Yuta HIGUCHI95b20352014-02-24 12:06:27 -0800580 for (DeviceEvent deviceEvent : new ArrayList<>(oldDeviceEvents.values())) {
Pavlin Radoslavov26d83402014-02-20 15:24:30 -0800581 removeDeviceDiscoveryEvent(deviceEvent);
Yuta HIGUCHI95b20352014-02-24 12:06:27 -0800582 }
Pavlin Radoslavov26d83402014-02-20 15:24:30 -0800583 discoveredAddedDeviceEvents.remove(switchEvent.getDpid());
Pavlin Radoslavov018d5332014-02-19 23:08:35 -0800584 }
Pavlin Radoslavovc1cfde52014-02-19 11:35:29 -0800585 }
Pavlin Radoslavovc1cfde52014-02-19 11:35:29 -0800586 }
587
Pavlin Radoslavov734ff5a2014-02-26 10:20:43 -0800588 /**
589 * Port discovered event.
590 *
591 * @param portEvent the port event.
592 */
Pavlin Radoslavovc1cfde52014-02-19 11:35:29 -0800593 @Override
Pavlin Radoslavov6ea84a42014-02-19 15:50:01 -0800594 public void putPortDiscoveryEvent(PortEvent portEvent) {
Pavlin Radoslavov50cd1482014-02-19 16:57:03 -0800595 if (datastore.addPort(portEvent)) {
Pavlin Radoslavovc1cfde52014-02-19 11:35:29 -0800596 // Send out notification
Pavlin Radoslavov87dcc262014-02-19 21:13:23 -0800597 TopologyEvent topologyEvent = new TopologyEvent(portEvent);
Pavlin Radoslavov018d5332014-02-19 23:08:35 -0800598 eventChannel.addEntry(topologyEvent.getID(), topologyEvent);
Pavlin Radoslavov26d83402014-02-20 15:24:30 -0800599
600 // Store the new Port Event in the local cache
601 Map<ByteBuffer, PortEvent> oldPortEvents =
602 discoveredAddedPortEvents.get(portEvent.getDpid());
603 if (oldPortEvents == null) {
604 oldPortEvents = new HashMap<>();
605 discoveredAddedPortEvents.put(portEvent.getDpid(),
606 oldPortEvents);
607 }
Yuta HIGUCHIa341b112014-02-23 15:42:00 -0800608 ByteBuffer id = portEvent.getIDasByteBuffer();
Pavlin Radoslavov26d83402014-02-20 15:24:30 -0800609 oldPortEvents.put(id, portEvent);
Pavlin Radoslavovc1cfde52014-02-19 11:35:29 -0800610 }
Pavlin Radoslavovc1cfde52014-02-19 11:35:29 -0800611 }
612
Pavlin Radoslavov734ff5a2014-02-26 10:20:43 -0800613 /**
614 * Port removed event.
615 *
616 * @param portEvent the port event.
617 */
Pavlin Radoslavovc1cfde52014-02-19 11:35:29 -0800618 @Override
Pavlin Radoslavov6ea84a42014-02-19 15:50:01 -0800619 public void removePortDiscoveryEvent(PortEvent portEvent) {
Pavlin Radoslavov50cd1482014-02-19 16:57:03 -0800620 if (datastore.deactivatePort(portEvent)) {
Pavlin Radoslavovc1cfde52014-02-19 11:35:29 -0800621 // Send out notification
622 eventChannel.removeEntry(portEvent.getID());
Pavlin Radoslavov26d83402014-02-20 15:24:30 -0800623
624 // Cleanup the Port Event from the local cache
625 Map<ByteBuffer, PortEvent> oldPortEvents =
626 discoveredAddedPortEvents.get(portEvent.getDpid());
627 if (oldPortEvents != null) {
Yuta HIGUCHIa341b112014-02-23 15:42:00 -0800628 ByteBuffer id = portEvent.getIDasByteBuffer();
Pavlin Radoslavov26d83402014-02-20 15:24:30 -0800629 oldPortEvents.remove(id);
630 }
631
632 // Cleanup for the incoming link
633 Map<ByteBuffer, LinkEvent> oldLinkEvents =
634 discoveredAddedLinkEvents.get(portEvent.getDpid());
635 if (oldLinkEvents != null) {
Pavlin Radoslavov6f870a12014-02-24 14:25:54 -0800636 for (LinkEvent linkEvent : new ArrayList<>(oldLinkEvents.values())) {
Pavlin Radoslavov26d83402014-02-20 15:24:30 -0800637 if (linkEvent.getDst().equals(portEvent.id)) {
638 removeLinkDiscoveryEvent(linkEvent);
Yuta HIGUCHI95b20352014-02-24 12:06:27 -0800639 // XXX If we change our model to allow multiple Link on
640 // a Port, this loop must be fixed to allow continuing.
Pavlin Radoslavov26d83402014-02-20 15:24:30 -0800641 break;
642 }
643 }
644 }
645
646 // Cleanup for the connected devices
647 // TODO: The implementation below is probably wrong
648 List<DeviceEvent> removedDeviceEvents = new LinkedList<>();
649 Map<ByteBuffer, DeviceEvent> oldDeviceEvents =
650 discoveredAddedDeviceEvents.get(portEvent.getDpid());
651 if (oldDeviceEvents != null) {
Yuta HIGUCHI95b20352014-02-24 12:06:27 -0800652 for (DeviceEvent deviceEvent : new ArrayList<>(oldDeviceEvents.values())) {
Pavlin Radoslavov26d83402014-02-20 15:24:30 -0800653 for (SwitchPort swp : deviceEvent.getAttachmentPoints()) {
654 if (swp.equals(portEvent.id)) {
655 removedDeviceEvents.add(deviceEvent);
Pavlin Radoslavov26d83402014-02-20 15:24:30 -0800656 }
657 }
658 }
659 for (DeviceEvent deviceEvent : removedDeviceEvents)
660 removeDeviceDiscoveryEvent(deviceEvent);
661 }
Pavlin Radoslavovc1cfde52014-02-19 11:35:29 -0800662 }
Pavlin Radoslavovc1cfde52014-02-19 11:35:29 -0800663 }
664
Pavlin Radoslavov734ff5a2014-02-26 10:20:43 -0800665 /**
666 * Link discovered event.
667 *
668 * @param linkEvent the link event.
669 */
Pavlin Radoslavovc1cfde52014-02-19 11:35:29 -0800670 @Override
Pavlin Radoslavov6ea84a42014-02-19 15:50:01 -0800671 public void putLinkDiscoveryEvent(LinkEvent linkEvent) {
Pavlin Radoslavov50cd1482014-02-19 16:57:03 -0800672 if (datastore.addLink(linkEvent)) {
Pavlin Radoslavovc1cfde52014-02-19 11:35:29 -0800673 // Send out notification
Pavlin Radoslavov87dcc262014-02-19 21:13:23 -0800674 TopologyEvent topologyEvent = new TopologyEvent(linkEvent);
Pavlin Radoslavovc1cfde52014-02-19 11:35:29 -0800675 eventChannel.addEntry(topologyEvent.getID(), topologyEvent);
Pavlin Radoslavov26d83402014-02-20 15:24:30 -0800676
677 // Store the new Link Event in the local cache
678 Map<ByteBuffer, LinkEvent> oldLinkEvents =
679 discoveredAddedLinkEvents.get(linkEvent.getDst().getDpid());
680 if (oldLinkEvents == null) {
681 oldLinkEvents = new HashMap<>();
682 discoveredAddedLinkEvents.put(linkEvent.getDst().getDpid(),
683 oldLinkEvents);
684 }
Yuta HIGUCHIa341b112014-02-23 15:42:00 -0800685 ByteBuffer id = linkEvent.getIDasByteBuffer();
Pavlin Radoslavov26d83402014-02-20 15:24:30 -0800686 oldLinkEvents.put(id, linkEvent);
Pavlin Radoslavovc1cfde52014-02-19 11:35:29 -0800687 }
Pavlin Radoslavovc1cfde52014-02-19 11:35:29 -0800688 }
689
Pavlin Radoslavov734ff5a2014-02-26 10:20:43 -0800690 /**
691 * Link removed event.
692 *
693 * @param linkEvent the link event.
694 */
Pavlin Radoslavovc1cfde52014-02-19 11:35:29 -0800695 @Override
Pavlin Radoslavov6ea84a42014-02-19 15:50:01 -0800696 public void removeLinkDiscoveryEvent(LinkEvent linkEvent) {
Pavlin Radoslavov50cd1482014-02-19 16:57:03 -0800697 if (datastore.removeLink(linkEvent)) {
Pavlin Radoslavovc1cfde52014-02-19 11:35:29 -0800698 // Send out notification
699 eventChannel.removeEntry(linkEvent.getID());
Pavlin Radoslavov26d83402014-02-20 15:24:30 -0800700
701 // Cleanup the Link Event from the local cache
702 Map<ByteBuffer, LinkEvent> oldLinkEvents =
703 discoveredAddedLinkEvents.get(linkEvent.getDst().getDpid());
704 if (oldLinkEvents != null) {
Yuta HIGUCHIa341b112014-02-23 15:42:00 -0800705 ByteBuffer id = linkEvent.getIDasByteBuffer();
Pavlin Radoslavov26d83402014-02-20 15:24:30 -0800706 oldLinkEvents.remove(id);
707 }
Jonathan Hart22eb9882014-02-11 15:52:59 -0800708 }
Pavlin Radoslavovc1cfde52014-02-19 11:35:29 -0800709 }
Jonathan Hart22eb9882014-02-11 15:52:59 -0800710
Pavlin Radoslavov734ff5a2014-02-26 10:20:43 -0800711 /**
712 * Device discovered event.
713 *
714 * @param deviceEvent the device event.
715 */
Pavlin Radoslavovc1cfde52014-02-19 11:35:29 -0800716 @Override
Pavlin Radoslavov6ea84a42014-02-19 15:50:01 -0800717 public void putDeviceDiscoveryEvent(DeviceEvent deviceEvent) {
Pavlin Radoslavov50cd1482014-02-19 16:57:03 -0800718 if (datastore.addDevice(deviceEvent)) {
Pavlin Radoslavovc1cfde52014-02-19 11:35:29 -0800719 // Send out notification
Pavlin Radoslavov87dcc262014-02-19 21:13:23 -0800720 TopologyEvent topologyEvent = new TopologyEvent(deviceEvent);
Pavlin Radoslavov50cd1482014-02-19 16:57:03 -0800721 eventChannel.addEntry(topologyEvent.getID(), topologyEvent);
TeruUd1c5b652014-03-24 13:58:46 -0700722 log.debug("Put the device info into the cache of the graph. mac {}", deviceEvent.getMac());
723
Pavlin Radoslavov26d83402014-02-20 15:24:30 -0800724 // Store the new Device Event in the local cache
725 // TODO: The implementation below is probably wrong
726 for (SwitchPort swp : deviceEvent.getAttachmentPoints()) {
727 Map<ByteBuffer, DeviceEvent> oldDeviceEvents =
728 discoveredAddedDeviceEvents.get(swp.getDpid());
729 if (oldDeviceEvents == null) {
730 oldDeviceEvents = new HashMap<>();
731 discoveredAddedDeviceEvents.put(swp.getDpid(),
732 oldDeviceEvents);
733 }
Yuta HIGUCHIa341b112014-02-23 15:42:00 -0800734 ByteBuffer id = deviceEvent.getIDasByteBuffer();
Pavlin Radoslavov26d83402014-02-20 15:24:30 -0800735 oldDeviceEvents.put(id, deviceEvent);
736 }
Jonathan Hart22eb9882014-02-11 15:52:59 -0800737 }
Pavlin Radoslavovc1cfde52014-02-19 11:35:29 -0800738 }
Jonathan Hart22eb9882014-02-11 15:52:59 -0800739
Pavlin Radoslavov734ff5a2014-02-26 10:20:43 -0800740 /**
741 * Device removed event.
742 *
743 * @param deviceEvent the device event.
744 */
Pavlin Radoslavovc1cfde52014-02-19 11:35:29 -0800745 @Override
Pavlin Radoslavov6ea84a42014-02-19 15:50:01 -0800746 public void removeDeviceDiscoveryEvent(DeviceEvent deviceEvent) {
Pavlin Radoslavov50cd1482014-02-19 16:57:03 -0800747 if (datastore.removeDevice(deviceEvent)) {
Pavlin Radoslavovc1cfde52014-02-19 11:35:29 -0800748 // Send out notification
749 eventChannel.removeEntry(deviceEvent.getID());
TeruUd1c5b652014-03-24 13:58:46 -0700750 log.debug("Remove the device info into the cache of the graph. mac {}", deviceEvent.getMac());
Pavlin Radoslavov26d83402014-02-20 15:24:30 -0800751
752 // Cleanup the Device Event from the local cache
753 // TODO: The implementation below is probably wrong
754 ByteBuffer id = ByteBuffer.wrap(deviceEvent.getID());
755 for (SwitchPort swp : deviceEvent.getAttachmentPoints()) {
756 Map<ByteBuffer, DeviceEvent> oldDeviceEvents =
757 discoveredAddedDeviceEvents.get(swp.getDpid());
758 if (oldDeviceEvents != null) {
759 oldDeviceEvents.remove(id);
760 }
761 }
Jonathan Hart22eb9882014-02-11 15:52:59 -0800762 }
Pavlin Radoslavovc1cfde52014-02-19 11:35:29 -0800763 }
Jonathan Hart22eb9882014-02-11 15:52:59 -0800764
Pavlin Radoslavov734ff5a2014-02-26 10:20:43 -0800765 /**
766 * Add a switch to the Network Graph.
767 *
768 * @param switchEvent the Switch Event with the switch to add.
769 */
Pavlin Radoslavov74986ce2014-02-20 13:17:20 -0800770 private void addSwitch(SwitchEvent switchEvent) {
771 Switch sw = networkGraph.getSwitch(switchEvent.getDpid());
Pavlin Radoslavov3c9cc552014-02-20 09:58:38 -0800772 if (sw == null) {
Pavlin Radoslavov74986ce2014-02-20 13:17:20 -0800773 sw = new SwitchImpl(networkGraph, switchEvent.getDpid());
Pavlin Radoslavov3c9cc552014-02-20 09:58:38 -0800774 networkGraph.putSwitch(sw);
775 } else {
776 // TODO: Update the switch attributes
777 // TODO: Nothing to do for now
778 }
Pavlin Radoslavov74986ce2014-02-20 13:17:20 -0800779 apiAddedSwitchEvents.add(switchEvent);
Pavlin Radoslavov3c9cc552014-02-20 09:58:38 -0800780 }
781
Pavlin Radoslavov734ff5a2014-02-26 10:20:43 -0800782 /**
783 * Remove a switch from the Network Graph.
784 *
785 * @param switchEvent the Switch Event with the switch to remove.
786 */
Pavlin Radoslavov74986ce2014-02-20 13:17:20 -0800787 private void removeSwitch(SwitchEvent switchEvent) {
788 Switch sw = networkGraph.getSwitch(switchEvent.getDpid());
Pavlin Radoslavov3c9cc552014-02-20 09:58:38 -0800789 if (sw == null) {
Pavlin Radoslavov74986ce2014-02-20 13:17:20 -0800790 log.warn("Switch {} already removed, ignoring", switchEvent);
Pavlin Radoslavov3c9cc552014-02-20 09:58:38 -0800791 return;
792 }
793
794 //
795 // Remove all Ports on the Switch
796 //
797 ArrayList<PortEvent> portsToRemove = new ArrayList<>();
798 for (Port port : sw.getPorts()) {
799 log.warn("Port {} on Switch {} should be removed prior to removing Switch. Removing Port now.",
Pavlin Radoslavov74986ce2014-02-20 13:17:20 -0800800 port, switchEvent);
Pavlin Radoslavov3c9cc552014-02-20 09:58:38 -0800801 PortEvent portEvent = new PortEvent(port.getDpid(),
802 port.getNumber());
803 portsToRemove.add(portEvent);
804 }
805 for (PortEvent portEvent : portsToRemove)
806 removePort(portEvent);
807
Pavlin Radoslavov74986ce2014-02-20 13:17:20 -0800808 networkGraph.removeSwitch(switchEvent.getDpid());
809 apiRemovedSwitchEvents.add(switchEvent);
Pavlin Radoslavov3c9cc552014-02-20 09:58:38 -0800810 }
811
Pavlin Radoslavov734ff5a2014-02-26 10:20:43 -0800812 /**
813 * Add a port to the Network Graph.
814 *
815 * @param portEvent the Port Event with the port to add.
816 */
Pavlin Radoslavov3c9cc552014-02-20 09:58:38 -0800817 private void addPort(PortEvent portEvent) {
818 Switch sw = networkGraph.getSwitch(portEvent.getDpid());
819 if (sw == null) {
Pavlin Radoslavov706add22014-02-20 12:15:59 -0800820 // Reordered event: delay the event in local cache
Yuta HIGUCHIa341b112014-02-23 15:42:00 -0800821 ByteBuffer id = portEvent.getIDasByteBuffer();
Pavlin Radoslavov706add22014-02-20 12:15:59 -0800822 reorderedAddedPortEvents.put(id, portEvent);
Pavlin Radoslavov3c9cc552014-02-20 09:58:38 -0800823 return;
824 }
825 SwitchImpl switchImpl = getSwitchImpl(sw);
826
827 Port port = sw.getPort(portEvent.getNumber());
828 if (port == null) {
829 port = new PortImpl(networkGraph, sw, portEvent.getNumber());
830 switchImpl.addPort(port);
831 } else {
832 // TODO: Update the port attributes
833 }
Pavlin Radoslavov74986ce2014-02-20 13:17:20 -0800834 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) {
843 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 }
849
850 Port port = sw.getPort(portEvent.getNumber());
851 if (port == null) {
852 log.warn("Port {} already removed, ignoring", portEvent);
853 return;
854 }
855
856 //
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);
870
871 //
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);
890
891 // Remove the Port from the Switch
892 SwitchImpl switchImpl = getSwitchImpl(sw);
893 switchImpl.removePort(port);
Pavlin Radoslavov74986ce2014-02-20 13:17:20 -0800894
895 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) {
904 Port srcPort = networkGraph.getPort(linkEvent.getSrc().dpid,
905 linkEvent.getSrc().number);
Pavlin Radoslavov3c9cc552014-02-20 09:58:38 -0800906 Port dstPort = networkGraph.getPort(linkEvent.getDst().dpid,
907 linkEvent.getDst().number);
Pavlin Radoslavov706add22014-02-20 12:15:59 -0800908 if ((srcPort == null) || (dstPort == null)) {
909 // Reordered event: delay the event in local cache
Yuta HIGUCHIa341b112014-02-23 15:42:00 -0800910 ByteBuffer id = linkEvent.getIDasByteBuffer();
Pavlin Radoslavov706add22014-02-20 12:15:59 -0800911 reorderedAddedLinkEvents.put(id, linkEvent);
Pavlin Radoslavov3c9cc552014-02-20 09:58:38 -0800912 return;
913 }
914
915 // 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);
924
925 // 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
947 }
Pavlin Radoslavov74986ce2014-02-20 13:17:20 -0800948
949 apiAddedLinkEvents.add(linkEvent);
Pavlin Radoslavov3c9cc552014-02-20 09:58:38 -0800950 }
951
Pavlin Radoslavov734ff5a2014-02-26 10:20:43 -0800952 /**
953 * Remove a link from the Network Graph.
954 *
955 * @param linkEvent the Link Event with the link to remove.
956 */
Pavlin Radoslavov3c9cc552014-02-20 09:58:38 -0800957 private void removeLink(LinkEvent linkEvent) {
958 Port srcPort = networkGraph.getPort(linkEvent.getSrc().dpid,
959 linkEvent.getSrc().number);
960 if (srcPort == null) {
961 log.warn("Src Port for Link {} already removed, ignoring",
962 linkEvent);
963 return;
964 }
965
966 Port dstPort = networkGraph.getPort(linkEvent.getDst().dpid,
967 linkEvent.getDst().number);
968 if (dstPort == null) {
969 log.warn("Dst Port for Link {} already removed, ignoring",
970 linkEvent);
971 return;
972 }
973
974 //
975 // Remove the Link instance from the Destination Port Incoming Link
976 // and the Source Port Outgoing Link.
977 //
978 Link link = dstPort.getIncomingLink();
979 if (link == null) {
980 log.warn("Link {} already removed on destination Port", linkEvent);
981 }
982 link = srcPort.getOutgoingLink();
983 if (link == null) {
984 log.warn("Link {} already removed on src Port", linkEvent);
985 }
986 getPortImpl(dstPort).setIncomingLink(null);
987 getPortImpl(srcPort).setOutgoingLink(null);
Pavlin Radoslavov74986ce2014-02-20 13:17:20 -0800988
989 apiRemovedLinkEvents.add(linkEvent);
Pavlin Radoslavov3c9cc552014-02-20 09:58:38 -0800990 }
991
Pavlin Radoslavov734ff5a2014-02-26 10:20:43 -0800992 /**
993 * Add a device to the Network Graph.
994 *
995 * TODO: Device-related work is incomplete.
996 * TODO: Eventually, we might need to consider reordering
997 * or addLink() and addDevice() events on the same port.
998 *
999 * @param deviceEvent the Device Event with the device to add.
1000 */
Pavlin Radoslavov3c9cc552014-02-20 09:58:38 -08001001 private void addDevice(DeviceEvent deviceEvent) {
1002 Device device = networkGraph.getDeviceByMac(deviceEvent.getMac());
TeruUd1c5b652014-03-24 13:58:46 -07001003
Pavlin Radoslavov3c9cc552014-02-20 09:58:38 -08001004 if (device == null) {
TeruUd1c5b652014-03-24 13:58:46 -07001005 log.debug("Existing device was not found in networkGraph. New device. mac {}", deviceEvent.getMac());
Pavlin Radoslavov3c9cc552014-02-20 09:58:38 -08001006 device = new DeviceImpl(networkGraph, deviceEvent.getMac());
1007 }
TeruUd1c5b652014-03-24 13:58:46 -07001008
Pavlin Radoslavov3c9cc552014-02-20 09:58:38 -08001009 DeviceImpl deviceImpl = getDeviceImpl(device);
1010
1011 // Update the IP addresses
1012 for (InetAddress ipAddr : deviceEvent.getIpAddresses())
1013 deviceImpl.addIpAddress(ipAddr);
1014
1015 // Process each attachment point
1016 boolean attachmentFound = false;
1017 for (SwitchPort swp : deviceEvent.getAttachmentPoints()) {
1018 // Attached Ports must exist
1019 Port port = networkGraph.getPort(swp.dpid, swp.number);
1020 if (port == null) {
Pavlin Radoslavov706add22014-02-20 12:15:59 -08001021 // Reordered event: delay the event in local cache
Yuta HIGUCHIa341b112014-02-23 15:42:00 -08001022 ByteBuffer id = deviceEvent.getIDasByteBuffer();
Pavlin Radoslavov706add22014-02-20 12:15:59 -08001023 reorderedAddedDeviceEvents.put(id, deviceEvent);
Pavlin Radoslavov3c9cc552014-02-20 09:58:38 -08001024 continue;
1025 }
1026 // Attached Ports must not have Link
1027 if (port.getOutgoingLink() != null ||
1028 port.getIncomingLink() != null) {
1029 log.warn("Link (Out:{},In:{}) exist on the attachment point, skipping mutation.",
1030 port.getOutgoingLink(),
1031 port.getIncomingLink());
1032 continue;
1033 }
1034
1035 // Add Device <-> Port attachment
1036 PortImpl portImpl = getPortImpl(port);
1037 portImpl.addDevice(device);
1038 deviceImpl.addAttachmentPoint(port);
1039 attachmentFound = true;
1040 }
1041
1042 // Update the device in the Network Graph
Pavlin Radoslavov74986ce2014-02-20 13:17:20 -08001043 if (attachmentFound) {
TeruUd1c5b652014-03-24 13:58:46 -07001044 log.debug("Storing the info into networkGraph. mac {}", deviceEvent.getMac());
Pavlin Radoslavov3c9cc552014-02-20 09:58:38 -08001045 networkGraph.putDevice(device);
Pavlin Radoslavov74986ce2014-02-20 13:17:20 -08001046 apiAddedDeviceEvents.add(deviceEvent);
1047 }
Pavlin Radoslavov3c9cc552014-02-20 09:58:38 -08001048 }
1049
Pavlin Radoslavov734ff5a2014-02-26 10:20:43 -08001050 /**
1051 * Remove a device from the Network Graph.
1052 *
1053 * TODO: Device-related work is incomplete.
1054 *
1055 * @param deviceEvent the Device Event with the device to remove.
1056 */
Pavlin Radoslavov3c9cc552014-02-20 09:58:38 -08001057 private void removeDevice(DeviceEvent deviceEvent) {
1058 Device device = networkGraph.getDeviceByMac(deviceEvent.getMac());
1059 if (device == null) {
1060 log.warn("Device {} already removed, ignoring", deviceEvent);
1061 return;
1062 }
1063 DeviceImpl deviceImpl = getDeviceImpl(device);
1064
1065 // Process each attachment point
1066 for (SwitchPort swp : deviceEvent.getAttachmentPoints()) {
1067 // Attached Ports must exist
1068 Port port = networkGraph.getPort(swp.dpid, swp.number);
1069 if (port == null) {
1070 log.warn("Port for the attachment point {} did not exist. skipping attachment point mutation", swp);
1071 continue;
1072 }
1073
1074 // Remove Device <-> Port attachment
1075 PortImpl portImpl = getPortImpl(port);
1076 portImpl.removeDevice(device);
1077 deviceImpl.removeAttachmentPoint(port);
1078 }
Pavlin Radoslavov74986ce2014-02-20 13:17:20 -08001079
Pavlin Radoslavov3c9cc552014-02-20 09:58:38 -08001080 networkGraph.removeDevice(device);
Pavlin Radoslavov74986ce2014-02-20 13:17:20 -08001081 apiRemovedDeviceEvents.add(deviceEvent);
Pavlin Radoslavov3c9cc552014-02-20 09:58:38 -08001082 }
Jonathan Hart22eb9882014-02-11 15:52:59 -08001083
Pavlin Radoslavovc1cfde52014-02-19 11:35:29 -08001084 /**
Pavlin Radoslavov734ff5a2014-02-26 10:20:43 -08001085 * Get the SwitchImpl-casted switch implementation.
Pavlin Radoslavovc1cfde52014-02-19 11:35:29 -08001086 *
Pavlin Radoslavov734ff5a2014-02-26 10:20:43 -08001087 * @param sw the Switch to cast.
1088 * @return the SwitchImpl-casted switch implementation.
Pavlin Radoslavovc1cfde52014-02-19 11:35:29 -08001089 */
Pavlin Radoslavovc1cfde52014-02-19 11:35:29 -08001090 private SwitchImpl getSwitchImpl(Switch sw) {
1091 if (sw instanceof SwitchImpl) {
Pavlin Radoslavov734ff5a2014-02-26 10:20:43 -08001092 return (SwitchImpl)sw;
Pavlin Radoslavovc1cfde52014-02-19 11:35:29 -08001093 }
1094 throw new ClassCastException("SwitchImpl expected, but found: " + sw);
1095 }
1096
Pavlin Radoslavov734ff5a2014-02-26 10:20:43 -08001097 /**
1098 * Get the PortImpl-casted port implementation.
1099 *
1100 * @param port the Port to cast.
1101 * @return the PortImpl-casted port implementation.
1102 */
1103 private PortImpl getPortImpl(Port port) {
1104 if (port instanceof PortImpl) {
1105 return (PortImpl)port;
Pavlin Radoslavovc1cfde52014-02-19 11:35:29 -08001106 }
Pavlin Radoslavov734ff5a2014-02-26 10:20:43 -08001107 throw new ClassCastException("PortImpl expected, but found: " + port);
Pavlin Radoslavovc1cfde52014-02-19 11:35:29 -08001108 }
1109
Pavlin Radoslavov734ff5a2014-02-26 10:20:43 -08001110 /**
1111 * Get the LinkImpl-casted link implementation.
1112 *
1113 * @param link the Link to cast.
1114 * @return the LinkImpl-casted link implementation.
1115 */
1116 private LinkImpl getLinkImpl(Link link) {
1117 if (link instanceof LinkImpl) {
1118 return (LinkImpl)link;
Pavlin Radoslavovc1cfde52014-02-19 11:35:29 -08001119 }
Pavlin Radoslavov734ff5a2014-02-26 10:20:43 -08001120 throw new ClassCastException("LinkImpl expected, but found: " + link);
Pavlin Radoslavovc1cfde52014-02-19 11:35:29 -08001121 }
1122
Pavlin Radoslavov734ff5a2014-02-26 10:20:43 -08001123 /**
1124 * Get the DeviceImpl-casted device implementation.
1125 *
1126 * @param device the Device to cast.
1127 * @return the DeviceImpl-casted device implementation.
1128 */
1129 private DeviceImpl getDeviceImpl(Device device) {
1130 if (device instanceof DeviceImpl) {
1131 return (DeviceImpl)device;
Pavlin Radoslavovc1cfde52014-02-19 11:35:29 -08001132 }
Pavlin Radoslavov734ff5a2014-02-26 10:20:43 -08001133 throw new ClassCastException("DeviceImpl expected, but found: " + device);
Pavlin Radoslavovc1cfde52014-02-19 11:35:29 -08001134 }
1135
Pavlin Radoslavov734ff5a2014-02-26 10:20:43 -08001136 /**
1137 * Read the whole topology from the database.
1138 *
1139 * @return a collection of EventEntry-encapsulated Topology Events for
1140 * the whole topology.
1141 */
Pavlin Radoslavov018d5332014-02-19 23:08:35 -08001142 private Collection<EventEntry<TopologyEvent>> readWholeTopologyFromDB() {
1143 Collection<EventEntry<TopologyEvent>> collection =
1144 new LinkedList<EventEntry<TopologyEvent>>();
1145
Pavlin Radoslavovc1cfde52014-02-19 11:35:29 -08001146 // XXX May need to clear whole topology first, depending on
1147 // how we initially subscribe to replication events
1148
Pavlin Radoslavov018d5332014-02-19 23:08:35 -08001149 // Add all active switches
Yuta HIGUCHI66ca1bf2014-03-12 18:34:09 -07001150 for (KVSwitch sw : KVSwitch.getAllSwitches()) {
1151 if (sw.getStatus() != KVSwitch.STATUS.ACTIVE) {
Pavlin Radoslavovc1cfde52014-02-19 11:35:29 -08001152 continue;
1153 }
Pavlin Radoslavov018d5332014-02-19 23:08:35 -08001154
1155 SwitchEvent switchEvent = new SwitchEvent(sw.getDpid());
1156 TopologyEvent topologyEvent = new TopologyEvent(switchEvent);
1157 EventEntry<TopologyEvent> eventEntry =
1158 new EventEntry<TopologyEvent>(EventEntry.Type.ENTRY_ADD,
1159 topologyEvent);
1160 collection.add(eventEntry);
Yuta HIGUCHIa536e762014-02-17 21:47:28 -08001161 }
1162
Pavlin Radoslavov018d5332014-02-19 23:08:35 -08001163 // Add all active ports
Yuta HIGUCHI66ca1bf2014-03-12 18:34:09 -07001164 for (KVPort p : KVPort.getAllPorts()) {
1165 if (p.getStatus() != KVPort.STATUS.ACTIVE) {
Pavlin Radoslavovc1cfde52014-02-19 11:35:29 -08001166 continue;
Yuta HIGUCHIa536e762014-02-17 21:47:28 -08001167 }
Pavlin Radoslavov018d5332014-02-19 23:08:35 -08001168
1169 PortEvent portEvent = new PortEvent(p.getDpid(), p.getNumber());
1170 TopologyEvent topologyEvent = new TopologyEvent(portEvent);
1171 EventEntry<TopologyEvent> eventEntry =
1172 new EventEntry<TopologyEvent>(EventEntry.Type.ENTRY_ADD,
1173 topologyEvent);
1174 collection.add(eventEntry);
Yuta HIGUCHIa536e762014-02-17 21:47:28 -08001175 }
1176
Pavlin Radoslavovc1cfde52014-02-19 11:35:29 -08001177 // TODO Is Device going to be in DB? If so, read from DB.
Yuta HIGUCHI66ca1bf2014-03-12 18:34:09 -07001178 // for (KVDevice d : KVDevice.getAllDevices()) {
Pavlin Radoslavovc1cfde52014-02-19 11:35:29 -08001179 // DeviceEvent devEvent = new DeviceEvent( MACAddress.valueOf(d.getMac()) );
1180 // for (byte[] portId : d.getAllPortIds() ) {
Yuta HIGUCHI66ca1bf2014-03-12 18:34:09 -07001181 // devEvent.addAttachmentPoint( new SwitchPort( KVPort.getDpidFromKey(portId), KVPort.getNumberFromKey(portId) ));
Pavlin Radoslavovc1cfde52014-02-19 11:35:29 -08001182 // }
1183 // }
1184
Yuta HIGUCHI66ca1bf2014-03-12 18:34:09 -07001185 for (KVLink l : KVLink.getAllLinks()) {
Pavlin Radoslavov018d5332014-02-19 23:08:35 -08001186 LinkEvent linkEvent = new LinkEvent(l.getSrc().dpid,
1187 l.getSrc().number,
1188 l.getDst().dpid,
1189 l.getDst().number);
1190 TopologyEvent topologyEvent = new TopologyEvent(linkEvent);
1191 EventEntry<TopologyEvent> eventEntry =
1192 new EventEntry<TopologyEvent>(EventEntry.Type.ENTRY_ADD,
1193 topologyEvent);
1194 collection.add(eventEntry);
Yuta HIGUCHI76df2472014-02-12 22:36:51 -08001195 }
Pavlin Radoslavov018d5332014-02-19 23:08:35 -08001196
1197 return collection;
Pavlin Radoslavovc1cfde52014-02-19 11:35:29 -08001198 }
Jonathan Hart062a2e82014-02-03 09:41:57 -08001199}