blob: aa1147e0df3d2ed14f6341a76d49ac800f7202f5 [file] [log] [blame]
Jonathan Hart062a2e82014-02-03 09:41:57 -08001package net.onrc.onos.ofcontroller.networkgraph;
2
Yuta HIGUCHI1c700102014-02-12 16:30:52 -08003import java.net.InetAddress;
Pavlin Radoslavov018d5332014-02-19 23:08:35 -08004import java.nio.ByteBuffer;
Yuta HIGUCHI8d762e92014-02-12 14:10:25 -08005import java.util.ArrayList;
Pavlin Radoslavov721a2e02014-02-14 23:40:14 -08006import java.util.Collection;
Pavlin Radoslavov018d5332014-02-19 23:08:35 -08007import java.util.HashMap;
Yuta HIGUCHI8d762e92014-02-12 14:10:25 -08008import java.util.HashSet;
Pavlin Radoslavov721a2e02014-02-14 23:40:14 -08009import java.util.LinkedList;
Yuta HIGUCHI8d762e92014-02-12 14:10:25 -080010import java.util.List;
Pavlin Radoslavov018d5332014-02-19 23:08:35 -080011import java.util.Map;
Yuta HIGUCHI8d762e92014-02-12 14:10:25 -080012import java.util.Set;
Pavlin Radoslavov721a2e02014-02-14 23:40:14 -080013import java.util.concurrent.BlockingQueue;
Yuta HIGUCHIa536e762014-02-17 21:47:28 -080014import java.util.concurrent.CopyOnWriteArrayList;
Pavlin Radoslavov721a2e02014-02-14 23:40:14 -080015import java.util.concurrent.LinkedBlockingQueue;
Yuta HIGUCHI8d762e92014-02-12 14:10:25 -080016
Pavlin Radoslavov721a2e02014-02-14 23:40:14 -080017import net.onrc.onos.datagrid.IDatagridService;
18import net.onrc.onos.datagrid.IEventChannel;
19import net.onrc.onos.datagrid.IEventChannelListener;
Yuta HIGUCHI765cd0d2014-02-06 12:46:41 -080020import net.onrc.onos.datastore.topology.RCLink;
Jonathan Hart062a2e82014-02-03 09:41:57 -080021import net.onrc.onos.datastore.topology.RCPort;
22import net.onrc.onos.datastore.topology.RCSwitch;
Yuta HIGUCHI8d762e92014-02-12 14:10:25 -080023import net.onrc.onos.ofcontroller.networkgraph.PortEvent.SwitchPort;
Pavlin Radoslavov721a2e02014-02-14 23:40:14 -080024import net.onrc.onos.ofcontroller.util.EventEntry;
Yuta 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) {
216 ByteBuffer id = ByteBuffer.wrap(switchEvent.getID());
217 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) {
222 ByteBuffer id = ByteBuffer.wrap(portEvent.getID());
223 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) {
228 ByteBuffer id = ByteBuffer.wrap(linkEvent.getID());
229 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) {
234 ByteBuffer id = ByteBuffer.wrap(deviceEvent.getID());
235 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) {
243 ByteBuffer id = ByteBuffer.wrap(switchEvent.getID());
244 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) {
249 ByteBuffer id = ByteBuffer.wrap(portEvent.getID());
250 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) {
255 ByteBuffer id = ByteBuffer.wrap(linkEvent.getID());
256 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) {
261 ByteBuffer id = ByteBuffer.wrap(deviceEvent.getID());
262 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
Jonathan Hart22eb9882014-02-11 15:52:59 -0800483 /* ******************************
484 * NetworkGraphDiscoveryInterface methods
485 * ******************************/
Yuta HIGUCHIcd922f42014-02-11 18:59:11 -0800486
Pavlin Radoslavovc1cfde52014-02-19 11:35:29 -0800487 @Override
Pavlin Radoslavov018d5332014-02-19 23:08:35 -0800488 public void putSwitchDiscoveryEvent(SwitchEvent switchEvent,
489 Collection<PortEvent> portEvents) {
490 if (datastore.addSwitch(switchEvent, portEvents)) {
Pavlin Radoslavovc1cfde52014-02-19 11:35:29 -0800491 // Send out notification
Pavlin Radoslavov87dcc262014-02-19 21:13:23 -0800492 TopologyEvent topologyEvent = new TopologyEvent(switchEvent);
Pavlin Radoslavovc1cfde52014-02-19 11:35:29 -0800493 eventChannel.addEntry(topologyEvent.getID(), topologyEvent);
Pavlin Radoslavov018d5332014-02-19 23:08:35 -0800494
Pavlin Radoslavov26d83402014-02-20 15:24:30 -0800495 // Send out notification for each port
Pavlin Radoslavov018d5332014-02-19 23:08:35 -0800496 for (PortEvent portEvent : portEvents) {
497 topologyEvent = new TopologyEvent(portEvent);
498 eventChannel.addEntry(topologyEvent.getID(), topologyEvent);
499 }
Pavlin Radoslavov26d83402014-02-20 15:24:30 -0800500
501 //
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<>();
509
510 // Store the new Port Events in the local cache
511 Map<ByteBuffer, PortEvent> newPortEvents = new HashMap<>();
512 for (PortEvent portEvent : portEvents) {
513 ByteBuffer id = ByteBuffer.wrap(portEvent.getID());
514 newPortEvents.put(id, portEvent);
515 }
516 discoveredAddedPortEvents.put(switchEvent.getDpid(),
517 newPortEvents);
518
519 //
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);
Pavlin Radoslavovc1cfde52014-02-19 11:35:29 -0800533 }
Pavlin Radoslavovc1cfde52014-02-19 11:35:29 -0800534 }
535
536 @Override
Pavlin Radoslavov6ea84a42014-02-19 15:50:01 -0800537 public void removeSwitchDiscoveryEvent(SwitchEvent switchEvent) {
Pavlin Radoslavov26d83402014-02-20 15:24:30 -0800538 // Get the old Port Events
539 Map<ByteBuffer, PortEvent> oldPortEvents =
540 discoveredAddedPortEvents.get(switchEvent.getDpid());
541 if (oldPortEvents == null)
542 oldPortEvents = new HashMap<>();
Pavlin Radoslavov018d5332014-02-19 23:08:35 -0800543
Pavlin Radoslavov26d83402014-02-20 15:24:30 -0800544 if (datastore.deactivateSwitch(switchEvent, oldPortEvents.values())) {
Pavlin Radoslavovc1cfde52014-02-19 11:35:29 -0800545 // Send out notification
546 eventChannel.removeEntry(switchEvent.getID());
Pavlin Radoslavov018d5332014-02-19 23:08:35 -0800547
Pavlin Radoslavov26d83402014-02-20 15:24:30 -0800548 // Send out notification for each port
549 for (PortEvent portEvent : oldPortEvents.values())
Pavlin Radoslavov018d5332014-02-19 23:08:35 -0800550 eventChannel.removeEntry(portEvent.getID());
Pavlin Radoslavov26d83402014-02-20 15:24:30 -0800551 discoveredAddedPortEvents.remove(switchEvent.getDpid());
552
553 // Cleanup for each link
554 Map<ByteBuffer, LinkEvent> oldLinkEvents =
555 discoveredAddedLinkEvents.get(switchEvent.getDpid());
556 if (oldLinkEvents != null) {
557 for (LinkEvent linkEvent : oldLinkEvents.values())
558 removeLinkDiscoveryEvent(linkEvent);
559 discoveredAddedLinkEvents.remove(switchEvent.getDpid());
560 }
561
562 // Cleanup for each device
563 Map<ByteBuffer, DeviceEvent> oldDeviceEvents =
564 discoveredAddedDeviceEvents.get(switchEvent.getDpid());
565 if (oldDeviceEvents != null) {
566 for (DeviceEvent deviceEvent : oldDeviceEvents.values())
567 removeDeviceDiscoveryEvent(deviceEvent);
568 discoveredAddedDeviceEvents.remove(switchEvent.getDpid());
Pavlin Radoslavov018d5332014-02-19 23:08:35 -0800569 }
Pavlin Radoslavovc1cfde52014-02-19 11:35:29 -0800570 }
Pavlin Radoslavovc1cfde52014-02-19 11:35:29 -0800571 }
572
573 @Override
Pavlin Radoslavov6ea84a42014-02-19 15:50:01 -0800574 public void putPortDiscoveryEvent(PortEvent portEvent) {
Pavlin Radoslavov50cd1482014-02-19 16:57:03 -0800575 if (datastore.addPort(portEvent)) {
Pavlin Radoslavovc1cfde52014-02-19 11:35:29 -0800576 // Send out notification
Pavlin Radoslavov87dcc262014-02-19 21:13:23 -0800577 TopologyEvent topologyEvent = new TopologyEvent(portEvent);
Pavlin Radoslavov018d5332014-02-19 23:08:35 -0800578 eventChannel.addEntry(topologyEvent.getID(), topologyEvent);
Pavlin Radoslavov26d83402014-02-20 15:24:30 -0800579
580 // Store the new Port Event in the local cache
581 Map<ByteBuffer, PortEvent> oldPortEvents =
582 discoveredAddedPortEvents.get(portEvent.getDpid());
583 if (oldPortEvents == null) {
584 oldPortEvents = new HashMap<>();
585 discoveredAddedPortEvents.put(portEvent.getDpid(),
586 oldPortEvents);
587 }
588 ByteBuffer id = ByteBuffer.wrap(portEvent.getID());
589 oldPortEvents.put(id, portEvent);
Pavlin Radoslavovc1cfde52014-02-19 11:35:29 -0800590 }
Pavlin Radoslavovc1cfde52014-02-19 11:35:29 -0800591 }
592
593 @Override
Pavlin Radoslavov6ea84a42014-02-19 15:50:01 -0800594 public void removePortDiscoveryEvent(PortEvent portEvent) {
Pavlin Radoslavov50cd1482014-02-19 16:57:03 -0800595 if (datastore.deactivatePort(portEvent)) {
Pavlin Radoslavovc1cfde52014-02-19 11:35:29 -0800596 // Send out notification
597 eventChannel.removeEntry(portEvent.getID());
Pavlin Radoslavov26d83402014-02-20 15:24:30 -0800598
599 // Cleanup the Port Event from the local cache
600 Map<ByteBuffer, PortEvent> oldPortEvents =
601 discoveredAddedPortEvents.get(portEvent.getDpid());
602 if (oldPortEvents != null) {
603 ByteBuffer id = ByteBuffer.wrap(portEvent.getID());
604 oldPortEvents.remove(id);
605 }
606
607 // Cleanup for the incoming link
608 Map<ByteBuffer, LinkEvent> oldLinkEvents =
609 discoveredAddedLinkEvents.get(portEvent.getDpid());
610 if (oldLinkEvents != null) {
611 for (LinkEvent linkEvent : oldLinkEvents.values()) {
612 if (linkEvent.getDst().equals(portEvent.id)) {
613 removeLinkDiscoveryEvent(linkEvent);
614 //
615 // NOTE: oldLinkEvents was modified by
616 // removeLinkDiscoveryEvent() and cannot be iterated
617 // anymore.
618 //
619 break;
620 }
621 }
622 }
623
624 // Cleanup for the connected devices
625 // TODO: The implementation below is probably wrong
626 List<DeviceEvent> removedDeviceEvents = new LinkedList<>();
627 Map<ByteBuffer, DeviceEvent> oldDeviceEvents =
628 discoveredAddedDeviceEvents.get(portEvent.getDpid());
629 if (oldDeviceEvents != null) {
630 for (DeviceEvent deviceEvent : oldDeviceEvents.values()) {
631 for (SwitchPort swp : deviceEvent.getAttachmentPoints()) {
632 if (swp.equals(portEvent.id)) {
633 removedDeviceEvents.add(deviceEvent);
634 break;
635 }
636 }
637 }
638 for (DeviceEvent deviceEvent : removedDeviceEvents)
639 removeDeviceDiscoveryEvent(deviceEvent);
640 }
Pavlin Radoslavovc1cfde52014-02-19 11:35:29 -0800641 }
Pavlin Radoslavovc1cfde52014-02-19 11:35:29 -0800642 }
643
644 @Override
Pavlin Radoslavov6ea84a42014-02-19 15:50:01 -0800645 public void putLinkDiscoveryEvent(LinkEvent linkEvent) {
Pavlin Radoslavov50cd1482014-02-19 16:57:03 -0800646 if (datastore.addLink(linkEvent)) {
Pavlin Radoslavovc1cfde52014-02-19 11:35:29 -0800647 // Send out notification
Pavlin Radoslavov87dcc262014-02-19 21:13:23 -0800648 TopologyEvent topologyEvent = new TopologyEvent(linkEvent);
Pavlin Radoslavovc1cfde52014-02-19 11:35:29 -0800649 eventChannel.addEntry(topologyEvent.getID(), topologyEvent);
Pavlin Radoslavov26d83402014-02-20 15:24:30 -0800650
651 // Store the new Link Event in the local cache
652 Map<ByteBuffer, LinkEvent> oldLinkEvents =
653 discoveredAddedLinkEvents.get(linkEvent.getDst().getDpid());
654 if (oldLinkEvents == null) {
655 oldLinkEvents = new HashMap<>();
656 discoveredAddedLinkEvents.put(linkEvent.getDst().getDpid(),
657 oldLinkEvents);
658 }
659 ByteBuffer id = ByteBuffer.wrap(linkEvent.getID());
660 oldLinkEvents.put(id, linkEvent);
Pavlin Radoslavovc1cfde52014-02-19 11:35:29 -0800661 }
Pavlin Radoslavovc1cfde52014-02-19 11:35:29 -0800662 }
663
664 @Override
Pavlin Radoslavov6ea84a42014-02-19 15:50:01 -0800665 public void removeLinkDiscoveryEvent(LinkEvent linkEvent) {
Pavlin Radoslavov50cd1482014-02-19 16:57:03 -0800666 if (datastore.removeLink(linkEvent)) {
Pavlin Radoslavovc1cfde52014-02-19 11:35:29 -0800667 // Send out notification
668 eventChannel.removeEntry(linkEvent.getID());
Pavlin Radoslavov26d83402014-02-20 15:24:30 -0800669
670 // Cleanup the Link Event from the local cache
671 Map<ByteBuffer, LinkEvent> oldLinkEvents =
672 discoveredAddedLinkEvents.get(linkEvent.getDst().getDpid());
673 if (oldLinkEvents != null) {
674 ByteBuffer id = ByteBuffer.wrap(linkEvent.getID());
675 oldLinkEvents.remove(id);
676 }
Jonathan Hart22eb9882014-02-11 15:52:59 -0800677 }
Pavlin Radoslavovc1cfde52014-02-19 11:35:29 -0800678 }
Jonathan Hart22eb9882014-02-11 15:52:59 -0800679
Pavlin Radoslavovc1cfde52014-02-19 11:35:29 -0800680 @Override
Pavlin Radoslavov6ea84a42014-02-19 15:50:01 -0800681 public void putDeviceDiscoveryEvent(DeviceEvent deviceEvent) {
Pavlin Radoslavov50cd1482014-02-19 16:57:03 -0800682 if (datastore.addDevice(deviceEvent)) {
Pavlin Radoslavovc1cfde52014-02-19 11:35:29 -0800683 // Send out notification
Pavlin Radoslavov87dcc262014-02-19 21:13:23 -0800684 TopologyEvent topologyEvent = new TopologyEvent(deviceEvent);
Pavlin Radoslavov50cd1482014-02-19 16:57:03 -0800685 eventChannel.addEntry(topologyEvent.getID(), topologyEvent);
Pavlin Radoslavov26d83402014-02-20 15:24:30 -0800686
687 // Store the new Device Event in the local cache
688 // TODO: The implementation below is probably wrong
689 for (SwitchPort swp : deviceEvent.getAttachmentPoints()) {
690 Map<ByteBuffer, DeviceEvent> oldDeviceEvents =
691 discoveredAddedDeviceEvents.get(swp.getDpid());
692 if (oldDeviceEvents == null) {
693 oldDeviceEvents = new HashMap<>();
694 discoveredAddedDeviceEvents.put(swp.getDpid(),
695 oldDeviceEvents);
696 }
697 ByteBuffer id = ByteBuffer.wrap(deviceEvent.getID());
698 oldDeviceEvents.put(id, deviceEvent);
699 }
Jonathan Hart22eb9882014-02-11 15:52:59 -0800700 }
Pavlin Radoslavovc1cfde52014-02-19 11:35:29 -0800701 }
Jonathan Hart22eb9882014-02-11 15:52:59 -0800702
Pavlin Radoslavovc1cfde52014-02-19 11:35:29 -0800703 @Override
Pavlin Radoslavov6ea84a42014-02-19 15:50:01 -0800704 public void removeDeviceDiscoveryEvent(DeviceEvent deviceEvent) {
Pavlin Radoslavov50cd1482014-02-19 16:57:03 -0800705 if (datastore.removeDevice(deviceEvent)) {
Pavlin Radoslavovc1cfde52014-02-19 11:35:29 -0800706 // Send out notification
707 eventChannel.removeEntry(deviceEvent.getID());
Pavlin Radoslavov26d83402014-02-20 15:24:30 -0800708
709 // Cleanup the Device Event from the local cache
710 // TODO: The implementation below is probably wrong
711 ByteBuffer id = ByteBuffer.wrap(deviceEvent.getID());
712 for (SwitchPort swp : deviceEvent.getAttachmentPoints()) {
713 Map<ByteBuffer, DeviceEvent> oldDeviceEvents =
714 discoveredAddedDeviceEvents.get(swp.getDpid());
715 if (oldDeviceEvents != null) {
716 oldDeviceEvents.remove(id);
717 }
718 }
Jonathan Hart22eb9882014-02-11 15:52:59 -0800719 }
Pavlin Radoslavovc1cfde52014-02-19 11:35:29 -0800720 }
Jonathan Hart22eb9882014-02-11 15:52:59 -0800721
Pavlin Radoslavov3c9cc552014-02-20 09:58:38 -0800722 /* ************************************************
723 * Internal methods to maintain the network graph
724 * ************************************************/
Pavlin Radoslavov74986ce2014-02-20 13:17:20 -0800725 private void addSwitch(SwitchEvent switchEvent) {
726 Switch sw = networkGraph.getSwitch(switchEvent.getDpid());
Pavlin Radoslavov3c9cc552014-02-20 09:58:38 -0800727 if (sw == null) {
Pavlin Radoslavov74986ce2014-02-20 13:17:20 -0800728 sw = new SwitchImpl(networkGraph, switchEvent.getDpid());
Pavlin Radoslavov3c9cc552014-02-20 09:58:38 -0800729 networkGraph.putSwitch(sw);
730 } else {
731 // TODO: Update the switch attributes
732 // TODO: Nothing to do for now
733 }
Pavlin Radoslavov74986ce2014-02-20 13:17:20 -0800734 apiAddedSwitchEvents.add(switchEvent);
Pavlin Radoslavov3c9cc552014-02-20 09:58:38 -0800735 }
736
Pavlin Radoslavov74986ce2014-02-20 13:17:20 -0800737 private void removeSwitch(SwitchEvent switchEvent) {
738 Switch sw = networkGraph.getSwitch(switchEvent.getDpid());
Pavlin Radoslavov3c9cc552014-02-20 09:58:38 -0800739 if (sw == null) {
Pavlin Radoslavov74986ce2014-02-20 13:17:20 -0800740 log.warn("Switch {} already removed, ignoring", switchEvent);
Pavlin Radoslavov3c9cc552014-02-20 09:58:38 -0800741 return;
742 }
743
744 //
745 // Remove all Ports on the Switch
746 //
747 ArrayList<PortEvent> portsToRemove = new ArrayList<>();
748 for (Port port : sw.getPorts()) {
749 log.warn("Port {} on Switch {} should be removed prior to removing Switch. Removing Port now.",
Pavlin Radoslavov74986ce2014-02-20 13:17:20 -0800750 port, switchEvent);
Pavlin Radoslavov3c9cc552014-02-20 09:58:38 -0800751 PortEvent portEvent = new PortEvent(port.getDpid(),
752 port.getNumber());
753 portsToRemove.add(portEvent);
754 }
755 for (PortEvent portEvent : portsToRemove)
756 removePort(portEvent);
757
Pavlin Radoslavov74986ce2014-02-20 13:17:20 -0800758 networkGraph.removeSwitch(switchEvent.getDpid());
759 apiRemovedSwitchEvents.add(switchEvent);
Pavlin Radoslavov3c9cc552014-02-20 09:58:38 -0800760 }
761
762 private void addPort(PortEvent portEvent) {
763 Switch sw = networkGraph.getSwitch(portEvent.getDpid());
764 if (sw == null) {
Pavlin Radoslavov706add22014-02-20 12:15:59 -0800765 // Reordered event: delay the event in local cache
766 ByteBuffer id = ByteBuffer.wrap(portEvent.getID());
767 reorderedAddedPortEvents.put(id, portEvent);
Pavlin Radoslavov3c9cc552014-02-20 09:58:38 -0800768 return;
769 }
770 SwitchImpl switchImpl = getSwitchImpl(sw);
771
772 Port port = sw.getPort(portEvent.getNumber());
773 if (port == null) {
774 port = new PortImpl(networkGraph, sw, portEvent.getNumber());
775 switchImpl.addPort(port);
776 } else {
777 // TODO: Update the port attributes
778 }
Pavlin Radoslavov74986ce2014-02-20 13:17:20 -0800779 apiAddedPortEvents.add(portEvent);
Pavlin Radoslavov3c9cc552014-02-20 09:58:38 -0800780 }
781
782 private void removePort(PortEvent portEvent) {
783 Switch sw = networkGraph.getSwitch(portEvent.getDpid());
784 if (sw == null) {
785 log.warn("Parent Switch for Port {} already removed, ignoring",
786 portEvent);
787 return;
788 }
789
790 Port port = sw.getPort(portEvent.getNumber());
791 if (port == null) {
792 log.warn("Port {} already removed, ignoring", portEvent);
793 return;
794 }
795
796 //
797 // Remove all Devices attached to the Port
798 //
799 ArrayList<DeviceEvent> devicesToRemove = new ArrayList<>();
800 for (Device device : port.getDevices()) {
801 log.debug("Removing Device {} on Port {}", device, portEvent);
802 DeviceEvent deviceEvent = new DeviceEvent(device.getMacAddress());
803 SwitchPort switchPort = new SwitchPort(port.getSwitch().getDpid(),
804 port.getNumber());
805 deviceEvent.addAttachmentPoint(switchPort);
806 devicesToRemove.add(deviceEvent);
807 }
808 for (DeviceEvent deviceEvent : devicesToRemove)
809 removeDevice(deviceEvent);
810
811 //
812 // Remove all Links connected to the Port
813 //
814 Set<Link> links = new HashSet<>();
815 links.add(port.getOutgoingLink());
816 links.add(port.getIncomingLink());
817 ArrayList<LinkEvent> linksToRemove = new ArrayList<>();
818 for (Link link : links) {
819 if (link == null)
820 continue;
821 log.debug("Removing Link {} on Port {}", link, portEvent);
822 LinkEvent linkEvent = new LinkEvent(link.getSrcSwitch().getDpid(),
823 link.getSrcPort().getNumber(),
824 link.getDstSwitch().getDpid(),
825 link.getDstPort().getNumber());
826 linksToRemove.add(linkEvent);
827 }
828 for (LinkEvent linkEvent : linksToRemove)
829 removeLink(linkEvent);
830
831 // Remove the Port from the Switch
832 SwitchImpl switchImpl = getSwitchImpl(sw);
833 switchImpl.removePort(port);
Pavlin Radoslavov74986ce2014-02-20 13:17:20 -0800834
835 apiRemovedPortEvents.add(portEvent);
Pavlin Radoslavov3c9cc552014-02-20 09:58:38 -0800836 }
837
838 private void addLink(LinkEvent linkEvent) {
839 Port srcPort = networkGraph.getPort(linkEvent.getSrc().dpid,
840 linkEvent.getSrc().number);
Pavlin Radoslavov3c9cc552014-02-20 09:58:38 -0800841 Port dstPort = networkGraph.getPort(linkEvent.getDst().dpid,
842 linkEvent.getDst().number);
Pavlin Radoslavov706add22014-02-20 12:15:59 -0800843 if ((srcPort == null) || (dstPort == null)) {
844 // Reordered event: delay the event in local cache
845 ByteBuffer id = ByteBuffer.wrap(linkEvent.getID());
846 reorderedAddedLinkEvents.put(id, linkEvent);
Pavlin Radoslavov3c9cc552014-02-20 09:58:38 -0800847 return;
848 }
849
850 // Get the Link instance from the Destination Port Incoming Link
851 Link link = dstPort.getIncomingLink();
852 assert(link == srcPort.getOutgoingLink());
853 if (link == null) {
854 link = new LinkImpl(networkGraph, srcPort, dstPort);
855 PortImpl srcPortImpl = getPortImpl(srcPort);
856 PortImpl dstPortImpl = getPortImpl(dstPort);
857 srcPortImpl.setOutgoingLink(link);
858 dstPortImpl.setIncomingLink(link);
859
860 // Remove all Devices attached to the Ports
861 ArrayList<DeviceEvent> devicesToRemove = new ArrayList<>();
862 ArrayList<Port> ports = new ArrayList<>();
863 ports.add(srcPort);
864 ports.add(dstPort);
865 for (Port port : ports) {
866 for (Device device : port.getDevices()) {
867 log.error("Device {} on Port {} should have been removed prior to adding Link {}",
868 device, port, linkEvent);
869 DeviceEvent deviceEvent =
870 new DeviceEvent(device.getMacAddress());
871 SwitchPort switchPort =
872 new SwitchPort(port.getSwitch().getDpid(),
873 port.getNumber());
874 deviceEvent.addAttachmentPoint(switchPort);
875 devicesToRemove.add(deviceEvent);
876 }
877 }
878 for (DeviceEvent deviceEvent : devicesToRemove)
879 removeDevice(deviceEvent);
880 } else {
881 // TODO: Update the link attributes
882 }
Pavlin Radoslavov74986ce2014-02-20 13:17:20 -0800883
884 apiAddedLinkEvents.add(linkEvent);
Pavlin Radoslavov3c9cc552014-02-20 09:58:38 -0800885 }
886
887 private void removeLink(LinkEvent linkEvent) {
888 Port srcPort = networkGraph.getPort(linkEvent.getSrc().dpid,
889 linkEvent.getSrc().number);
890 if (srcPort == null) {
891 log.warn("Src Port for Link {} already removed, ignoring",
892 linkEvent);
893 return;
894 }
895
896 Port dstPort = networkGraph.getPort(linkEvent.getDst().dpid,
897 linkEvent.getDst().number);
898 if (dstPort == null) {
899 log.warn("Dst Port for Link {} already removed, ignoring",
900 linkEvent);
901 return;
902 }
903
904 //
905 // Remove the Link instance from the Destination Port Incoming Link
906 // and the Source Port Outgoing Link.
907 //
908 Link link = dstPort.getIncomingLink();
909 if (link == null) {
910 log.warn("Link {} already removed on destination Port", linkEvent);
911 }
912 link = srcPort.getOutgoingLink();
913 if (link == null) {
914 log.warn("Link {} already removed on src Port", linkEvent);
915 }
916 getPortImpl(dstPort).setIncomingLink(null);
917 getPortImpl(srcPort).setOutgoingLink(null);
Pavlin Radoslavov74986ce2014-02-20 13:17:20 -0800918
919 apiRemovedLinkEvents.add(linkEvent);
Pavlin Radoslavov3c9cc552014-02-20 09:58:38 -0800920 }
921
922 // TODO: Device-related work is incomplete
923 private void addDevice(DeviceEvent deviceEvent) {
924 Device device = networkGraph.getDeviceByMac(deviceEvent.getMac());
925 if (device == null) {
926 device = new DeviceImpl(networkGraph, deviceEvent.getMac());
927 }
928 DeviceImpl deviceImpl = getDeviceImpl(device);
929
930 // Update the IP addresses
931 for (InetAddress ipAddr : deviceEvent.getIpAddresses())
932 deviceImpl.addIpAddress(ipAddr);
933
934 // Process each attachment point
935 boolean attachmentFound = false;
936 for (SwitchPort swp : deviceEvent.getAttachmentPoints()) {
937 // Attached Ports must exist
938 Port port = networkGraph.getPort(swp.dpid, swp.number);
939 if (port == null) {
Pavlin Radoslavov706add22014-02-20 12:15:59 -0800940 // Reordered event: delay the event in local cache
941 ByteBuffer id = ByteBuffer.wrap(deviceEvent.getID());
942 reorderedAddedDeviceEvents.put(id, deviceEvent);
Pavlin Radoslavov3c9cc552014-02-20 09:58:38 -0800943 continue;
944 }
945 // Attached Ports must not have Link
946 if (port.getOutgoingLink() != null ||
947 port.getIncomingLink() != null) {
948 log.warn("Link (Out:{},In:{}) exist on the attachment point, skipping mutation.",
949 port.getOutgoingLink(),
950 port.getIncomingLink());
951 continue;
952 }
953
954 // Add Device <-> Port attachment
955 PortImpl portImpl = getPortImpl(port);
956 portImpl.addDevice(device);
957 deviceImpl.addAttachmentPoint(port);
958 attachmentFound = true;
959 }
960
961 // Update the device in the Network Graph
Pavlin Radoslavov74986ce2014-02-20 13:17:20 -0800962 if (attachmentFound) {
Pavlin Radoslavov3c9cc552014-02-20 09:58:38 -0800963 networkGraph.putDevice(device);
Pavlin Radoslavov74986ce2014-02-20 13:17:20 -0800964 apiAddedDeviceEvents.add(deviceEvent);
965 }
Pavlin Radoslavov3c9cc552014-02-20 09:58:38 -0800966 }
967
968 private void removeDevice(DeviceEvent deviceEvent) {
969 Device device = networkGraph.getDeviceByMac(deviceEvent.getMac());
970 if (device == null) {
971 log.warn("Device {} already removed, ignoring", deviceEvent);
972 return;
973 }
974 DeviceImpl deviceImpl = getDeviceImpl(device);
975
976 // Process each attachment point
977 for (SwitchPort swp : deviceEvent.getAttachmentPoints()) {
978 // Attached Ports must exist
979 Port port = networkGraph.getPort(swp.dpid, swp.number);
980 if (port == null) {
981 log.warn("Port for the attachment point {} did not exist. skipping attachment point mutation", swp);
982 continue;
983 }
984
985 // Remove Device <-> Port attachment
986 PortImpl portImpl = getPortImpl(port);
987 portImpl.removeDevice(device);
988 deviceImpl.removeAttachmentPoint(port);
989 }
Pavlin Radoslavov74986ce2014-02-20 13:17:20 -0800990
Pavlin Radoslavov3c9cc552014-02-20 09:58:38 -0800991 networkGraph.removeDevice(device);
Pavlin Radoslavov74986ce2014-02-20 13:17:20 -0800992 apiRemovedDeviceEvents.add(deviceEvent);
Pavlin Radoslavov3c9cc552014-02-20 09:58:38 -0800993 }
Jonathan Hart22eb9882014-02-11 15:52:59 -0800994
Pavlin Radoslavovc1cfde52014-02-19 11:35:29 -0800995 /**
996 *
Pavlin Radoslavov74986ce2014-02-20 13:17:20 -0800997 * @param switchEvent
Pavlin Radoslavovc1cfde52014-02-19 11:35:29 -0800998 * @return true if ready to accept event.
999 */
Pavlin Radoslavov74986ce2014-02-20 13:17:20 -08001000 private boolean prepareForAddSwitchEvent(SwitchEvent switchEvent) {
Pavlin Radoslavovc1cfde52014-02-19 11:35:29 -08001001 // No show stopping precondition
Pavlin Radoslavovc1cfde52014-02-19 11:35:29 -08001002 return true;
1003 }
Jonathan Hart22eb9882014-02-11 15:52:59 -08001004
Pavlin Radoslavov74986ce2014-02-20 13:17:20 -08001005 private boolean prepareForRemoveSwitchEvent(SwitchEvent switchEvent) {
Pavlin Radoslavovc1cfde52014-02-19 11:35:29 -08001006 // No show stopping precondition
Pavlin Radoslavovc1cfde52014-02-19 11:35:29 -08001007 return true;
1008 }
Yuta HIGUCHI71e7a052014-02-17 22:14:15 -08001009
Pavlin Radoslavovc1cfde52014-02-19 11:35:29 -08001010 private boolean prepareForAddPortEvent(PortEvent portEvent) {
1011 // Parent Switch must exist
1012 if (networkGraph.getSwitch(portEvent.getDpid()) == null) {
1013 log.warn("Dropping add port event because switch doesn't exist: {}",
1014 portEvent);
1015 return false;
1016 }
1017 // Prep: None
1018 return true;
1019 }
1020
1021 private boolean prepareForRemovePortEvent(PortEvent portEvent) {
1022 Port port = networkGraph.getPort(portEvent.getDpid(),
1023 portEvent.getNumber());
1024 if (port == null) {
1025 log.debug("Port already removed? {}", portEvent);
1026 // let it pass
1027 return true;
Jonathan Hart22eb9882014-02-11 15:52:59 -08001028 }
Yuta HIGUCHIcd922f42014-02-11 18:59:11 -08001029
Pavlin Radoslavovc1cfde52014-02-19 11:35:29 -08001030 // Prep: Remove Link and Device Attachment
1031 ArrayList<DeviceEvent> deviceEvents = new ArrayList<>();
1032 for (Device device : port.getDevices()) {
1033 log.debug("Removing Device {} on Port {}", device, portEvent);
1034 DeviceEvent devEvent = new DeviceEvent(device.getMacAddress());
1035 devEvent.addAttachmentPoint(new SwitchPort(port.getSwitch().getDpid(),
1036 port.getNumber()));
1037 deviceEvents.add(devEvent);
1038 }
1039 for (DeviceEvent devEvent : deviceEvents) {
1040 // calling Discovery API to wipe from DB, etc.
Pavlin Radoslavov6ea84a42014-02-19 15:50:01 -08001041 removeDeviceDiscoveryEvent(devEvent);
Jonathan Hart22eb9882014-02-11 15:52:59 -08001042 }
Yuta HIGUCHIcd922f42014-02-11 18:59:11 -08001043
Pavlin Radoslavovc1cfde52014-02-19 11:35:29 -08001044 Set<Link> links = new HashSet<>();
1045 links.add(port.getOutgoingLink());
1046 links.add(port.getIncomingLink());
1047 for (Link link : links) {
1048 if (link == null) {
1049 continue;
1050 }
1051 log.debug("Removing Link {} on Port {}", link, portEvent);
1052 LinkEvent linkEvent =
Pavlin Radoslavov7c8f69a2014-02-19 19:01:45 -08001053 new LinkEvent(link.getSrcSwitch().getDpid(),
1054 link.getSrcPort().getNumber(),
1055 link.getDstSwitch().getDpid(),
1056 link.getDstPort().getNumber());
Pavlin Radoslavovc1cfde52014-02-19 11:35:29 -08001057 // calling Discovery API to wipe from DB, etc.
Yuta HIGUCHI8d762e92014-02-12 14:10:25 -08001058
Pavlin Radoslavovc1cfde52014-02-19 11:35:29 -08001059 // Call internal remove Link, which will check
1060 // ownership of DST dpid and modify DB only if it is the owner
Pavlin Radoslavov6ea84a42014-02-19 15:50:01 -08001061 removeLinkDiscoveryEvent(linkEvent, true);
Jonathan Hart22eb9882014-02-11 15:52:59 -08001062 }
Pavlin Radoslavovc1cfde52014-02-19 11:35:29 -08001063 return true;
1064 }
Yuta HIGUCHIcd922f42014-02-11 18:59:11 -08001065
Pavlin Radoslavovc1cfde52014-02-19 11:35:29 -08001066 private boolean prepareForAddLinkEvent(LinkEvent linkEvent) {
1067 // Src/Dst Port must exist
1068 Port srcPort = networkGraph.getPort(linkEvent.getSrc().dpid,
1069 linkEvent.getSrc().number);
1070 Port dstPort = networkGraph.getPort(linkEvent.getDst().dpid,
1071 linkEvent.getDst().number);
1072 if (srcPort == null || dstPort == null) {
Jonathan Hart0a4846e2014-02-18 11:03:40 -08001073 log.warn("Dropping add link event because port doesn't exist: {}",
Pavlin Radoslavovc1cfde52014-02-19 11:35:29 -08001074 linkEvent);
1075 return false;
Jonathan Hart22eb9882014-02-11 15:52:59 -08001076 }
Yuta HIGUCHIcd922f42014-02-11 18:59:11 -08001077
Pavlin Radoslavovc1cfde52014-02-19 11:35:29 -08001078 // Prep: remove Device attachment on both Ports
1079 ArrayList<DeviceEvent> deviceEvents = new ArrayList<>();
1080 for (Device device : srcPort.getDevices()) {
1081 DeviceEvent devEvent = new DeviceEvent(device.getMacAddress());
1082 devEvent.addAttachmentPoint(new SwitchPort(srcPort.getSwitch().getDpid(), srcPort.getNumber()));
1083 deviceEvents.add(devEvent);
1084 }
1085 for (Device device : dstPort.getDevices()) {
1086 DeviceEvent devEvent = new DeviceEvent(device.getMacAddress());
1087 devEvent.addAttachmentPoint(new SwitchPort(dstPort.getSwitch().getDpid(),
1088 dstPort.getNumber()));
1089 deviceEvents.add(devEvent);
1090 }
1091 for (DeviceEvent devEvent : deviceEvents) {
1092 // calling Discovery API to wipe from DB, etc.
Pavlin Radoslavov6ea84a42014-02-19 15:50:01 -08001093 removeDeviceDiscoveryEvent(devEvent);
Jonathan Hart22eb9882014-02-11 15:52:59 -08001094 }
Yuta HIGUCHIcd922f42014-02-11 18:59:11 -08001095
Pavlin Radoslavovc1cfde52014-02-19 11:35:29 -08001096 return true;
1097 }
Yuta HIGUCHId02e9282014-02-12 09:24:41 -08001098
Pavlin Radoslavovc1cfde52014-02-19 11:35:29 -08001099 private boolean prepareForRemoveLinkEvent(LinkEvent linkEvent) {
1100 // Src/Dst Port must exist
1101 Port srcPort = networkGraph.getPort(linkEvent.getSrc().dpid,
1102 linkEvent.getSrc().number);
1103 Port dstPort = networkGraph.getPort(linkEvent.getDst().dpid,
1104 linkEvent.getDst().number);
1105 if (srcPort == null || dstPort == null) {
1106 log.warn("Dropping remove link event because port doesn't exist {}", linkEvent);
1107 return false;
1108 }
Yuta HIGUCHI8d762e92014-02-12 14:10:25 -08001109
Pavlin Radoslavovc1cfde52014-02-19 11:35:29 -08001110 Link link = srcPort.getOutgoingLink();
1111
1112 // Link is already gone, or different Link exist in memory
1113 // XXX Check if we should reject or just accept these cases.
1114 // it should be harmless to remove the Link on event from DB anyways
1115 if (link == null ||
Pavlin Radoslavov7c8f69a2014-02-19 19:01:45 -08001116 !link.getDstPort().getNumber().equals(linkEvent.getDst().number)
1117 || !link.getDstSwitch().getDpid().equals(linkEvent.getDst().dpid)) {
Pavlin Radoslavovc1cfde52014-02-19 11:35:29 -08001118 log.warn("Dropping remove link event because link doesn't exist: {}", linkEvent);
1119 return false;
1120 }
1121 // Prep: None
1122 return true;
1123 }
1124
1125 /**
1126 *
1127 * @param deviceEvent Event will be modified to remove inapplicable attachemntPoints/ipAddress
1128 * @return false if this event should be dropped.
1129 */
1130 private boolean prepareForAddDeviceEvent(DeviceEvent deviceEvent) {
1131 boolean preconditionBroken = false;
1132 ArrayList<PortEvent.SwitchPort> failedSwitchPort = new ArrayList<>();
1133 for ( PortEvent.SwitchPort swp : deviceEvent.getAttachmentPoints() ) {
1134 // Attached Ports must exist
1135 Port port = networkGraph.getPort(swp.dpid, swp.number);
1136 if (port == null) {
1137 preconditionBroken = true;
1138 failedSwitchPort.add(swp);
1139 continue;
Yuta HIGUCHI8d762e92014-02-12 14:10:25 -08001140 }
Pavlin Radoslavovc1cfde52014-02-19 11:35:29 -08001141 // Attached Ports must not have Link
1142 if (port.getOutgoingLink() != null ||
1143 port.getIncomingLink() != null) {
1144 preconditionBroken = true;
1145 failedSwitchPort.add(swp);
1146 continue;
1147 }
1148 }
1149
1150 // Rewriting event to exclude failed attachmentPoint
1151 // XXX Assumption behind this is that inapplicable device event should
1152 // be dropped, not deferred. If we decide to defer Device event,
1153 // rewriting can become a problem
1154 List<SwitchPort> attachmentPoints = deviceEvent.getAttachmentPoints();
1155 attachmentPoints.removeAll(failedSwitchPort);
1156 deviceEvent.setAttachmentPoints(attachmentPoints);
1157
1158 if (deviceEvent.getAttachmentPoints().isEmpty() &&
1159 deviceEvent.getIpAddresses().isEmpty()) {
1160 // return false to represent: Nothing left to do for this event.
1161 // Caller should drop event
1162 return false;
1163 }
Yuta HIGUCHI8d762e92014-02-12 14:10:25 -08001164
1165 // Should we return false to tell caller that the event was trimmed?
1166 // if ( preconditionBroken ) {
1167 // return false;
1168 // }
1169
Pavlin Radoslavovc1cfde52014-02-19 11:35:29 -08001170 return true;
1171 }
1172
1173 private boolean prepareForRemoveDeviceEvent(DeviceEvent deviceEvent) {
1174 // No show stopping precondition?
1175 // Prep: none
1176 return true;
1177 }
1178
Pavlin Radoslavovc1cfde52014-02-19 11:35:29 -08001179 private SwitchImpl getSwitchImpl(Switch sw) {
1180 if (sw instanceof SwitchImpl) {
1181 return (SwitchImpl) sw;
1182 }
1183 throw new ClassCastException("SwitchImpl expected, but found: " + sw);
1184 }
1185
1186 private PortImpl getPortImpl(Port p) {
1187 if (p instanceof PortImpl) {
1188 return (PortImpl) p;
1189 }
1190 throw new ClassCastException("PortImpl expected, but found: " + p);
1191 }
1192
1193 private LinkImpl getLinkImpl(Link l) {
1194 if (l instanceof LinkImpl) {
1195 return (LinkImpl) l;
1196 }
1197 throw new ClassCastException("LinkImpl expected, but found: " + l);
1198 }
1199
1200 private DeviceImpl getDeviceImpl(Device d) {
1201 if (d instanceof DeviceImpl) {
1202 return (DeviceImpl) d;
1203 }
1204 throw new ClassCastException("DeviceImpl expected, but found: " + d);
1205 }
1206
1207 @Deprecated
Pavlin Radoslavov018d5332014-02-19 23:08:35 -08001208 private Collection<EventEntry<TopologyEvent>> readWholeTopologyFromDB() {
1209 Collection<EventEntry<TopologyEvent>> collection =
1210 new LinkedList<EventEntry<TopologyEvent>>();
1211
Pavlin Radoslavovc1cfde52014-02-19 11:35:29 -08001212 // XXX May need to clear whole topology first, depending on
1213 // how we initially subscribe to replication events
1214
Pavlin Radoslavov018d5332014-02-19 23:08:35 -08001215 // Add all active switches
Pavlin Radoslavovc1cfde52014-02-19 11:35:29 -08001216 for (RCSwitch sw : RCSwitch.getAllSwitches()) {
1217 if (sw.getStatus() != RCSwitch.STATUS.ACTIVE) {
1218 continue;
1219 }
Pavlin Radoslavov018d5332014-02-19 23:08:35 -08001220
1221 SwitchEvent switchEvent = new SwitchEvent(sw.getDpid());
1222 TopologyEvent topologyEvent = new TopologyEvent(switchEvent);
1223 EventEntry<TopologyEvent> eventEntry =
1224 new EventEntry<TopologyEvent>(EventEntry.Type.ENTRY_ADD,
1225 topologyEvent);
1226 collection.add(eventEntry);
Yuta HIGUCHIa536e762014-02-17 21:47:28 -08001227 }
1228
Pavlin Radoslavov018d5332014-02-19 23:08:35 -08001229 // Add all active ports
Pavlin Radoslavovc1cfde52014-02-19 11:35:29 -08001230 for (RCPort p : RCPort.getAllPorts()) {
1231 if (p.getStatus() != RCPort.STATUS.ACTIVE) {
1232 continue;
Yuta HIGUCHIa536e762014-02-17 21:47:28 -08001233 }
Pavlin Radoslavov018d5332014-02-19 23:08:35 -08001234
1235 PortEvent portEvent = new PortEvent(p.getDpid(), p.getNumber());
1236 TopologyEvent topologyEvent = new TopologyEvent(portEvent);
1237 EventEntry<TopologyEvent> eventEntry =
1238 new EventEntry<TopologyEvent>(EventEntry.Type.ENTRY_ADD,
1239 topologyEvent);
1240 collection.add(eventEntry);
Yuta HIGUCHIa536e762014-02-17 21:47:28 -08001241 }
1242
Pavlin Radoslavovc1cfde52014-02-19 11:35:29 -08001243 // TODO Is Device going to be in DB? If so, read from DB.
1244 // for (RCDevice d : RCDevice.getAllDevices()) {
1245 // DeviceEvent devEvent = new DeviceEvent( MACAddress.valueOf(d.getMac()) );
1246 // for (byte[] portId : d.getAllPortIds() ) {
1247 // devEvent.addAttachmentPoint( new SwitchPort( RCPort.getDpidFromKey(portId), RCPort.getNumberFromKey(portId) ));
1248 // }
1249 // }
1250
1251 for (RCLink l : RCLink.getAllLinks()) {
Pavlin Radoslavov018d5332014-02-19 23:08:35 -08001252 LinkEvent linkEvent = new LinkEvent(l.getSrc().dpid,
1253 l.getSrc().number,
1254 l.getDst().dpid,
1255 l.getDst().number);
1256 TopologyEvent topologyEvent = new TopologyEvent(linkEvent);
1257 EventEntry<TopologyEvent> eventEntry =
1258 new EventEntry<TopologyEvent>(EventEntry.Type.ENTRY_ADD,
1259 topologyEvent);
1260 collection.add(eventEntry);
Yuta HIGUCHI76df2472014-02-12 22:36:51 -08001261 }
Pavlin Radoslavov018d5332014-02-19 23:08:35 -08001262
1263 return collection;
Pavlin Radoslavovc1cfde52014-02-19 11:35:29 -08001264 }
Pavlin Radoslavov50cd1482014-02-19 16:57:03 -08001265
1266 @Deprecated
1267 private void removeLinkDiscoveryEvent(LinkEvent linkEvent,
1268 boolean dstCheckBeforeDBmodify) {
1269 if (prepareForRemoveLinkEvent(linkEvent)) {
1270 if (dstCheckBeforeDBmodify) {
1271 // write to DB only if it is owner of the dst dpid
1272 // XXX this will cause link remove events to be dropped
1273 // if the dst switch just disconnected
1274 if (registryService.hasControl(linkEvent.getDst().dpid)) {
1275 datastore.removeLink(linkEvent);
1276 }
1277 } else {
1278 datastore.removeLink(linkEvent);
1279 }
1280 removeLink(linkEvent);
1281 // Send out notification
1282 eventChannel.removeEntry(linkEvent.getID());
1283 }
1284 // TODO handle invariant violation
1285 }
Jonathan Hart062a2e82014-02-03 09:41:57 -08001286}