blob: 47022f1b07f043f7b8d3ed3ca28e9f55bd892636 [file] [log] [blame]
Jonathan Hart062a2e82014-02-03 09:41:57 -08001package net.onrc.onos.ofcontroller.networkgraph;
2
Yuta HIGUCHI1c700102014-02-12 16:30:52 -08003import java.net.InetAddress;
Pavlin Radoslavov018d5332014-02-19 23:08:35 -08004import java.nio.ByteBuffer;
Yuta HIGUCHI8d762e92014-02-12 14:10:25 -08005import java.util.ArrayList;
Pavlin Radoslavov721a2e02014-02-14 23:40:14 -08006import java.util.Collection;
Pavlin Radoslavov018d5332014-02-19 23:08:35 -08007import java.util.HashMap;
Yuta HIGUCHI8d762e92014-02-12 14:10:25 -08008import java.util.HashSet;
Pavlin Radoslavov721a2e02014-02-14 23:40:14 -08009import java.util.LinkedList;
Yuta HIGUCHI8d762e92014-02-12 14:10:25 -080010import java.util.List;
Pavlin Radoslavov018d5332014-02-19 23:08:35 -080011import java.util.Map;
Yuta HIGUCHI8d762e92014-02-12 14:10:25 -080012import java.util.Set;
Pavlin Radoslavov721a2e02014-02-14 23:40:14 -080013import java.util.concurrent.BlockingQueue;
Yuta HIGUCHIa536e762014-02-17 21:47:28 -080014import java.util.concurrent.CopyOnWriteArrayList;
Pavlin Radoslavov721a2e02014-02-14 23:40:14 -080015import java.util.concurrent.LinkedBlockingQueue;
Yuta HIGUCHI8d762e92014-02-12 14:10:25 -080016
Pavlin Radoslavov721a2e02014-02-14 23:40:14 -080017import net.onrc.onos.datagrid.IDatagridService;
18import net.onrc.onos.datagrid.IEventChannel;
19import net.onrc.onos.datagrid.IEventChannelListener;
Yuta HIGUCHI765cd0d2014-02-06 12:46:41 -080020import net.onrc.onos.datastore.topology.RCLink;
Jonathan Hart062a2e82014-02-03 09:41:57 -080021import net.onrc.onos.datastore.topology.RCPort;
22import net.onrc.onos.datastore.topology.RCSwitch;
Yuta HIGUCHI8d762e92014-02-12 14:10:25 -080023import net.onrc.onos.ofcontroller.networkgraph.PortEvent.SwitchPort;
Pavlin Radoslavov721a2e02014-02-14 23:40:14 -080024import net.onrc.onos.ofcontroller.util.EventEntry;
Yuta HIGUCHI765cd0d2014-02-06 12:46:41 -080025import net.onrc.onos.ofcontroller.util.Dpid;
Yuta HIGUCHI170229f2014-02-17 15:47:54 -080026import net.onrc.onos.registry.controller.IControllerRegistryService;
Jonathan Hart062a2e82014-02-03 09:41:57 -080027
28import org.slf4j.Logger;
29import org.slf4j.LoggerFactory;
30
Yuta HIGUCHI181d34d2014-02-05 15:05:46 -080031/**
32 * The "NB" read-only Network Map.
33 *
Yuta HIGUCHI4bfdd532014-02-07 13:47:36 -080034 * - Maintain Invariant/Relationships between Topology Objects.
35 *
Yuta HIGUCHI765cd0d2014-02-06 12:46:41 -080036 * TODO To be synchronized based on TopologyEvent Notification.
Yuta HIGUCHI181d34d2014-02-05 15:05:46 -080037 *
Yuta HIGUCHIcb951982014-02-11 13:31:44 -080038 * TODO TBD: Caller is expected to maintain parent/child calling order. Parent
Yuta HIGUCHI1c700102014-02-12 16:30:52 -080039 * Object must exist before adding sub component(Add Switch -> Port).
Yuta HIGUCHIcb951982014-02-11 13:31:44 -080040 *
Yuta HIGUCHI4bfdd532014-02-07 13:47:36 -080041 * TODO TBD: This class may delay the requested change to handle event
42 * re-ordering. e.g.) Link Add came in, but Switch was not there.
Yuta HIGUCHIcb951982014-02-11 13:31:44 -080043 *
Yuta HIGUCHI181d34d2014-02-05 15:05:46 -080044 */
Pavlin Radoslavov87dcc262014-02-19 21:13:23 -080045public class TopologyManager implements NetworkGraphDiscoveryInterface {
Jonathan Hart062a2e82014-02-03 09:41:57 -080046
Yuta HIGUCHI80829d12014-02-05 20:16:56 -080047 private static final Logger log = LoggerFactory
Pavlin Radoslavovdb7dbb22014-02-18 14:45:10 -080048 .getLogger(TopologyManager.class);
Yuta HIGUCHIcd922f42014-02-11 18:59:11 -080049
Pavlin Radoslavov721a2e02014-02-14 23:40:14 -080050 private IEventChannel<byte[], TopologyEvent> eventChannel;
51 private static final String EVENT_CHANNEL_NAME = "onos.topology";
52 private EventHandler eventHandler = new EventHandler();
53
Jonathan Hart22eb9882014-02-11 15:52:59 -080054 private final NetworkGraphDatastore datastore;
Pavlin Radoslavov6d224ee2014-02-18 16:43:15 -080055 private final NetworkGraphImpl networkGraph = new NetworkGraphImpl();
Yuta HIGUCHI170229f2014-02-17 15:47:54 -080056 private final IControllerRegistryService registryService;
Yuta HIGUCHIa536e762014-02-17 21:47:28 -080057 private CopyOnWriteArrayList<INetworkGraphListener> networkGraphListeners;
Yuta HIGUCHI181d34d2014-02-05 15:05:46 -080058
Pavlin Radoslavov706add22014-02-20 12:15:59 -080059 //
60 // Local state for keeping track of reordered events.
61 // NOTE: Switch Events are not affected by the event reordering.
62 //
63 private Map<ByteBuffer, PortEvent> reorderedAddedPortEvents =
Pavlin Radoslavov018d5332014-02-19 23:08:35 -080064 new HashMap<ByteBuffer, PortEvent>();
Pavlin Radoslavov706add22014-02-20 12:15:59 -080065 private Map<ByteBuffer, LinkEvent> reorderedAddedLinkEvents =
Pavlin Radoslavov018d5332014-02-19 23:08:35 -080066 new HashMap<ByteBuffer, LinkEvent>();
Pavlin Radoslavov706add22014-02-20 12:15:59 -080067 private Map<ByteBuffer, DeviceEvent> reorderedAddedDeviceEvents =
Pavlin Radoslavov018d5332014-02-19 23:08:35 -080068 new HashMap<ByteBuffer, DeviceEvent>();
69
Pavlin Radoslavov74986ce2014-02-20 13:17:20 -080070 //
71 // Local state for keeping track of the application event notifications
72 //
73 List<SwitchEvent> apiAddedSwitchEvents = new LinkedList<SwitchEvent>();
74 List<SwitchEvent> apiRemovedSwitchEvents = new LinkedList<SwitchEvent>();
75 List<PortEvent> apiAddedPortEvents = new LinkedList<PortEvent>();
76 List<PortEvent> apiRemovedPortEvents = new LinkedList<PortEvent>();
77 List<LinkEvent> apiAddedLinkEvents = new LinkedList<LinkEvent>();
78 List<LinkEvent> apiRemovedLinkEvents = new LinkedList<LinkEvent>();
79 List<DeviceEvent> apiAddedDeviceEvents = new LinkedList<DeviceEvent>();
80 List<DeviceEvent> apiRemovedDeviceEvents = new LinkedList<DeviceEvent>();
81
Pavlin Radoslavovc1cfde52014-02-19 11:35:29 -080082 /**
83 * Constructor.
84 *
85 * @param registryService the Registry Service to use.
86 * @param networkGraphListeners the collection of Network Graph Listeners
87 * to use.
88 */
89 public TopologyManager(IControllerRegistryService registryService,
90 CopyOnWriteArrayList<INetworkGraphListener> networkGraphListeners) {
Jonathan Hartdaea86f2014-02-19 15:28:42 -080091 datastore = new NetworkGraphDatastore();
Yuta HIGUCHI170229f2014-02-17 15:47:54 -080092 this.registryService = registryService;
Yuta HIGUCHIa536e762014-02-17 21:47:28 -080093 this.networkGraphListeners = networkGraphListeners;
Yuta HIGUCHI80829d12014-02-05 20:16:56 -080094 }
Yuta HIGUCHI181d34d2014-02-05 15:05:46 -080095
Pavlin Radoslavovc1cfde52014-02-19 11:35:29 -080096 /**
97 * Get the Network Graph.
98 *
99 * @return the Network Graph.
100 */
Pavlin Radoslavov6d224ee2014-02-18 16:43:15 -0800101 NetworkGraph getNetworkGraph() {
102 return networkGraph;
103 }
104
Yuta HIGUCHI4bfdd532014-02-07 13:47:36 -0800105 /**
Pavlin Radoslavov721a2e02014-02-14 23:40:14 -0800106 * Event handler class.
107 */
108 private class EventHandler extends Thread implements
109 IEventChannelListener<byte[], TopologyEvent> {
110 private BlockingQueue<EventEntry<TopologyEvent>> topologyEvents =
111 new LinkedBlockingQueue<EventEntry<TopologyEvent>>();
112
113 /**
114 * Startup processing.
115 */
116 private void startup() {
117 //
Pavlin Radoslavov018d5332014-02-19 23:08:35 -0800118 // TODO: Read all state from the database:
119 //
120 // Collection<EventEntry<TopologyEvent>> collection =
121 // readWholeTopologyFromDB();
122 //
Pavlin Radoslavov721a2e02014-02-14 23:40:14 -0800123 // For now, as a shortcut we read it from the datagrid
124 //
125 Collection<TopologyEvent> topologyEvents =
126 eventChannel.getAllEntries();
127 Collection<EventEntry<TopologyEvent>> collection =
128 new LinkedList<EventEntry<TopologyEvent>>();
129
130 for (TopologyEvent topologyEvent : topologyEvents) {
131 EventEntry<TopologyEvent> eventEntry =
132 new EventEntry<TopologyEvent>(EventEntry.Type.ENTRY_ADD,
133 topologyEvent);
134 collection.add(eventEntry);
135 }
136 processEvents(collection);
137 }
138
139 /**
140 * Run the thread.
141 */
Yuta HIGUCHI240bf072014-02-17 10:55:21 -0800142 @Override
Pavlin Radoslavov721a2e02014-02-14 23:40:14 -0800143 public void run() {
144 Collection<EventEntry<TopologyEvent>> collection =
145 new LinkedList<EventEntry<TopologyEvent>>();
146
Pavlin Radoslavovdb7dbb22014-02-18 14:45:10 -0800147 this.setName("TopologyManager.EventHandler " + this.getId());
Pavlin Radoslavov721a2e02014-02-14 23:40:14 -0800148 startup();
149
150 //
151 // The main loop
152 //
153 try {
154 while (true) {
155 EventEntry<TopologyEvent> eventEntry = topologyEvents.take();
156 collection.add(eventEntry);
157 topologyEvents.drainTo(collection);
158
159 processEvents(collection);
160 collection.clear();
161 }
162 } catch (Exception exception) {
163 log.debug("Exception processing Topology Events: ", exception);
164 }
165 }
166
167 /**
168 * Process all topology events.
169 *
170 * @param events the events to process.
171 */
172 private void processEvents(Collection<EventEntry<TopologyEvent>> events) {
Pavlin Radoslavov706add22014-02-20 12:15:59 -0800173 // Local state for computing the final set of events
174 Map<ByteBuffer, SwitchEvent> addedSwitchEvents =
175 new HashMap<ByteBuffer, SwitchEvent>();
176 Map<ByteBuffer, SwitchEvent> removedSwitchEvents =
177 new HashMap<ByteBuffer, SwitchEvent>();
178 Map<ByteBuffer, PortEvent> addedPortEvents =
179 new HashMap<ByteBuffer, PortEvent>();
180 Map<ByteBuffer, PortEvent> removedPortEvents =
181 new HashMap<ByteBuffer, PortEvent>();
182 Map<ByteBuffer, LinkEvent> addedLinkEvents =
183 new HashMap<ByteBuffer, LinkEvent>();
184 Map<ByteBuffer, LinkEvent> removedLinkEvents =
185 new HashMap<ByteBuffer, LinkEvent>();
186 Map<ByteBuffer, DeviceEvent> addedDeviceEvents =
187 new HashMap<ByteBuffer, DeviceEvent>();
188 Map<ByteBuffer, DeviceEvent> removedDeviceEvents =
189 new HashMap<ByteBuffer, DeviceEvent>();
Pavlin Radoslavov3c9cc552014-02-20 09:58:38 -0800190
191 //
192 // Classify and suppress matching events
193 //
Pavlin Radoslavov721a2e02014-02-14 23:40:14 -0800194 for (EventEntry<TopologyEvent> event : events) {
195 TopologyEvent topologyEvent = event.eventData();
Pavlin Radoslavov018d5332014-02-19 23:08:35 -0800196 SwitchEvent switchEvent = topologyEvent.switchEvent;
197 PortEvent portEvent = topologyEvent.portEvent;
198 LinkEvent linkEvent = topologyEvent.linkEvent;
199 DeviceEvent deviceEvent = topologyEvent.deviceEvent;
200
201 //
Pavlin Radoslavov3c9cc552014-02-20 09:58:38 -0800202 // Extract the events
Pavlin Radoslavov018d5332014-02-19 23:08:35 -0800203 //
Pavlin Radoslavov721a2e02014-02-14 23:40:14 -0800204 switch (event.eventType()) {
205 case ENTRY_ADD:
206 log.debug("Topology event ENTRY_ADD: {}", topologyEvent);
Pavlin Radoslavov018d5332014-02-19 23:08:35 -0800207 if (switchEvent != null) {
208 ByteBuffer id = ByteBuffer.wrap(switchEvent.getID());
209 addedSwitchEvents.put(id, switchEvent);
210 removedSwitchEvents.remove(id);
Pavlin Radoslavov706add22014-02-20 12:15:59 -0800211 // Switch Events are not affected by event reordering
Pavlin Radoslavov018d5332014-02-19 23:08:35 -0800212 }
213 if (portEvent != null) {
214 ByteBuffer id = ByteBuffer.wrap(portEvent.getID());
215 addedPortEvents.put(id, portEvent);
216 removedPortEvents.remove(id);
Pavlin Radoslavov706add22014-02-20 12:15:59 -0800217 reorderedAddedPortEvents.remove(id);
Pavlin Radoslavov018d5332014-02-19 23:08:35 -0800218 }
219 if (linkEvent != null) {
220 ByteBuffer id = ByteBuffer.wrap(linkEvent.getID());
221 addedLinkEvents.put(id, linkEvent);
222 removedLinkEvents.remove(id);
Pavlin Radoslavov706add22014-02-20 12:15:59 -0800223 reorderedAddedLinkEvents.remove(id);
Pavlin Radoslavov018d5332014-02-19 23:08:35 -0800224 }
225 if (deviceEvent != null) {
226 ByteBuffer id = ByteBuffer.wrap(deviceEvent.getID());
227 addedDeviceEvents.put(id, deviceEvent);
228 removedDeviceEvents.remove(id);
Pavlin Radoslavov706add22014-02-20 12:15:59 -0800229 reorderedAddedDeviceEvents.remove(id);
Pavlin Radoslavov018d5332014-02-19 23:08:35 -0800230 }
Pavlin Radoslavov721a2e02014-02-14 23:40:14 -0800231 break;
232 case ENTRY_REMOVE:
233 log.debug("Topology event ENTRY_REMOVE: {}", topologyEvent);
Pavlin Radoslavov018d5332014-02-19 23:08:35 -0800234 if (switchEvent != null) {
235 ByteBuffer id = ByteBuffer.wrap(switchEvent.getID());
236 addedSwitchEvents.remove(id);
237 removedSwitchEvents.put(id, switchEvent);
Pavlin Radoslavov706add22014-02-20 12:15:59 -0800238 // Switch Events are not affected by event reordering
Pavlin Radoslavov018d5332014-02-19 23:08:35 -0800239 }
240 if (portEvent != null) {
241 ByteBuffer id = ByteBuffer.wrap(portEvent.getID());
242 addedPortEvents.remove(id);
243 removedPortEvents.put(id, portEvent);
Pavlin Radoslavov706add22014-02-20 12:15:59 -0800244 reorderedAddedPortEvents.remove(id);
Pavlin Radoslavov018d5332014-02-19 23:08:35 -0800245 }
246 if (linkEvent != null) {
247 ByteBuffer id = ByteBuffer.wrap(linkEvent.getID());
248 addedLinkEvents.remove(id);
249 removedLinkEvents.put(id, linkEvent);
Pavlin Radoslavov706add22014-02-20 12:15:59 -0800250 reorderedAddedLinkEvents.remove(id);
Pavlin Radoslavov018d5332014-02-19 23:08:35 -0800251 }
252 if (deviceEvent != null) {
253 ByteBuffer id = ByteBuffer.wrap(deviceEvent.getID());
254 addedDeviceEvents.remove(id);
255 removedDeviceEvents.put(id, deviceEvent);
Pavlin Radoslavov706add22014-02-20 12:15:59 -0800256 reorderedAddedDeviceEvents.remove(id);
Pavlin Radoslavov018d5332014-02-19 23:08:35 -0800257 }
Pavlin Radoslavov721a2e02014-02-14 23:40:14 -0800258 break;
259 }
260 }
Pavlin Radoslavov3c9cc552014-02-20 09:58:38 -0800261
262 //
263 // Apply the classified events.
264 //
265 // Apply the "add" events in the proper order:
266 // switch, port, link, device
267 //
268 for (SwitchEvent switchEvent : addedSwitchEvents.values())
269 addSwitch(switchEvent);
270 for (PortEvent portEvent : addedPortEvents.values())
271 addPort(portEvent);
272 for (LinkEvent linkEvent : addedLinkEvents.values())
273 addLink(linkEvent);
274 for (DeviceEvent deviceEvent : addedDeviceEvents.values())
275 addDevice(deviceEvent);
276 //
277 // Apply the "remove" events in the reverse order:
278 // device, link, port, switch
279 //
280 for (DeviceEvent deviceEvent : removedDeviceEvents.values())
281 removeDevice(deviceEvent);
282 for (LinkEvent linkEvent : removedLinkEvents.values())
283 removeLink(linkEvent);
284 for (PortEvent portEvent : removedPortEvents.values())
285 removePort(portEvent);
286 for (SwitchEvent switchEvent : removedSwitchEvents.values())
287 removeSwitch(switchEvent);
288
Pavlin Radoslavov3c9cc552014-02-20 09:58:38 -0800289 //
Pavlin Radoslavov74986ce2014-02-20 13:17:20 -0800290 // Apply reordered events
Pavlin Radoslavov3c9cc552014-02-20 09:58:38 -0800291 //
Pavlin Radoslavov74986ce2014-02-20 13:17:20 -0800292 applyReorderedEvents(! addedSwitchEvents.isEmpty(),
293 ! addedPortEvents.isEmpty());
294
Pavlin Radoslavov706add22014-02-20 12:15:59 -0800295 //
Pavlin Radoslavov74986ce2014-02-20 13:17:20 -0800296 // Dispatch the Topology Notification Events to the applications
297 //
298 dispatchNetworkGraphEvents();
Pavlin Radoslavov721a2e02014-02-14 23:40:14 -0800299 }
300
301 /**
302 * Receive a notification that an entry is added.
303 *
304 * @param value the value for the entry.
305 */
306 @Override
307 public void entryAdded(TopologyEvent value) {
308 EventEntry<TopologyEvent> eventEntry =
309 new EventEntry<TopologyEvent>(EventEntry.Type.ENTRY_ADD,
310 value);
311 topologyEvents.add(eventEntry);
312 }
313
314 /**
315 * Receive a notification that an entry is removed.
316 *
317 * @param value the value for the entry.
318 */
319 @Override
320 public void entryRemoved(TopologyEvent value) {
321 EventEntry<TopologyEvent> eventEntry =
322 new EventEntry<TopologyEvent>(EventEntry.Type.ENTRY_REMOVE,
323 value);
324 topologyEvents.add(eventEntry);
325 }
326
327 /**
328 * Receive a notification that an entry is updated.
329 *
330 * @param value the value for the entry.
331 */
332 @Override
333 public void entryUpdated(TopologyEvent value) {
334 // NOTE: The ADD and UPDATE events are processed in same way
335 entryAdded(value);
336 }
337 }
338
339 /**
340 * Startup processing.
341 *
342 * @param datagridService the datagrid service to use.
343 */
344 void startup(IDatagridService datagridService) {
345 eventChannel = datagridService.addListener(EVENT_CHANNEL_NAME,
346 eventHandler,
347 byte[].class,
348 TopologyEvent.class);
349 eventHandler.start();
350 }
351
Pavlin Radoslavov74986ce2014-02-20 13:17:20 -0800352 /**
353 * Dispatch Network Graph Events to the listeners.
354 */
355 private void dispatchNetworkGraphEvents() {
356 if (apiAddedSwitchEvents.isEmpty() &&
357 apiRemovedSwitchEvents.isEmpty() &&
358 apiAddedPortEvents.isEmpty() &&
359 apiRemovedPortEvents.isEmpty() &&
360 apiAddedLinkEvents.isEmpty() &&
361 apiRemovedLinkEvents.isEmpty() &&
362 apiAddedDeviceEvents.isEmpty() &&
363 apiRemovedDeviceEvents.isEmpty()) {
364 return; // No events to dispatch
365 }
366
367 // Deliver the events
368 for (INetworkGraphListener listener : this.networkGraphListeners) {
369 // TODO: Should copy before handing them over to listener?
370 listener.networkGraphEvents(apiAddedSwitchEvents,
371 apiRemovedSwitchEvents,
372 apiAddedPortEvents,
373 apiRemovedPortEvents,
374 apiAddedLinkEvents,
375 apiRemovedLinkEvents,
376 apiAddedDeviceEvents,
377 apiRemovedDeviceEvents);
378 }
379
380 //
381 // Cleanup
382 //
383 apiAddedSwitchEvents.clear();
384 apiRemovedSwitchEvents.clear();
385 apiAddedPortEvents.clear();
386 apiRemovedPortEvents.clear();
387 apiAddedLinkEvents.clear();
388 apiRemovedLinkEvents.clear();
389 apiAddedDeviceEvents.clear();
390 apiRemovedDeviceEvents.clear();
391 }
392
393 /**
394 * Apply reordered events.
395 *
396 * @param hasAddedSwitchEvents true if there were Added Switch Events.
397 * @param hasAddedPortEvents true if there were Added Port Events.
398 */
399 private void applyReorderedEvents(boolean hasAddedSwitchEvents,
400 boolean hasAddedPortEvents) {
401 if (! (hasAddedSwitchEvents || hasAddedPortEvents))
402 return; // Nothing to do
403
404 //
405 // Try to apply the reordered events.
406 //
407 // NOTE: For simplicity we try to apply all events of a particular
408 // type if any "parent" type event was processed:
409 // - Apply reordered Port Events if Switches were added
410 // - Apply reordered Link and Device Events if Switches or Ports
411 // were added
412 //
413 Map<ByteBuffer, PortEvent> portEvents = reorderedAddedPortEvents;
414 Map<ByteBuffer, LinkEvent> linkEvents = reorderedAddedLinkEvents;
415 Map<ByteBuffer, DeviceEvent> deviceEvents = reorderedAddedDeviceEvents;
416 reorderedAddedPortEvents = new HashMap<>();
417 reorderedAddedLinkEvents = new HashMap<>();
418 reorderedAddedDeviceEvents = new HashMap<>();
419 //
420 // Apply reordered Port Events if Switches were added
421 //
422 if (hasAddedSwitchEvents) {
423 for (PortEvent portEvent : portEvents.values())
424 addPort(portEvent);
425 }
426 //
427 // Apply reordered Link and Device Events if Switches or Ports
428 // were added.
429 //
430 for (LinkEvent linkEvent : linkEvents.values())
431 addLink(linkEvent);
432 for (DeviceEvent deviceEvent : deviceEvents.values())
433 addDevice(deviceEvent);
434 }
435
Jonathan Hart22eb9882014-02-11 15:52:59 -0800436 /* ******************************
437 * NetworkGraphDiscoveryInterface methods
438 * ******************************/
Yuta HIGUCHIcd922f42014-02-11 18:59:11 -0800439
Pavlin Radoslavovc1cfde52014-02-19 11:35:29 -0800440 @Override
Pavlin Radoslavov018d5332014-02-19 23:08:35 -0800441 public void putSwitchDiscoveryEvent(SwitchEvent switchEvent,
442 Collection<PortEvent> portEvents) {
443 if (datastore.addSwitch(switchEvent, portEvents)) {
Pavlin Radoslavovc1cfde52014-02-19 11:35:29 -0800444 // Send out notification
Pavlin Radoslavov87dcc262014-02-19 21:13:23 -0800445 TopologyEvent topologyEvent = new TopologyEvent(switchEvent);
Pavlin Radoslavovc1cfde52014-02-19 11:35:29 -0800446 eventChannel.addEntry(topologyEvent.getID(), topologyEvent);
Pavlin Radoslavov018d5332014-02-19 23:08:35 -0800447
448 for (PortEvent portEvent : portEvents) {
449 topologyEvent = new TopologyEvent(portEvent);
450 eventChannel.addEntry(topologyEvent.getID(), topologyEvent);
451 }
Pavlin Radoslavovc1cfde52014-02-19 11:35:29 -0800452 }
Pavlin Radoslavovc1cfde52014-02-19 11:35:29 -0800453 }
454
455 @Override
Pavlin Radoslavov6ea84a42014-02-19 15:50:01 -0800456 public void removeSwitchDiscoveryEvent(SwitchEvent switchEvent) {
Pavlin Radoslavov018d5332014-02-19 23:08:35 -0800457 // TODO: Use a copy of the port events previously added for that switch
458 Collection<PortEvent> portEvents = new LinkedList<PortEvent>();
459
460 if (datastore.deactivateSwitch(switchEvent, portEvents)) {
Pavlin Radoslavovc1cfde52014-02-19 11:35:29 -0800461 // Send out notification
462 eventChannel.removeEntry(switchEvent.getID());
Pavlin Radoslavov018d5332014-02-19 23:08:35 -0800463
464 for (PortEvent portEvent : portEvents) {
465 eventChannel.removeEntry(portEvent.getID());
466 }
Pavlin Radoslavovc1cfde52014-02-19 11:35:29 -0800467 }
Pavlin Radoslavovc1cfde52014-02-19 11:35:29 -0800468 }
469
470 @Override
Pavlin Radoslavov6ea84a42014-02-19 15:50:01 -0800471 public void putPortDiscoveryEvent(PortEvent portEvent) {
Pavlin Radoslavov50cd1482014-02-19 16:57:03 -0800472 if (datastore.addPort(portEvent)) {
Pavlin Radoslavovc1cfde52014-02-19 11:35:29 -0800473 // Send out notification
Pavlin Radoslavov87dcc262014-02-19 21:13:23 -0800474 TopologyEvent topologyEvent = new TopologyEvent(portEvent);
Pavlin Radoslavov018d5332014-02-19 23:08:35 -0800475 eventChannel.addEntry(topologyEvent.getID(), topologyEvent);
Pavlin Radoslavovc1cfde52014-02-19 11:35:29 -0800476 }
Pavlin Radoslavovc1cfde52014-02-19 11:35:29 -0800477 }
478
479 @Override
Pavlin Radoslavov6ea84a42014-02-19 15:50:01 -0800480 public void removePortDiscoveryEvent(PortEvent portEvent) {
Pavlin Radoslavov50cd1482014-02-19 16:57:03 -0800481 if (datastore.deactivatePort(portEvent)) {
Pavlin Radoslavovc1cfde52014-02-19 11:35:29 -0800482 // Send out notification
483 eventChannel.removeEntry(portEvent.getID());
484 }
Pavlin Radoslavovc1cfde52014-02-19 11:35:29 -0800485 }
486
487 @Override
Pavlin Radoslavov6ea84a42014-02-19 15:50:01 -0800488 public void putLinkDiscoveryEvent(LinkEvent linkEvent) {
Pavlin Radoslavov50cd1482014-02-19 16:57:03 -0800489 if (datastore.addLink(linkEvent)) {
Pavlin Radoslavovc1cfde52014-02-19 11:35:29 -0800490 // Send out notification
Pavlin Radoslavov87dcc262014-02-19 21:13:23 -0800491 TopologyEvent topologyEvent = new TopologyEvent(linkEvent);
Pavlin Radoslavovc1cfde52014-02-19 11:35:29 -0800492 eventChannel.addEntry(topologyEvent.getID(), topologyEvent);
493 }
Pavlin Radoslavovc1cfde52014-02-19 11:35:29 -0800494 }
495
496 @Override
Pavlin Radoslavov6ea84a42014-02-19 15:50:01 -0800497 public void removeLinkDiscoveryEvent(LinkEvent linkEvent) {
Pavlin Radoslavov50cd1482014-02-19 16:57:03 -0800498 if (datastore.removeLink(linkEvent)) {
Pavlin Radoslavovc1cfde52014-02-19 11:35:29 -0800499 // Send out notification
500 eventChannel.removeEntry(linkEvent.getID());
Jonathan Hart22eb9882014-02-11 15:52:59 -0800501 }
Pavlin Radoslavovc1cfde52014-02-19 11:35:29 -0800502 }
Jonathan Hart22eb9882014-02-11 15:52:59 -0800503
Pavlin Radoslavovc1cfde52014-02-19 11:35:29 -0800504 @Override
Pavlin Radoslavov6ea84a42014-02-19 15:50:01 -0800505 public void putDeviceDiscoveryEvent(DeviceEvent deviceEvent) {
Pavlin Radoslavov50cd1482014-02-19 16:57:03 -0800506 if (datastore.addDevice(deviceEvent)) {
Pavlin Radoslavovc1cfde52014-02-19 11:35:29 -0800507 // Send out notification
Pavlin Radoslavov87dcc262014-02-19 21:13:23 -0800508 TopologyEvent topologyEvent = new TopologyEvent(deviceEvent);
Pavlin Radoslavov50cd1482014-02-19 16:57:03 -0800509 eventChannel.addEntry(topologyEvent.getID(), topologyEvent);
Jonathan Hart22eb9882014-02-11 15:52:59 -0800510 }
Pavlin Radoslavovc1cfde52014-02-19 11:35:29 -0800511 }
Jonathan Hart22eb9882014-02-11 15:52:59 -0800512
Pavlin Radoslavovc1cfde52014-02-19 11:35:29 -0800513 @Override
Pavlin Radoslavov6ea84a42014-02-19 15:50:01 -0800514 public void removeDeviceDiscoveryEvent(DeviceEvent deviceEvent) {
Pavlin Radoslavov50cd1482014-02-19 16:57:03 -0800515 if (datastore.removeDevice(deviceEvent)) {
Pavlin Radoslavovc1cfde52014-02-19 11:35:29 -0800516 // Send out notification
517 eventChannel.removeEntry(deviceEvent.getID());
Jonathan Hart22eb9882014-02-11 15:52:59 -0800518 }
Pavlin Radoslavovc1cfde52014-02-19 11:35:29 -0800519 }
Jonathan Hart22eb9882014-02-11 15:52:59 -0800520
Pavlin Radoslavov3c9cc552014-02-20 09:58:38 -0800521 /* ************************************************
522 * Internal methods to maintain the network graph
523 * ************************************************/
Pavlin Radoslavov74986ce2014-02-20 13:17:20 -0800524 private void addSwitch(SwitchEvent switchEvent) {
525 Switch sw = networkGraph.getSwitch(switchEvent.getDpid());
Pavlin Radoslavov3c9cc552014-02-20 09:58:38 -0800526 if (sw == null) {
Pavlin Radoslavov74986ce2014-02-20 13:17:20 -0800527 sw = new SwitchImpl(networkGraph, switchEvent.getDpid());
Pavlin Radoslavov3c9cc552014-02-20 09:58:38 -0800528 networkGraph.putSwitch(sw);
529 } else {
530 // TODO: Update the switch attributes
531 // TODO: Nothing to do for now
532 }
Pavlin Radoslavov74986ce2014-02-20 13:17:20 -0800533 apiAddedSwitchEvents.add(switchEvent);
Pavlin Radoslavov3c9cc552014-02-20 09:58:38 -0800534 }
535
Pavlin Radoslavov74986ce2014-02-20 13:17:20 -0800536 private void removeSwitch(SwitchEvent switchEvent) {
537 Switch sw = networkGraph.getSwitch(switchEvent.getDpid());
Pavlin Radoslavov3c9cc552014-02-20 09:58:38 -0800538 if (sw == null) {
Pavlin Radoslavov74986ce2014-02-20 13:17:20 -0800539 log.warn("Switch {} already removed, ignoring", switchEvent);
Pavlin Radoslavov3c9cc552014-02-20 09:58:38 -0800540 return;
541 }
542
543 //
544 // Remove all Ports on the Switch
545 //
546 ArrayList<PortEvent> portsToRemove = new ArrayList<>();
547 for (Port port : sw.getPorts()) {
548 log.warn("Port {} on Switch {} should be removed prior to removing Switch. Removing Port now.",
Pavlin Radoslavov74986ce2014-02-20 13:17:20 -0800549 port, switchEvent);
Pavlin Radoslavov3c9cc552014-02-20 09:58:38 -0800550 PortEvent portEvent = new PortEvent(port.getDpid(),
551 port.getNumber());
552 portsToRemove.add(portEvent);
553 }
554 for (PortEvent portEvent : portsToRemove)
555 removePort(portEvent);
556
Pavlin Radoslavov74986ce2014-02-20 13:17:20 -0800557 networkGraph.removeSwitch(switchEvent.getDpid());
558 apiRemovedSwitchEvents.add(switchEvent);
Pavlin Radoslavov3c9cc552014-02-20 09:58:38 -0800559 }
560
561 private void addPort(PortEvent portEvent) {
562 Switch sw = networkGraph.getSwitch(portEvent.getDpid());
563 if (sw == null) {
Pavlin Radoslavov706add22014-02-20 12:15:59 -0800564 // Reordered event: delay the event in local cache
565 ByteBuffer id = ByteBuffer.wrap(portEvent.getID());
566 reorderedAddedPortEvents.put(id, portEvent);
Pavlin Radoslavov3c9cc552014-02-20 09:58:38 -0800567 return;
568 }
569 SwitchImpl switchImpl = getSwitchImpl(sw);
570
571 Port port = sw.getPort(portEvent.getNumber());
572 if (port == null) {
573 port = new PortImpl(networkGraph, sw, portEvent.getNumber());
574 switchImpl.addPort(port);
575 } else {
576 // TODO: Update the port attributes
577 }
Pavlin Radoslavov74986ce2014-02-20 13:17:20 -0800578 apiAddedPortEvents.add(portEvent);
Pavlin Radoslavov3c9cc552014-02-20 09:58:38 -0800579 }
580
581 private void removePort(PortEvent portEvent) {
582 Switch sw = networkGraph.getSwitch(portEvent.getDpid());
583 if (sw == null) {
584 log.warn("Parent Switch for Port {} already removed, ignoring",
585 portEvent);
586 return;
587 }
588
589 Port port = sw.getPort(portEvent.getNumber());
590 if (port == null) {
591 log.warn("Port {} already removed, ignoring", portEvent);
592 return;
593 }
594
595 //
596 // Remove all Devices attached to the Port
597 //
598 ArrayList<DeviceEvent> devicesToRemove = new ArrayList<>();
599 for (Device device : port.getDevices()) {
600 log.debug("Removing Device {} on Port {}", device, portEvent);
601 DeviceEvent deviceEvent = new DeviceEvent(device.getMacAddress());
602 SwitchPort switchPort = new SwitchPort(port.getSwitch().getDpid(),
603 port.getNumber());
604 deviceEvent.addAttachmentPoint(switchPort);
605 devicesToRemove.add(deviceEvent);
606 }
607 for (DeviceEvent deviceEvent : devicesToRemove)
608 removeDevice(deviceEvent);
609
610 //
611 // Remove all Links connected to the Port
612 //
613 Set<Link> links = new HashSet<>();
614 links.add(port.getOutgoingLink());
615 links.add(port.getIncomingLink());
616 ArrayList<LinkEvent> linksToRemove = new ArrayList<>();
617 for (Link link : links) {
618 if (link == null)
619 continue;
620 log.debug("Removing Link {} on Port {}", link, portEvent);
621 LinkEvent linkEvent = new LinkEvent(link.getSrcSwitch().getDpid(),
622 link.getSrcPort().getNumber(),
623 link.getDstSwitch().getDpid(),
624 link.getDstPort().getNumber());
625 linksToRemove.add(linkEvent);
626 }
627 for (LinkEvent linkEvent : linksToRemove)
628 removeLink(linkEvent);
629
630 // Remove the Port from the Switch
631 SwitchImpl switchImpl = getSwitchImpl(sw);
632 switchImpl.removePort(port);
Pavlin Radoslavov74986ce2014-02-20 13:17:20 -0800633
634 apiRemovedPortEvents.add(portEvent);
Pavlin Radoslavov3c9cc552014-02-20 09:58:38 -0800635 }
636
637 private void addLink(LinkEvent linkEvent) {
638 Port srcPort = networkGraph.getPort(linkEvent.getSrc().dpid,
639 linkEvent.getSrc().number);
Pavlin Radoslavov3c9cc552014-02-20 09:58:38 -0800640 Port dstPort = networkGraph.getPort(linkEvent.getDst().dpid,
641 linkEvent.getDst().number);
Pavlin Radoslavov706add22014-02-20 12:15:59 -0800642 if ((srcPort == null) || (dstPort == null)) {
643 // Reordered event: delay the event in local cache
644 ByteBuffer id = ByteBuffer.wrap(linkEvent.getID());
645 reorderedAddedLinkEvents.put(id, linkEvent);
Pavlin Radoslavov3c9cc552014-02-20 09:58:38 -0800646 return;
647 }
648
649 // Get the Link instance from the Destination Port Incoming Link
650 Link link = dstPort.getIncomingLink();
651 assert(link == srcPort.getOutgoingLink());
652 if (link == null) {
653 link = new LinkImpl(networkGraph, srcPort, dstPort);
654 PortImpl srcPortImpl = getPortImpl(srcPort);
655 PortImpl dstPortImpl = getPortImpl(dstPort);
656 srcPortImpl.setOutgoingLink(link);
657 dstPortImpl.setIncomingLink(link);
658
659 // Remove all Devices attached to the Ports
660 ArrayList<DeviceEvent> devicesToRemove = new ArrayList<>();
661 ArrayList<Port> ports = new ArrayList<>();
662 ports.add(srcPort);
663 ports.add(dstPort);
664 for (Port port : ports) {
665 for (Device device : port.getDevices()) {
666 log.error("Device {} on Port {} should have been removed prior to adding Link {}",
667 device, port, linkEvent);
668 DeviceEvent deviceEvent =
669 new DeviceEvent(device.getMacAddress());
670 SwitchPort switchPort =
671 new SwitchPort(port.getSwitch().getDpid(),
672 port.getNumber());
673 deviceEvent.addAttachmentPoint(switchPort);
674 devicesToRemove.add(deviceEvent);
675 }
676 }
677 for (DeviceEvent deviceEvent : devicesToRemove)
678 removeDevice(deviceEvent);
679 } else {
680 // TODO: Update the link attributes
681 }
Pavlin Radoslavov74986ce2014-02-20 13:17:20 -0800682
683 apiAddedLinkEvents.add(linkEvent);
Pavlin Radoslavov3c9cc552014-02-20 09:58:38 -0800684 }
685
686 private void removeLink(LinkEvent linkEvent) {
687 Port srcPort = networkGraph.getPort(linkEvent.getSrc().dpid,
688 linkEvent.getSrc().number);
689 if (srcPort == null) {
690 log.warn("Src Port for Link {} already removed, ignoring",
691 linkEvent);
692 return;
693 }
694
695 Port dstPort = networkGraph.getPort(linkEvent.getDst().dpid,
696 linkEvent.getDst().number);
697 if (dstPort == null) {
698 log.warn("Dst Port for Link {} already removed, ignoring",
699 linkEvent);
700 return;
701 }
702
703 //
704 // Remove the Link instance from the Destination Port Incoming Link
705 // and the Source Port Outgoing Link.
706 //
707 Link link = dstPort.getIncomingLink();
708 if (link == null) {
709 log.warn("Link {} already removed on destination Port", linkEvent);
710 }
711 link = srcPort.getOutgoingLink();
712 if (link == null) {
713 log.warn("Link {} already removed on src Port", linkEvent);
714 }
715 getPortImpl(dstPort).setIncomingLink(null);
716 getPortImpl(srcPort).setOutgoingLink(null);
Pavlin Radoslavov74986ce2014-02-20 13:17:20 -0800717
718 apiRemovedLinkEvents.add(linkEvent);
Pavlin Radoslavov3c9cc552014-02-20 09:58:38 -0800719 }
720
721 // TODO: Device-related work is incomplete
722 private void addDevice(DeviceEvent deviceEvent) {
723 Device device = networkGraph.getDeviceByMac(deviceEvent.getMac());
724 if (device == null) {
725 device = new DeviceImpl(networkGraph, deviceEvent.getMac());
726 }
727 DeviceImpl deviceImpl = getDeviceImpl(device);
728
729 // Update the IP addresses
730 for (InetAddress ipAddr : deviceEvent.getIpAddresses())
731 deviceImpl.addIpAddress(ipAddr);
732
733 // Process each attachment point
734 boolean attachmentFound = false;
735 for (SwitchPort swp : deviceEvent.getAttachmentPoints()) {
736 // Attached Ports must exist
737 Port port = networkGraph.getPort(swp.dpid, swp.number);
738 if (port == null) {
Pavlin Radoslavov706add22014-02-20 12:15:59 -0800739 // Reordered event: delay the event in local cache
740 ByteBuffer id = ByteBuffer.wrap(deviceEvent.getID());
741 reorderedAddedDeviceEvents.put(id, deviceEvent);
Pavlin Radoslavov3c9cc552014-02-20 09:58:38 -0800742 continue;
743 }
744 // Attached Ports must not have Link
745 if (port.getOutgoingLink() != null ||
746 port.getIncomingLink() != null) {
747 log.warn("Link (Out:{},In:{}) exist on the attachment point, skipping mutation.",
748 port.getOutgoingLink(),
749 port.getIncomingLink());
750 continue;
751 }
752
753 // Add Device <-> Port attachment
754 PortImpl portImpl = getPortImpl(port);
755 portImpl.addDevice(device);
756 deviceImpl.addAttachmentPoint(port);
757 attachmentFound = true;
758 }
759
760 // Update the device in the Network Graph
Pavlin Radoslavov74986ce2014-02-20 13:17:20 -0800761 if (attachmentFound) {
Pavlin Radoslavov3c9cc552014-02-20 09:58:38 -0800762 networkGraph.putDevice(device);
Pavlin Radoslavov74986ce2014-02-20 13:17:20 -0800763 apiAddedDeviceEvents.add(deviceEvent);
764 }
Pavlin Radoslavov3c9cc552014-02-20 09:58:38 -0800765 }
766
767 private void removeDevice(DeviceEvent deviceEvent) {
768 Device device = networkGraph.getDeviceByMac(deviceEvent.getMac());
769 if (device == null) {
770 log.warn("Device {} already removed, ignoring", deviceEvent);
771 return;
772 }
773 DeviceImpl deviceImpl = getDeviceImpl(device);
774
775 // Process each attachment point
776 for (SwitchPort swp : deviceEvent.getAttachmentPoints()) {
777 // Attached Ports must exist
778 Port port = networkGraph.getPort(swp.dpid, swp.number);
779 if (port == null) {
780 log.warn("Port for the attachment point {} did not exist. skipping attachment point mutation", swp);
781 continue;
782 }
783
784 // Remove Device <-> Port attachment
785 PortImpl portImpl = getPortImpl(port);
786 portImpl.removeDevice(device);
787 deviceImpl.removeAttachmentPoint(port);
788 }
Pavlin Radoslavov74986ce2014-02-20 13:17:20 -0800789
Pavlin Radoslavov3c9cc552014-02-20 09:58:38 -0800790 networkGraph.removeDevice(device);
Pavlin Radoslavov74986ce2014-02-20 13:17:20 -0800791 apiRemovedDeviceEvents.add(deviceEvent);
Pavlin Radoslavov3c9cc552014-02-20 09:58:38 -0800792 }
Jonathan Hart22eb9882014-02-11 15:52:59 -0800793
Pavlin Radoslavovc1cfde52014-02-19 11:35:29 -0800794 /**
795 *
Pavlin Radoslavov74986ce2014-02-20 13:17:20 -0800796 * @param switchEvent
Pavlin Radoslavovc1cfde52014-02-19 11:35:29 -0800797 * @return true if ready to accept event.
798 */
Pavlin Radoslavov74986ce2014-02-20 13:17:20 -0800799 private boolean prepareForAddSwitchEvent(SwitchEvent switchEvent) {
Pavlin Radoslavovc1cfde52014-02-19 11:35:29 -0800800 // No show stopping precondition
Pavlin Radoslavovc1cfde52014-02-19 11:35:29 -0800801 return true;
802 }
Jonathan Hart22eb9882014-02-11 15:52:59 -0800803
Pavlin Radoslavov74986ce2014-02-20 13:17:20 -0800804 private boolean prepareForRemoveSwitchEvent(SwitchEvent switchEvent) {
Pavlin Radoslavovc1cfde52014-02-19 11:35:29 -0800805 // No show stopping precondition
Pavlin Radoslavovc1cfde52014-02-19 11:35:29 -0800806 return true;
807 }
Yuta HIGUCHI71e7a052014-02-17 22:14:15 -0800808
Pavlin Radoslavovc1cfde52014-02-19 11:35:29 -0800809 private boolean prepareForAddPortEvent(PortEvent portEvent) {
810 // Parent Switch must exist
811 if (networkGraph.getSwitch(portEvent.getDpid()) == null) {
812 log.warn("Dropping add port event because switch doesn't exist: {}",
813 portEvent);
814 return false;
815 }
816 // Prep: None
817 return true;
818 }
819
820 private boolean prepareForRemovePortEvent(PortEvent portEvent) {
821 Port port = networkGraph.getPort(portEvent.getDpid(),
822 portEvent.getNumber());
823 if (port == null) {
824 log.debug("Port already removed? {}", portEvent);
825 // let it pass
826 return true;
Jonathan Hart22eb9882014-02-11 15:52:59 -0800827 }
Yuta HIGUCHIcd922f42014-02-11 18:59:11 -0800828
Pavlin Radoslavovc1cfde52014-02-19 11:35:29 -0800829 // Prep: Remove Link and Device Attachment
830 ArrayList<DeviceEvent> deviceEvents = new ArrayList<>();
831 for (Device device : port.getDevices()) {
832 log.debug("Removing Device {} on Port {}", device, portEvent);
833 DeviceEvent devEvent = new DeviceEvent(device.getMacAddress());
834 devEvent.addAttachmentPoint(new SwitchPort(port.getSwitch().getDpid(),
835 port.getNumber()));
836 deviceEvents.add(devEvent);
837 }
838 for (DeviceEvent devEvent : deviceEvents) {
839 // calling Discovery API to wipe from DB, etc.
Pavlin Radoslavov6ea84a42014-02-19 15:50:01 -0800840 removeDeviceDiscoveryEvent(devEvent);
Jonathan Hart22eb9882014-02-11 15:52:59 -0800841 }
Yuta HIGUCHIcd922f42014-02-11 18:59:11 -0800842
Pavlin Radoslavovc1cfde52014-02-19 11:35:29 -0800843 Set<Link> links = new HashSet<>();
844 links.add(port.getOutgoingLink());
845 links.add(port.getIncomingLink());
846 for (Link link : links) {
847 if (link == null) {
848 continue;
849 }
850 log.debug("Removing Link {} on Port {}", link, portEvent);
851 LinkEvent linkEvent =
Pavlin Radoslavov7c8f69a2014-02-19 19:01:45 -0800852 new LinkEvent(link.getSrcSwitch().getDpid(),
853 link.getSrcPort().getNumber(),
854 link.getDstSwitch().getDpid(),
855 link.getDstPort().getNumber());
Pavlin Radoslavovc1cfde52014-02-19 11:35:29 -0800856 // calling Discovery API to wipe from DB, etc.
Yuta HIGUCHI8d762e92014-02-12 14:10:25 -0800857
Pavlin Radoslavovc1cfde52014-02-19 11:35:29 -0800858 // Call internal remove Link, which will check
859 // ownership of DST dpid and modify DB only if it is the owner
Pavlin Radoslavov6ea84a42014-02-19 15:50:01 -0800860 removeLinkDiscoveryEvent(linkEvent, true);
Jonathan Hart22eb9882014-02-11 15:52:59 -0800861 }
Pavlin Radoslavovc1cfde52014-02-19 11:35:29 -0800862 return true;
863 }
Yuta HIGUCHIcd922f42014-02-11 18:59:11 -0800864
Pavlin Radoslavovc1cfde52014-02-19 11:35:29 -0800865 private boolean prepareForAddLinkEvent(LinkEvent linkEvent) {
866 // Src/Dst Port must exist
867 Port srcPort = networkGraph.getPort(linkEvent.getSrc().dpid,
868 linkEvent.getSrc().number);
869 Port dstPort = networkGraph.getPort(linkEvent.getDst().dpid,
870 linkEvent.getDst().number);
871 if (srcPort == null || dstPort == null) {
Jonathan Hart0a4846e2014-02-18 11:03:40 -0800872 log.warn("Dropping add link event because port doesn't exist: {}",
Pavlin Radoslavovc1cfde52014-02-19 11:35:29 -0800873 linkEvent);
874 return false;
Jonathan Hart22eb9882014-02-11 15:52:59 -0800875 }
Yuta HIGUCHIcd922f42014-02-11 18:59:11 -0800876
Pavlin Radoslavovc1cfde52014-02-19 11:35:29 -0800877 // Prep: remove Device attachment on both Ports
878 ArrayList<DeviceEvent> deviceEvents = new ArrayList<>();
879 for (Device device : srcPort.getDevices()) {
880 DeviceEvent devEvent = new DeviceEvent(device.getMacAddress());
881 devEvent.addAttachmentPoint(new SwitchPort(srcPort.getSwitch().getDpid(), srcPort.getNumber()));
882 deviceEvents.add(devEvent);
883 }
884 for (Device device : dstPort.getDevices()) {
885 DeviceEvent devEvent = new DeviceEvent(device.getMacAddress());
886 devEvent.addAttachmentPoint(new SwitchPort(dstPort.getSwitch().getDpid(),
887 dstPort.getNumber()));
888 deviceEvents.add(devEvent);
889 }
890 for (DeviceEvent devEvent : deviceEvents) {
891 // calling Discovery API to wipe from DB, etc.
Pavlin Radoslavov6ea84a42014-02-19 15:50:01 -0800892 removeDeviceDiscoveryEvent(devEvent);
Jonathan Hart22eb9882014-02-11 15:52:59 -0800893 }
Yuta HIGUCHIcd922f42014-02-11 18:59:11 -0800894
Pavlin Radoslavovc1cfde52014-02-19 11:35:29 -0800895 return true;
896 }
Yuta HIGUCHId02e9282014-02-12 09:24:41 -0800897
Pavlin Radoslavovc1cfde52014-02-19 11:35:29 -0800898 private boolean prepareForRemoveLinkEvent(LinkEvent linkEvent) {
899 // Src/Dst Port must exist
900 Port srcPort = networkGraph.getPort(linkEvent.getSrc().dpid,
901 linkEvent.getSrc().number);
902 Port dstPort = networkGraph.getPort(linkEvent.getDst().dpid,
903 linkEvent.getDst().number);
904 if (srcPort == null || dstPort == null) {
905 log.warn("Dropping remove link event because port doesn't exist {}", linkEvent);
906 return false;
907 }
Yuta HIGUCHI8d762e92014-02-12 14:10:25 -0800908
Pavlin Radoslavovc1cfde52014-02-19 11:35:29 -0800909 Link link = srcPort.getOutgoingLink();
910
911 // Link is already gone, or different Link exist in memory
912 // XXX Check if we should reject or just accept these cases.
913 // it should be harmless to remove the Link on event from DB anyways
914 if (link == null ||
Pavlin Radoslavov7c8f69a2014-02-19 19:01:45 -0800915 !link.getDstPort().getNumber().equals(linkEvent.getDst().number)
916 || !link.getDstSwitch().getDpid().equals(linkEvent.getDst().dpid)) {
Pavlin Radoslavovc1cfde52014-02-19 11:35:29 -0800917 log.warn("Dropping remove link event because link doesn't exist: {}", linkEvent);
918 return false;
919 }
920 // Prep: None
921 return true;
922 }
923
924 /**
925 *
926 * @param deviceEvent Event will be modified to remove inapplicable attachemntPoints/ipAddress
927 * @return false if this event should be dropped.
928 */
929 private boolean prepareForAddDeviceEvent(DeviceEvent deviceEvent) {
930 boolean preconditionBroken = false;
931 ArrayList<PortEvent.SwitchPort> failedSwitchPort = new ArrayList<>();
932 for ( PortEvent.SwitchPort swp : deviceEvent.getAttachmentPoints() ) {
933 // Attached Ports must exist
934 Port port = networkGraph.getPort(swp.dpid, swp.number);
935 if (port == null) {
936 preconditionBroken = true;
937 failedSwitchPort.add(swp);
938 continue;
Yuta HIGUCHI8d762e92014-02-12 14:10:25 -0800939 }
Pavlin Radoslavovc1cfde52014-02-19 11:35:29 -0800940 // Attached Ports must not have Link
941 if (port.getOutgoingLink() != null ||
942 port.getIncomingLink() != null) {
943 preconditionBroken = true;
944 failedSwitchPort.add(swp);
945 continue;
946 }
947 }
948
949 // Rewriting event to exclude failed attachmentPoint
950 // XXX Assumption behind this is that inapplicable device event should
951 // be dropped, not deferred. If we decide to defer Device event,
952 // rewriting can become a problem
953 List<SwitchPort> attachmentPoints = deviceEvent.getAttachmentPoints();
954 attachmentPoints.removeAll(failedSwitchPort);
955 deviceEvent.setAttachmentPoints(attachmentPoints);
956
957 if (deviceEvent.getAttachmentPoints().isEmpty() &&
958 deviceEvent.getIpAddresses().isEmpty()) {
959 // return false to represent: Nothing left to do for this event.
960 // Caller should drop event
961 return false;
962 }
Yuta HIGUCHI8d762e92014-02-12 14:10:25 -0800963
964 // Should we return false to tell caller that the event was trimmed?
965 // if ( preconditionBroken ) {
966 // return false;
967 // }
968
Pavlin Radoslavovc1cfde52014-02-19 11:35:29 -0800969 return true;
970 }
971
972 private boolean prepareForRemoveDeviceEvent(DeviceEvent deviceEvent) {
973 // No show stopping precondition?
974 // Prep: none
975 return true;
976 }
977
Pavlin Radoslavovc1cfde52014-02-19 11:35:29 -0800978 private SwitchImpl getSwitchImpl(Switch sw) {
979 if (sw instanceof SwitchImpl) {
980 return (SwitchImpl) sw;
981 }
982 throw new ClassCastException("SwitchImpl expected, but found: " + sw);
983 }
984
985 private PortImpl getPortImpl(Port p) {
986 if (p instanceof PortImpl) {
987 return (PortImpl) p;
988 }
989 throw new ClassCastException("PortImpl expected, but found: " + p);
990 }
991
992 private LinkImpl getLinkImpl(Link l) {
993 if (l instanceof LinkImpl) {
994 return (LinkImpl) l;
995 }
996 throw new ClassCastException("LinkImpl expected, but found: " + l);
997 }
998
999 private DeviceImpl getDeviceImpl(Device d) {
1000 if (d instanceof DeviceImpl) {
1001 return (DeviceImpl) d;
1002 }
1003 throw new ClassCastException("DeviceImpl expected, but found: " + d);
1004 }
1005
1006 @Deprecated
Pavlin Radoslavov018d5332014-02-19 23:08:35 -08001007 private Collection<EventEntry<TopologyEvent>> readWholeTopologyFromDB() {
1008 Collection<EventEntry<TopologyEvent>> collection =
1009 new LinkedList<EventEntry<TopologyEvent>>();
1010
Pavlin Radoslavovc1cfde52014-02-19 11:35:29 -08001011 // XXX May need to clear whole topology first, depending on
1012 // how we initially subscribe to replication events
1013
Pavlin Radoslavov018d5332014-02-19 23:08:35 -08001014 // Add all active switches
Pavlin Radoslavovc1cfde52014-02-19 11:35:29 -08001015 for (RCSwitch sw : RCSwitch.getAllSwitches()) {
1016 if (sw.getStatus() != RCSwitch.STATUS.ACTIVE) {
1017 continue;
1018 }
Pavlin Radoslavov018d5332014-02-19 23:08:35 -08001019
1020 SwitchEvent switchEvent = new SwitchEvent(sw.getDpid());
1021 TopologyEvent topologyEvent = new TopologyEvent(switchEvent);
1022 EventEntry<TopologyEvent> eventEntry =
1023 new EventEntry<TopologyEvent>(EventEntry.Type.ENTRY_ADD,
1024 topologyEvent);
1025 collection.add(eventEntry);
Yuta HIGUCHIa536e762014-02-17 21:47:28 -08001026 }
1027
Pavlin Radoslavov018d5332014-02-19 23:08:35 -08001028 // Add all active ports
Pavlin Radoslavovc1cfde52014-02-19 11:35:29 -08001029 for (RCPort p : RCPort.getAllPorts()) {
1030 if (p.getStatus() != RCPort.STATUS.ACTIVE) {
1031 continue;
Yuta HIGUCHIa536e762014-02-17 21:47:28 -08001032 }
Pavlin Radoslavov018d5332014-02-19 23:08:35 -08001033
1034 PortEvent portEvent = new PortEvent(p.getDpid(), p.getNumber());
1035 TopologyEvent topologyEvent = new TopologyEvent(portEvent);
1036 EventEntry<TopologyEvent> eventEntry =
1037 new EventEntry<TopologyEvent>(EventEntry.Type.ENTRY_ADD,
1038 topologyEvent);
1039 collection.add(eventEntry);
Yuta HIGUCHIa536e762014-02-17 21:47:28 -08001040 }
1041
Pavlin Radoslavovc1cfde52014-02-19 11:35:29 -08001042 // TODO Is Device going to be in DB? If so, read from DB.
1043 // for (RCDevice d : RCDevice.getAllDevices()) {
1044 // DeviceEvent devEvent = new DeviceEvent( MACAddress.valueOf(d.getMac()) );
1045 // for (byte[] portId : d.getAllPortIds() ) {
1046 // devEvent.addAttachmentPoint( new SwitchPort( RCPort.getDpidFromKey(portId), RCPort.getNumberFromKey(portId) ));
1047 // }
1048 // }
1049
1050 for (RCLink l : RCLink.getAllLinks()) {
1051 // check if src/dst switch/port exist before triggering event
1052 Port srcPort = networkGraph.getPort(l.getSrc().dpid,
1053 l.getSrc().number);
1054 Port dstPort = networkGraph.getPort(l.getDst().dpid,
1055 l.getDst().number);
1056 if (srcPort == null || dstPort == null) {
1057 continue;
Yuta HIGUCHI76df2472014-02-12 22:36:51 -08001058 }
Pavlin Radoslavov018d5332014-02-19 23:08:35 -08001059
1060 LinkEvent linkEvent = new LinkEvent(l.getSrc().dpid,
1061 l.getSrc().number,
1062 l.getDst().dpid,
1063 l.getDst().number);
1064 TopologyEvent topologyEvent = new TopologyEvent(linkEvent);
1065 EventEntry<TopologyEvent> eventEntry =
1066 new EventEntry<TopologyEvent>(EventEntry.Type.ENTRY_ADD,
1067 topologyEvent);
1068 collection.add(eventEntry);
Yuta HIGUCHI76df2472014-02-12 22:36:51 -08001069 }
Pavlin Radoslavov018d5332014-02-19 23:08:35 -08001070
1071 return collection;
Pavlin Radoslavovc1cfde52014-02-19 11:35:29 -08001072 }
Pavlin Radoslavov50cd1482014-02-19 16:57:03 -08001073
1074 @Deprecated
1075 private void removeLinkDiscoveryEvent(LinkEvent linkEvent,
1076 boolean dstCheckBeforeDBmodify) {
1077 if (prepareForRemoveLinkEvent(linkEvent)) {
1078 if (dstCheckBeforeDBmodify) {
1079 // write to DB only if it is owner of the dst dpid
1080 // XXX this will cause link remove events to be dropped
1081 // if the dst switch just disconnected
1082 if (registryService.hasControl(linkEvent.getDst().dpid)) {
1083 datastore.removeLink(linkEvent);
1084 }
1085 } else {
1086 datastore.removeLink(linkEvent);
1087 }
1088 removeLink(linkEvent);
1089 // Send out notification
1090 eventChannel.removeEntry(linkEvent.getID());
1091 }
1092 // TODO handle invariant violation
1093 }
Jonathan Hart062a2e82014-02-03 09:41:57 -08001094}