blob: b800d84fa2f0691b9df8b1ea68cea7dc17732113 [file] [log] [blame]
Jonathan Hart472062d2014-04-03 10:56:48 -07001package net.onrc.onos.core.topology;
Jonathan Hart062a2e82014-02-03 09:41:57 -08002
Pavlin Radoslavov018d5332014-02-19 23:08:35 -08003import java.nio.ByteBuffer;
Yuta HIGUCHI8d762e92014-02-12 14:10:25 -08004import java.util.ArrayList;
Pavlin Radoslavov721a2e02014-02-14 23:40:14 -08005import java.util.Collection;
Pavlin Radoslavov018d5332014-02-19 23:08:35 -08006import java.util.HashMap;
Yuta HIGUCHI8d762e92014-02-12 14:10:25 -08007import java.util.HashSet;
Pavlin Radoslavov721a2e02014-02-14 23:40:14 -08008import java.util.LinkedList;
Yuta HIGUCHI8d762e92014-02-12 14:10:25 -08009import java.util.List;
Pavlin Radoslavov018d5332014-02-19 23:08:35 -080010import java.util.Map;
Yuta HIGUCHI8d762e92014-02-12 14:10:25 -080011import java.util.Set;
Pavlin Radoslavov721a2e02014-02-14 23:40:14 -080012import java.util.concurrent.BlockingQueue;
Yuta HIGUCHIa536e762014-02-17 21:47:28 -080013import java.util.concurrent.CopyOnWriteArrayList;
Pavlin Radoslavov721a2e02014-02-14 23:40:14 -080014import java.util.concurrent.LinkedBlockingQueue;
Yuta HIGUCHI8d762e92014-02-12 14:10:25 -080015
Yuta HIGUCHIbc67a052014-06-30 10:37:09 -070016import javax.annotation.concurrent.GuardedBy;
17
TeruU28adcc32014-04-15 17:57:35 -070018import net.floodlightcontroller.util.MACAddress;
Jonathan Hart6df90172014-04-03 10:13:11 -070019import net.onrc.onos.core.datagrid.IDatagridService;
20import net.onrc.onos.core.datagrid.IEventChannel;
21import net.onrc.onos.core.datagrid.IEventChannelListener;
TeruU28adcc32014-04-15 17:57:35 -070022import net.onrc.onos.core.datastore.topology.KVDevice;
Jonathan Hart6df90172014-04-03 10:13:11 -070023import net.onrc.onos.core.datastore.topology.KVLink;
24import net.onrc.onos.core.datastore.topology.KVPort;
25import net.onrc.onos.core.datastore.topology.KVSwitch;
Jonathan Hartdeda0ba2014-04-03 11:14:12 -070026import net.onrc.onos.core.registry.IControllerRegistryService;
Jonathan Hart472062d2014-04-03 10:56:48 -070027import net.onrc.onos.core.topology.PortEvent.SwitchPort;
Yuta HIGUCHI8f3dfa32014-06-25 00:14:25 -070028import net.onrc.onos.core.util.Dpid;
Jonathan Hart23701d12014-04-03 10:45:48 -070029import net.onrc.onos.core.util.EventEntry;
Jonathan Hart062a2e82014-02-03 09:41:57 -080030import org.slf4j.Logger;
31import org.slf4j.LoggerFactory;
32
Yuta HIGUCHI181d34d2014-02-05 15:05:46 -080033/**
Jonathan Harte37e4e22014-05-13 19:12:02 -070034 * The TopologyManager receives topology updates from the southbound discovery
35 * modules and from other ONOS instances. These updates are processed and
36 * applied to the in-memory topology instance.
Ray Milkey269ffb92014-04-03 14:43:30 -070037 * <p/>
Yuta HIGUCHI4bfdd532014-02-07 13:47:36 -080038 * - Maintain Invariant/Relationships between Topology Objects.
Ray Milkey269ffb92014-04-03 14:43:30 -070039 * <p/>
Yuta HIGUCHI765cd0d2014-02-06 12:46:41 -080040 * TODO To be synchronized based on TopologyEvent Notification.
Ray Milkey269ffb92014-04-03 14:43:30 -070041 * <p/>
Yuta HIGUCHIcb951982014-02-11 13:31:44 -080042 * TODO TBD: Caller is expected to maintain parent/child calling order. Parent
Yuta HIGUCHI1c700102014-02-12 16:30:52 -080043 * Object must exist before adding sub component(Add Switch -> Port).
Ray Milkey269ffb92014-04-03 14:43:30 -070044 * <p/>
Yuta HIGUCHI4bfdd532014-02-07 13:47:36 -080045 * TODO TBD: This class may delay the requested change to handle event
46 * re-ordering. e.g.) Link Add came in, but Switch was not there.
Yuta HIGUCHI181d34d2014-02-05 15:05:46 -080047 */
Jonathan Harte37e4e22014-05-13 19:12:02 -070048public class TopologyManager implements TopologyDiscoveryInterface {
Jonathan Hart062a2e82014-02-03 09:41:57 -080049
Yuta HIGUCHI80829d12014-02-05 20:16:56 -080050 private static final Logger log = LoggerFactory
Ray Milkey269ffb92014-04-03 14:43:30 -070051 .getLogger(TopologyManager.class);
Yuta HIGUCHIcd922f42014-02-11 18:59:11 -080052
Pavlin Radoslavov721a2e02014-02-14 23:40:14 -080053 private IEventChannel<byte[], TopologyEvent> eventChannel;
Jonathan Hart10a7e2b2014-02-21 18:30:08 -080054 public static final String EVENT_CHANNEL_NAME = "onos.topology";
Pavlin Radoslavov721a2e02014-02-14 23:40:14 -080055 private EventHandler eventHandler = new EventHandler();
56
Jonathan Harte37e4e22014-05-13 19:12:02 -070057 private final TopologyDatastore datastore;
58 private final TopologyImpl topology = new TopologyImpl();
Yuta HIGUCHI170229f2014-02-17 15:47:54 -080059 private final IControllerRegistryService registryService;
Jonathan Harte37e4e22014-05-13 19:12:02 -070060 private CopyOnWriteArrayList<ITopologyListener> topologyListeners;
Yuta HIGUCHI181d34d2014-02-05 15:05:46 -080061
Pavlin Radoslavov706add22014-02-20 12:15:59 -080062 //
63 // Local state for keeping track of reordered events.
64 // NOTE: Switch Events are not affected by the event reordering.
65 //
66 private Map<ByteBuffer, PortEvent> reorderedAddedPortEvents =
Ray Milkey269ffb92014-04-03 14:43:30 -070067 new HashMap<ByteBuffer, PortEvent>();
Pavlin Radoslavov706add22014-02-20 12:15:59 -080068 private Map<ByteBuffer, LinkEvent> reorderedAddedLinkEvents =
Ray Milkey269ffb92014-04-03 14:43:30 -070069 new HashMap<ByteBuffer, LinkEvent>();
Pavlin Radoslavov706add22014-02-20 12:15:59 -080070 private Map<ByteBuffer, DeviceEvent> reorderedAddedDeviceEvents =
Ray Milkey269ffb92014-04-03 14:43:30 -070071 new HashMap<ByteBuffer, DeviceEvent>();
Pavlin Radoslavov018d5332014-02-19 23:08:35 -080072
Pavlin Radoslavov74986ce2014-02-20 13:17:20 -080073 //
Pavlin Radoslavov26d83402014-02-20 15:24:30 -080074 // Local state for keeping track of locally discovered events so we can
75 // cleanup properly when a Switch or Port is removed.
76 //
Yuta HIGUCHIbc67a052014-06-30 10:37:09 -070077 // We keep all Port, (incoming) Link and Device events per Switch DPID:
Pavlin Radoslavov26d83402014-02-20 15:24:30 -080078 // - If a switch goes down, we remove all corresponding Port, Link and
79 // Device events.
80 // - If a port on a switch goes down, we remove all corresponding Link
Yuta HIGUCHIbc67a052014-06-30 10:37:09 -070081 // and Device events discovered by this instance.
82 //
83 // How to handle side-effect of remote events.
84 // - Remote Port Down event -> Link Down
85 // Not handled. (XXX Shouldn't it be removed from discovered.. Map)
86 // - Remote Device Added -> lose ownership of Device)
87 // Not handled. (XXX Shouldn't it be removed from discovered.. Map)
88 //
89 // XXX Domain knowledge based invariant maintenance should be moved to
90 // driver module, since the invariant may be different on optical, etc.
91 //
92 // What happens on leadership change?
93 // - Probably should: remove from discovered.. Maps, but not send DELETE events
94 // XXX Switch/Port can be rediscovered by new leader, but Link, Device?
95 // - Current: There is no way to recognize leadership change?
96 // ZookeeperRegistry.requestControl(long, ControlChangeCallback)
97 // is the only way to register listener, and it allows only 1 listener,
98 // which is already used by Controller class.
99 //
100 // FIXME Replace with concurrent variant.
101 // #removeSwitchDiscoveryEvent(SwitchEvent) runs in different thread.
Pavlin Radoslavov26d83402014-02-20 15:24:30 -0800102 //
Yuta HIGUCHI8f3dfa32014-06-25 00:14:25 -0700103 private Map<Dpid, Map<ByteBuffer, PortEvent>> discoveredAddedPortEvents =
Ray Milkey269ffb92014-04-03 14:43:30 -0700104 new HashMap<>();
Yuta HIGUCHI8f3dfa32014-06-25 00:14:25 -0700105 private Map<Dpid, Map<ByteBuffer, LinkEvent>> discoveredAddedLinkEvents =
Ray Milkey269ffb92014-04-03 14:43:30 -0700106 new HashMap<>();
Yuta HIGUCHI8f3dfa32014-06-25 00:14:25 -0700107 private Map<Dpid, Map<ByteBuffer, DeviceEvent>> discoveredAddedDeviceEvents =
Ray Milkey269ffb92014-04-03 14:43:30 -0700108 new HashMap<>();
Pavlin Radoslavov26d83402014-02-20 15:24:30 -0800109
110 //
Pavlin Radoslavov74986ce2014-02-20 13:17:20 -0800111 // Local state for keeping track of the application event notifications
112 //
Yuta HIGUCHIbc67a052014-06-30 10:37:09 -0700113 // - Queue of events, which will be dispatched to local listeners
114 // on next notification.
Yuta HIGUCHI703696c2014-06-25 20:36:45 -0700115
116 private List<SwitchEvent> apiAddedSwitchEvents = new LinkedList<>();
117 private List<SwitchEvent> apiRemovedSwitchEvents = new LinkedList<>();
118 private List<PortEvent> apiAddedPortEvents = new LinkedList<>();
119 private List<PortEvent> apiRemovedPortEvents = new LinkedList<>();
120 private List<LinkEvent> apiAddedLinkEvents = new LinkedList<>();
121 private List<LinkEvent> apiRemovedLinkEvents = new LinkedList<>();
122 private List<DeviceEvent> apiAddedDeviceEvents = new LinkedList<>();
123 private List<DeviceEvent> apiRemovedDeviceEvents = new LinkedList<>();
Pavlin Radoslavov74986ce2014-02-20 13:17:20 -0800124
Pavlin Radoslavovc1cfde52014-02-19 11:35:29 -0800125 /**
126 * Constructor.
127 *
Jonathan Harte37e4e22014-05-13 19:12:02 -0700128 * @param registryService the Registry Service to use.
129 * @param topologyListeners the collection of topology listeners to use.
Pavlin Radoslavovc1cfde52014-02-19 11:35:29 -0800130 */
131 public TopologyManager(IControllerRegistryService registryService,
Jonathan Harte37e4e22014-05-13 19:12:02 -0700132 CopyOnWriteArrayList<ITopologyListener> topologyListeners) {
133 datastore = new TopologyDatastore();
Ray Milkey269ffb92014-04-03 14:43:30 -0700134 this.registryService = registryService;
Jonathan Harte37e4e22014-05-13 19:12:02 -0700135 this.topologyListeners = topologyListeners;
Yuta HIGUCHI80829d12014-02-05 20:16:56 -0800136 }
Yuta HIGUCHI181d34d2014-02-05 15:05:46 -0800137
Pavlin Radoslavovc1cfde52014-02-19 11:35:29 -0800138 /**
Jonathan Harte37e4e22014-05-13 19:12:02 -0700139 * Get the Topology.
Pavlin Radoslavovc1cfde52014-02-19 11:35:29 -0800140 *
Jonathan Harte37e4e22014-05-13 19:12:02 -0700141 * @return the Topology.
Pavlin Radoslavovc1cfde52014-02-19 11:35:29 -0800142 */
Jonathan Harte37e4e22014-05-13 19:12:02 -0700143 Topology getTopology() {
144 return topology;
Pavlin Radoslavov6d224ee2014-02-18 16:43:15 -0800145 }
146
Yuta HIGUCHI4bfdd532014-02-07 13:47:36 -0800147 /**
Pavlin Radoslavov721a2e02014-02-14 23:40:14 -0800148 * Event handler class.
149 */
150 private class EventHandler extends Thread implements
Ray Milkey269ffb92014-04-03 14:43:30 -0700151 IEventChannelListener<byte[], TopologyEvent> {
152 private BlockingQueue<EventEntry<TopologyEvent>> topologyEvents =
153 new LinkedBlockingQueue<EventEntry<TopologyEvent>>();
Pavlin Radoslavov721a2e02014-02-14 23:40:14 -0800154
Ray Milkey269ffb92014-04-03 14:43:30 -0700155 /**
156 * Startup processing.
157 */
158 private void startup() {
159 //
160 // TODO: Read all state from the database:
161 //
162 // Collection<EventEntry<TopologyEvent>> collection =
163 // readWholeTopologyFromDB();
164 //
165 // For now, as a shortcut we read it from the datagrid
166 //
Ray Milkey5df613b2014-04-15 10:50:56 -0700167 Collection<TopologyEvent> allTopologyEvents =
Ray Milkey269ffb92014-04-03 14:43:30 -0700168 eventChannel.getAllEntries();
169 Collection<EventEntry<TopologyEvent>> collection =
170 new LinkedList<EventEntry<TopologyEvent>>();
Pavlin Radoslavov721a2e02014-02-14 23:40:14 -0800171
Ray Milkey5df613b2014-04-15 10:50:56 -0700172 for (TopologyEvent topologyEvent : allTopologyEvents) {
Ray Milkey269ffb92014-04-03 14:43:30 -0700173 EventEntry<TopologyEvent> eventEntry =
174 new EventEntry<TopologyEvent>(EventEntry.Type.ENTRY_ADD,
175 topologyEvent);
176 collection.add(eventEntry);
177 }
178 processEvents(collection);
179 }
Pavlin Radoslavov721a2e02014-02-14 23:40:14 -0800180
Ray Milkey269ffb92014-04-03 14:43:30 -0700181 /**
182 * Run the thread.
183 */
184 @Override
185 public void run() {
186 Collection<EventEntry<TopologyEvent>> collection =
187 new LinkedList<EventEntry<TopologyEvent>>();
Pavlin Radoslavov721a2e02014-02-14 23:40:14 -0800188
Ray Milkey269ffb92014-04-03 14:43:30 -0700189 this.setName("TopologyManager.EventHandler " + this.getId());
190 startup();
Pavlin Radoslavov721a2e02014-02-14 23:40:14 -0800191
Ray Milkey269ffb92014-04-03 14:43:30 -0700192 //
193 // The main loop
194 //
Pavlin Radoslavov8e881a42014-06-24 16:58:07 -0700195 while (true) {
196 try {
197 EventEntry<TopologyEvent> eventEntry =
198 topologyEvents.take();
Ray Milkey269ffb92014-04-03 14:43:30 -0700199 collection.add(eventEntry);
200 topologyEvents.drainTo(collection);
Pavlin Radoslavov721a2e02014-02-14 23:40:14 -0800201
Ray Milkey269ffb92014-04-03 14:43:30 -0700202 processEvents(collection);
203 collection.clear();
Pavlin Radoslavov8e881a42014-06-24 16:58:07 -0700204 } catch (Exception exception) {
205 log.debug("Exception processing Topology Events: ",
206 exception);
Ray Milkey269ffb92014-04-03 14:43:30 -0700207 }
Ray Milkey269ffb92014-04-03 14:43:30 -0700208 }
209 }
Pavlin Radoslavov721a2e02014-02-14 23:40:14 -0800210
Ray Milkey269ffb92014-04-03 14:43:30 -0700211 /**
212 * Process all topology events.
213 *
214 * @param events the events to process.
215 */
216 private void processEvents(Collection<EventEntry<TopologyEvent>> events) {
217 // Local state for computing the final set of events
218 Map<ByteBuffer, SwitchEvent> addedSwitchEvents = new HashMap<>();
219 Map<ByteBuffer, SwitchEvent> removedSwitchEvents = new HashMap<>();
220 Map<ByteBuffer, PortEvent> addedPortEvents = new HashMap<>();
221 Map<ByteBuffer, PortEvent> removedPortEvents = new HashMap<>();
222 Map<ByteBuffer, LinkEvent> addedLinkEvents = new HashMap<>();
223 Map<ByteBuffer, LinkEvent> removedLinkEvents = new HashMap<>();
224 Map<ByteBuffer, DeviceEvent> addedDeviceEvents = new HashMap<>();
225 Map<ByteBuffer, DeviceEvent> removedDeviceEvents = new HashMap<>();
Pavlin Radoslavov3c9cc552014-02-20 09:58:38 -0800226
Ray Milkey269ffb92014-04-03 14:43:30 -0700227 //
228 // Classify and suppress matching events
229 //
230 for (EventEntry<TopologyEvent> event : events) {
231 TopologyEvent topologyEvent = event.eventData();
232 SwitchEvent switchEvent = topologyEvent.switchEvent;
233 PortEvent portEvent = topologyEvent.portEvent;
234 LinkEvent linkEvent = topologyEvent.linkEvent;
235 DeviceEvent deviceEvent = topologyEvent.deviceEvent;
Pavlin Radoslavov018d5332014-02-19 23:08:35 -0800236
Ray Milkey269ffb92014-04-03 14:43:30 -0700237 //
238 // Extract the events
239 //
240 switch (event.eventType()) {
241 case ENTRY_ADD:
242 log.debug("Topology event ENTRY_ADD: {}", topologyEvent);
243 if (switchEvent != null) {
244 ByteBuffer id = switchEvent.getIDasByteBuffer();
245 addedSwitchEvents.put(id, switchEvent);
246 removedSwitchEvents.remove(id);
247 // Switch Events are not affected by event reordering
248 }
249 if (portEvent != null) {
250 ByteBuffer id = portEvent.getIDasByteBuffer();
251 addedPortEvents.put(id, portEvent);
252 removedPortEvents.remove(id);
253 reorderedAddedPortEvents.remove(id);
254 }
255 if (linkEvent != null) {
256 ByteBuffer id = linkEvent.getIDasByteBuffer();
257 addedLinkEvents.put(id, linkEvent);
258 removedLinkEvents.remove(id);
259 reorderedAddedLinkEvents.remove(id);
260 }
261 if (deviceEvent != null) {
262 ByteBuffer id = deviceEvent.getIDasByteBuffer();
263 addedDeviceEvents.put(id, deviceEvent);
264 removedDeviceEvents.remove(id);
265 reorderedAddedDeviceEvents.remove(id);
266 }
267 break;
268 case ENTRY_REMOVE:
269 log.debug("Topology event ENTRY_REMOVE: {}", topologyEvent);
270 if (switchEvent != null) {
271 ByteBuffer id = switchEvent.getIDasByteBuffer();
272 addedSwitchEvents.remove(id);
273 removedSwitchEvents.put(id, switchEvent);
274 // Switch Events are not affected by event reordering
275 }
276 if (portEvent != null) {
277 ByteBuffer id = portEvent.getIDasByteBuffer();
278 addedPortEvents.remove(id);
279 removedPortEvents.put(id, portEvent);
280 reorderedAddedPortEvents.remove(id);
281 }
282 if (linkEvent != null) {
283 ByteBuffer id = linkEvent.getIDasByteBuffer();
284 addedLinkEvents.remove(id);
285 removedLinkEvents.put(id, linkEvent);
286 reorderedAddedLinkEvents.remove(id);
287 }
288 if (deviceEvent != null) {
289 ByteBuffer id = deviceEvent.getIDasByteBuffer();
290 addedDeviceEvents.remove(id);
291 removedDeviceEvents.put(id, deviceEvent);
292 reorderedAddedDeviceEvents.remove(id);
293 }
294 break;
Ray Milkey0b122ed2014-04-14 10:06:03 -0700295 default:
296 log.error("Unknown topology event {}",
297 event.eventType());
Ray Milkey269ffb92014-04-03 14:43:30 -0700298 }
299 }
Pavlin Radoslavov3c9cc552014-02-20 09:58:38 -0800300
Ray Milkey269ffb92014-04-03 14:43:30 -0700301 //
Jonathan Harte37e4e22014-05-13 19:12:02 -0700302 // Lock the topology while it is modified
Ray Milkey269ffb92014-04-03 14:43:30 -0700303 //
Jonathan Harte37e4e22014-05-13 19:12:02 -0700304 topology.acquireWriteLock();
Pavlin Radoslavov8ffb8bf2014-02-20 15:34:26 -0800305
Ray Milkey269ffb92014-04-03 14:43:30 -0700306 try {
307 //
308 // Apply the classified events.
309 //
310 // Apply the "add" events in the proper order:
311 // switch, port, link, device
312 //
Ray Milkeyb29e6262014-04-09 16:02:14 -0700313 for (SwitchEvent switchEvent : addedSwitchEvents.values()) {
Ray Milkey269ffb92014-04-03 14:43:30 -0700314 addSwitch(switchEvent);
Ray Milkeyb29e6262014-04-09 16:02:14 -0700315 }
316 for (PortEvent portEvent : addedPortEvents.values()) {
Ray Milkey269ffb92014-04-03 14:43:30 -0700317 addPort(portEvent);
Ray Milkeyb29e6262014-04-09 16:02:14 -0700318 }
319 for (LinkEvent linkEvent : addedLinkEvents.values()) {
Ray Milkey269ffb92014-04-03 14:43:30 -0700320 addLink(linkEvent);
Ray Milkeyb29e6262014-04-09 16:02:14 -0700321 }
322 for (DeviceEvent deviceEvent : addedDeviceEvents.values()) {
Ray Milkey269ffb92014-04-03 14:43:30 -0700323 addDevice(deviceEvent);
Ray Milkeyb29e6262014-04-09 16:02:14 -0700324 }
Ray Milkey269ffb92014-04-03 14:43:30 -0700325 //
326 // Apply the "remove" events in the reverse order:
327 // device, link, port, switch
328 //
Ray Milkeyb29e6262014-04-09 16:02:14 -0700329 for (DeviceEvent deviceEvent : removedDeviceEvents.values()) {
Ray Milkey269ffb92014-04-03 14:43:30 -0700330 removeDevice(deviceEvent);
Ray Milkeyb29e6262014-04-09 16:02:14 -0700331 }
332 for (LinkEvent linkEvent : removedLinkEvents.values()) {
Ray Milkey269ffb92014-04-03 14:43:30 -0700333 removeLink(linkEvent);
Ray Milkeyb29e6262014-04-09 16:02:14 -0700334 }
335 for (PortEvent portEvent : removedPortEvents.values()) {
Ray Milkey269ffb92014-04-03 14:43:30 -0700336 removePort(portEvent);
Ray Milkeyb29e6262014-04-09 16:02:14 -0700337 }
338 for (SwitchEvent switchEvent : removedSwitchEvents.values()) {
Ray Milkey269ffb92014-04-03 14:43:30 -0700339 removeSwitch(switchEvent);
Ray Milkeyb29e6262014-04-09 16:02:14 -0700340 }
Yuta HIGUCHI3aca81a2014-02-23 12:41:19 -0800341
Ray Milkey269ffb92014-04-03 14:43:30 -0700342 //
343 // Apply reordered events
344 //
345 applyReorderedEvents(!addedSwitchEvents.isEmpty(),
346 !addedPortEvents.isEmpty());
Yuta HIGUCHI3aca81a2014-02-23 12:41:19 -0800347
Ray Milkey269ffb92014-04-03 14:43:30 -0700348 } finally {
349 //
Jonathan Harte37e4e22014-05-13 19:12:02 -0700350 // Topology modifications completed: Release the lock
Ray Milkey269ffb92014-04-03 14:43:30 -0700351 //
Jonathan Harte37e4e22014-05-13 19:12:02 -0700352 topology.releaseWriteLock();
Ray Milkey269ffb92014-04-03 14:43:30 -0700353 }
Yuta HIGUCHI3aca81a2014-02-23 12:41:19 -0800354
Ray Milkey269ffb92014-04-03 14:43:30 -0700355 //
356 // Dispatch the Topology Notification Events to the applications
357 //
Jonathan Harte37e4e22014-05-13 19:12:02 -0700358 dispatchTopologyEvents();
Ray Milkey269ffb92014-04-03 14:43:30 -0700359 }
Pavlin Radoslavov721a2e02014-02-14 23:40:14 -0800360
Ray Milkey269ffb92014-04-03 14:43:30 -0700361 /**
362 * Receive a notification that an entry is added.
363 *
364 * @param value the value for the entry.
365 */
366 @Override
367 public void entryAdded(TopologyEvent value) {
368 EventEntry<TopologyEvent> eventEntry =
369 new EventEntry<TopologyEvent>(EventEntry.Type.ENTRY_ADD,
370 value);
371 topologyEvents.add(eventEntry);
372 }
Pavlin Radoslavov721a2e02014-02-14 23:40:14 -0800373
Ray Milkey269ffb92014-04-03 14:43:30 -0700374 /**
375 * Receive a notification that an entry is removed.
376 *
377 * @param value the value for the entry.
378 */
379 @Override
380 public void entryRemoved(TopologyEvent value) {
381 EventEntry<TopologyEvent> eventEntry =
382 new EventEntry<TopologyEvent>(EventEntry.Type.ENTRY_REMOVE,
383 value);
384 topologyEvents.add(eventEntry);
385 }
Pavlin Radoslavov721a2e02014-02-14 23:40:14 -0800386
Ray Milkey269ffb92014-04-03 14:43:30 -0700387 /**
388 * Receive a notification that an entry is updated.
389 *
390 * @param value the value for the entry.
391 */
392 @Override
393 public void entryUpdated(TopologyEvent value) {
394 // NOTE: The ADD and UPDATE events are processed in same way
395 entryAdded(value);
396 }
Pavlin Radoslavov721a2e02014-02-14 23:40:14 -0800397 }
398
399 /**
400 * Startup processing.
401 *
402 * @param datagridService the datagrid service to use.
403 */
404 void startup(IDatagridService datagridService) {
Ray Milkey269ffb92014-04-03 14:43:30 -0700405 eventChannel = datagridService.addListener(EVENT_CHANNEL_NAME,
406 eventHandler,
407 byte[].class,
408 TopologyEvent.class);
409 eventHandler.start();
Pavlin Radoslavov721a2e02014-02-14 23:40:14 -0800410 }
411
Pavlin Radoslavov74986ce2014-02-20 13:17:20 -0800412 /**
Jonathan Harte37e4e22014-05-13 19:12:02 -0700413 * Dispatch Topology Events to the listeners.
Pavlin Radoslavov74986ce2014-02-20 13:17:20 -0800414 */
Jonathan Harte37e4e22014-05-13 19:12:02 -0700415 private void dispatchTopologyEvents() {
Ray Milkey269ffb92014-04-03 14:43:30 -0700416 if (apiAddedSwitchEvents.isEmpty() &&
417 apiRemovedSwitchEvents.isEmpty() &&
418 apiAddedPortEvents.isEmpty() &&
419 apiRemovedPortEvents.isEmpty() &&
420 apiAddedLinkEvents.isEmpty() &&
421 apiRemovedLinkEvents.isEmpty() &&
422 apiAddedDeviceEvents.isEmpty() &&
423 apiRemovedDeviceEvents.isEmpty()) {
424 return; // No events to dispatch
425 }
Pavlin Radoslavov74986ce2014-02-20 13:17:20 -0800426
Ray Milkey269ffb92014-04-03 14:43:30 -0700427 if (log.isDebugEnabled()) {
428 //
429 // Debug statements
430 // TODO: Those statements should be removed in the future
431 //
Ray Milkeyb29e6262014-04-09 16:02:14 -0700432 for (SwitchEvent switchEvent : apiAddedSwitchEvents) {
Jonathan Harte37e4e22014-05-13 19:12:02 -0700433 log.debug("Dispatch Topology Event: ADDED {}", switchEvent);
Ray Milkeyb29e6262014-04-09 16:02:14 -0700434 }
435 for (SwitchEvent switchEvent : apiRemovedSwitchEvents) {
Jonathan Harte37e4e22014-05-13 19:12:02 -0700436 log.debug("Dispatch Topology Event: REMOVED {}", switchEvent);
Ray Milkeyb29e6262014-04-09 16:02:14 -0700437 }
438 for (PortEvent portEvent : apiAddedPortEvents) {
Jonathan Harte37e4e22014-05-13 19:12:02 -0700439 log.debug("Dispatch Topology Event: ADDED {}", portEvent);
Ray Milkeyb29e6262014-04-09 16:02:14 -0700440 }
441 for (PortEvent portEvent : apiRemovedPortEvents) {
Jonathan Harte37e4e22014-05-13 19:12:02 -0700442 log.debug("Dispatch Topology Event: REMOVED {}", portEvent);
Ray Milkeyb29e6262014-04-09 16:02:14 -0700443 }
444 for (LinkEvent linkEvent : apiAddedLinkEvents) {
Jonathan Harte37e4e22014-05-13 19:12:02 -0700445 log.debug("Dispatch Topology Event: ADDED {}", linkEvent);
Ray Milkeyb29e6262014-04-09 16:02:14 -0700446 }
447 for (LinkEvent linkEvent : apiRemovedLinkEvents) {
Jonathan Harte37e4e22014-05-13 19:12:02 -0700448 log.debug("Dispatch Topology Event: REMOVED {}", linkEvent);
Ray Milkeyb29e6262014-04-09 16:02:14 -0700449 }
450 for (DeviceEvent deviceEvent : apiAddedDeviceEvents) {
Jonathan Harte37e4e22014-05-13 19:12:02 -0700451 log.debug("Dispatch Topology Event: ADDED {}", deviceEvent);
Ray Milkeyb29e6262014-04-09 16:02:14 -0700452 }
453 for (DeviceEvent deviceEvent : apiRemovedDeviceEvents) {
Jonathan Harte37e4e22014-05-13 19:12:02 -0700454 log.debug("Dispatch Topology Event: REMOVED {}", deviceEvent);
Ray Milkeyb29e6262014-04-09 16:02:14 -0700455 }
Ray Milkey269ffb92014-04-03 14:43:30 -0700456 }
adminbc181552014-02-21 18:36:42 -0800457
Ray Milkey269ffb92014-04-03 14:43:30 -0700458 // Deliver the events
Jonathan Harte37e4e22014-05-13 19:12:02 -0700459 for (ITopologyListener listener : this.topologyListeners) {
Ray Milkey269ffb92014-04-03 14:43:30 -0700460 // TODO: Should copy before handing them over to listener?
Jonathan Harte37e4e22014-05-13 19:12:02 -0700461 listener.topologyEvents(apiAddedSwitchEvents,
Ray Milkey269ffb92014-04-03 14:43:30 -0700462 apiRemovedSwitchEvents,
463 apiAddedPortEvents,
464 apiRemovedPortEvents,
465 apiAddedLinkEvents,
466 apiRemovedLinkEvents,
467 apiAddedDeviceEvents,
468 apiRemovedDeviceEvents);
469 }
Pavlin Radoslavov74986ce2014-02-20 13:17:20 -0800470
Ray Milkey269ffb92014-04-03 14:43:30 -0700471 //
472 // Cleanup
473 //
474 apiAddedSwitchEvents.clear();
475 apiRemovedSwitchEvents.clear();
476 apiAddedPortEvents.clear();
477 apiRemovedPortEvents.clear();
478 apiAddedLinkEvents.clear();
479 apiRemovedLinkEvents.clear();
480 apiAddedDeviceEvents.clear();
481 apiRemovedDeviceEvents.clear();
Pavlin Radoslavov74986ce2014-02-20 13:17:20 -0800482 }
483
484 /**
485 * Apply reordered events.
486 *
487 * @param hasAddedSwitchEvents true if there were Added Switch Events.
Ray Milkey269ffb92014-04-03 14:43:30 -0700488 * @param hasAddedPortEvents true if there were Added Port Events.
Pavlin Radoslavov74986ce2014-02-20 13:17:20 -0800489 */
Yuta HIGUCHIbc67a052014-06-30 10:37:09 -0700490 @GuardedBy("topology.writeLock")
Pavlin Radoslavov74986ce2014-02-20 13:17:20 -0800491 private void applyReorderedEvents(boolean hasAddedSwitchEvents,
Ray Milkey269ffb92014-04-03 14:43:30 -0700492 boolean hasAddedPortEvents) {
Ray Milkeyb29e6262014-04-09 16:02:14 -0700493 if (!(hasAddedSwitchEvents || hasAddedPortEvents)) {
Ray Milkey269ffb92014-04-03 14:43:30 -0700494 return; // Nothing to do
Ray Milkeyb29e6262014-04-09 16:02:14 -0700495 }
Pavlin Radoslavov74986ce2014-02-20 13:17:20 -0800496
Ray Milkey269ffb92014-04-03 14:43:30 -0700497 //
498 // Try to apply the reordered events.
499 //
500 // NOTE: For simplicity we try to apply all events of a particular
501 // type if any "parent" type event was processed:
502 // - Apply reordered Port Events if Switches were added
503 // - Apply reordered Link and Device Events if Switches or Ports
504 // were added
505 //
adminbc181552014-02-21 18:36:42 -0800506
Ray Milkey269ffb92014-04-03 14:43:30 -0700507 //
508 // Apply reordered Port Events if Switches were added
509 //
510 if (hasAddedSwitchEvents) {
511 Map<ByteBuffer, PortEvent> portEvents = reorderedAddedPortEvents;
512 reorderedAddedPortEvents = new HashMap<>();
Ray Milkeyb29e6262014-04-09 16:02:14 -0700513 for (PortEvent portEvent : portEvents.values()) {
Ray Milkey269ffb92014-04-03 14:43:30 -0700514 addPort(portEvent);
Ray Milkeyb29e6262014-04-09 16:02:14 -0700515 }
Ray Milkey269ffb92014-04-03 14:43:30 -0700516 }
517 //
518 // Apply reordered Link and Device Events if Switches or Ports
519 // were added.
520 //
521 Map<ByteBuffer, LinkEvent> linkEvents = reorderedAddedLinkEvents;
522 reorderedAddedLinkEvents = new HashMap<>();
Ray Milkeyb29e6262014-04-09 16:02:14 -0700523 for (LinkEvent linkEvent : linkEvents.values()) {
Ray Milkey269ffb92014-04-03 14:43:30 -0700524 addLink(linkEvent);
Ray Milkeyb29e6262014-04-09 16:02:14 -0700525 }
Ray Milkey269ffb92014-04-03 14:43:30 -0700526 //
527 Map<ByteBuffer, DeviceEvent> deviceEvents = reorderedAddedDeviceEvents;
528 reorderedAddedDeviceEvents = new HashMap<>();
Ray Milkeyb29e6262014-04-09 16:02:14 -0700529 for (DeviceEvent deviceEvent : deviceEvents.values()) {
Ray Milkey269ffb92014-04-03 14:43:30 -0700530 addDevice(deviceEvent);
Ray Milkeyb29e6262014-04-09 16:02:14 -0700531 }
Pavlin Radoslavov74986ce2014-02-20 13:17:20 -0800532 }
533
Pavlin Radoslavov734ff5a2014-02-26 10:20:43 -0800534 /**
535 * Switch discovered event.
536 *
537 * @param switchEvent the switch event.
Ray Milkey269ffb92014-04-03 14:43:30 -0700538 * @param portEvents the corresponding port events for the switch.
Pavlin Radoslavov734ff5a2014-02-26 10:20:43 -0800539 */
Pavlin Radoslavovc1cfde52014-02-19 11:35:29 -0800540 @Override
Pavlin Radoslavov018d5332014-02-19 23:08:35 -0800541 public void putSwitchDiscoveryEvent(SwitchEvent switchEvent,
Ray Milkey269ffb92014-04-03 14:43:30 -0700542 Collection<PortEvent> portEvents) {
543 if (datastore.addSwitch(switchEvent, portEvents)) {
Jonathan Hart92c819f2014-05-30 10:53:30 -0700544 log.debug("Sending add switch: {}", switchEvent);
Ray Milkey269ffb92014-04-03 14:43:30 -0700545 // Send out notification
546 TopologyEvent topologyEvent = new TopologyEvent(switchEvent);
547 eventChannel.addEntry(topologyEvent.getID(), topologyEvent);
Pavlin Radoslavov26d83402014-02-20 15:24:30 -0800548
Ray Milkey269ffb92014-04-03 14:43:30 -0700549 // Send out notification for each port
550 for (PortEvent portEvent : portEvents) {
Jonathan Hart92c819f2014-05-30 10:53:30 -0700551 log.debug("Sending add port: {}", portEvent);
Ray Milkey269ffb92014-04-03 14:43:30 -0700552 topologyEvent = new TopologyEvent(portEvent);
553 eventChannel.addEntry(topologyEvent.getID(), topologyEvent);
554 }
Pavlin Radoslavov26d83402014-02-20 15:24:30 -0800555
Ray Milkey269ffb92014-04-03 14:43:30 -0700556 //
557 // Keep track of the added ports
558 //
559 // Get the old Port Events
560 Map<ByteBuffer, PortEvent> oldPortEvents =
561 discoveredAddedPortEvents.get(switchEvent.getDpid());
Ray Milkeyb29e6262014-04-09 16:02:14 -0700562 if (oldPortEvents == null) {
Ray Milkey269ffb92014-04-03 14:43:30 -0700563 oldPortEvents = new HashMap<>();
Ray Milkeyb29e6262014-04-09 16:02:14 -0700564 }
Pavlin Radoslavov26d83402014-02-20 15:24:30 -0800565
Ray Milkey269ffb92014-04-03 14:43:30 -0700566 // Store the new Port Events in the local cache
567 Map<ByteBuffer, PortEvent> newPortEvents = new HashMap<>();
568 for (PortEvent portEvent : portEvents) {
569 ByteBuffer id = portEvent.getIDasByteBuffer();
570 newPortEvents.put(id, portEvent);
571 }
572 discoveredAddedPortEvents.put(switchEvent.getDpid(),
573 newPortEvents);
Pavlin Radoslavov26d83402014-02-20 15:24:30 -0800574
Ray Milkey269ffb92014-04-03 14:43:30 -0700575 //
576 // Extract the removed ports
577 //
578 List<PortEvent> removedPortEvents = new LinkedList<>();
579 for (Map.Entry<ByteBuffer, PortEvent> entry : oldPortEvents.entrySet()) {
580 ByteBuffer key = entry.getKey();
581 PortEvent portEvent = entry.getValue();
Ray Milkeyb29e6262014-04-09 16:02:14 -0700582 if (!newPortEvents.containsKey(key)) {
Ray Milkey269ffb92014-04-03 14:43:30 -0700583 removedPortEvents.add(portEvent);
Ray Milkeyb29e6262014-04-09 16:02:14 -0700584 }
Ray Milkey269ffb92014-04-03 14:43:30 -0700585 }
586
587 // Cleanup old removed ports
Ray Milkeyb29e6262014-04-09 16:02:14 -0700588 for (PortEvent portEvent : removedPortEvents) {
Ray Milkey269ffb92014-04-03 14:43:30 -0700589 removePortDiscoveryEvent(portEvent);
Ray Milkeyb29e6262014-04-09 16:02:14 -0700590 }
Ray Milkey269ffb92014-04-03 14:43:30 -0700591 }
Pavlin Radoslavovc1cfde52014-02-19 11:35:29 -0800592 }
593
Pavlin Radoslavov734ff5a2014-02-26 10:20:43 -0800594 /**
Yuta HIGUCHIbc67a052014-06-30 10:37:09 -0700595 * {@inheritDoc}
596 * <p/>
597 * Called by {@link TopologyPublisher.SwitchCleanup} thread.
Pavlin Radoslavov734ff5a2014-02-26 10:20:43 -0800598 */
Pavlin Radoslavovc1cfde52014-02-19 11:35:29 -0800599 @Override
Pavlin Radoslavov6ea84a42014-02-19 15:50:01 -0800600 public void removeSwitchDiscoveryEvent(SwitchEvent switchEvent) {
Ray Milkey269ffb92014-04-03 14:43:30 -0700601 // Get the old Port Events
602 Map<ByteBuffer, PortEvent> oldPortEvents =
603 discoveredAddedPortEvents.get(switchEvent.getDpid());
Ray Milkeyb29e6262014-04-09 16:02:14 -0700604 if (oldPortEvents == null) {
Ray Milkey269ffb92014-04-03 14:43:30 -0700605 oldPortEvents = new HashMap<>();
Ray Milkeyb29e6262014-04-09 16:02:14 -0700606 }
Pavlin Radoslavov018d5332014-02-19 23:08:35 -0800607
Ray Milkey269ffb92014-04-03 14:43:30 -0700608 if (datastore.deactivateSwitch(switchEvent, oldPortEvents.values())) {
Jonathan Hart92c819f2014-05-30 10:53:30 -0700609 log.debug("Sending remove switch: {}", switchEvent);
Ray Milkey269ffb92014-04-03 14:43:30 -0700610 // Send out notification
611 eventChannel.removeEntry(switchEvent.getID());
Pavlin Radoslavov018d5332014-02-19 23:08:35 -0800612
Ray Milkey269ffb92014-04-03 14:43:30 -0700613 //
614 // Send out notification for each port.
615 //
616 // NOTE: We don't use removePortDiscoveryEvent() for the cleanup,
617 // because it will attempt to remove the port from the database,
618 // and the deactiveSwitch() call above already removed all ports.
619 //
Ray Milkeyb29e6262014-04-09 16:02:14 -0700620 for (PortEvent portEvent : oldPortEvents.values()) {
Jonathan Hart92c819f2014-05-30 10:53:30 -0700621 log.debug("Sending remove port:", portEvent);
Ray Milkey269ffb92014-04-03 14:43:30 -0700622 eventChannel.removeEntry(portEvent.getID());
Ray Milkeyb29e6262014-04-09 16:02:14 -0700623 }
Ray Milkey269ffb92014-04-03 14:43:30 -0700624 discoveredAddedPortEvents.remove(switchEvent.getDpid());
Pavlin Radoslavov26d83402014-02-20 15:24:30 -0800625
Ray Milkey269ffb92014-04-03 14:43:30 -0700626 // Cleanup for each link
627 Map<ByteBuffer, LinkEvent> oldLinkEvents =
628 discoveredAddedLinkEvents.get(switchEvent.getDpid());
629 if (oldLinkEvents != null) {
630 for (LinkEvent linkEvent : new ArrayList<>(oldLinkEvents.values())) {
631 removeLinkDiscoveryEvent(linkEvent);
632 }
633 discoveredAddedLinkEvents.remove(switchEvent.getDpid());
634 }
Pavlin Radoslavov26d83402014-02-20 15:24:30 -0800635
Ray Milkey269ffb92014-04-03 14:43:30 -0700636 // Cleanup for each device
637 Map<ByteBuffer, DeviceEvent> oldDeviceEvents =
638 discoveredAddedDeviceEvents.get(switchEvent.getDpid());
639 if (oldDeviceEvents != null) {
640 for (DeviceEvent deviceEvent : new ArrayList<>(oldDeviceEvents.values())) {
641 removeDeviceDiscoveryEvent(deviceEvent);
642 }
643 discoveredAddedDeviceEvents.remove(switchEvent.getDpid());
644 }
645 }
Pavlin Radoslavovc1cfde52014-02-19 11:35:29 -0800646 }
647
Pavlin Radoslavov734ff5a2014-02-26 10:20:43 -0800648 /**
649 * Port discovered event.
650 *
651 * @param portEvent the port event.
652 */
Pavlin Radoslavovc1cfde52014-02-19 11:35:29 -0800653 @Override
Pavlin Radoslavov6ea84a42014-02-19 15:50:01 -0800654 public void putPortDiscoveryEvent(PortEvent portEvent) {
Ray Milkey269ffb92014-04-03 14:43:30 -0700655 if (datastore.addPort(portEvent)) {
Jonathan Hart92c819f2014-05-30 10:53:30 -0700656 log.debug("Sending add port: {}", portEvent);
Ray Milkey269ffb92014-04-03 14:43:30 -0700657 // Send out notification
658 TopologyEvent topologyEvent = new TopologyEvent(portEvent);
659 eventChannel.addEntry(topologyEvent.getID(), topologyEvent);
Pavlin Radoslavov26d83402014-02-20 15:24:30 -0800660
Ray Milkey269ffb92014-04-03 14:43:30 -0700661 // Store the new Port Event in the local cache
662 Map<ByteBuffer, PortEvent> oldPortEvents =
663 discoveredAddedPortEvents.get(portEvent.getDpid());
664 if (oldPortEvents == null) {
665 oldPortEvents = new HashMap<>();
666 discoveredAddedPortEvents.put(portEvent.getDpid(),
667 oldPortEvents);
668 }
669 ByteBuffer id = portEvent.getIDasByteBuffer();
670 oldPortEvents.put(id, portEvent);
671 }
Pavlin Radoslavovc1cfde52014-02-19 11:35:29 -0800672 }
673
Pavlin Radoslavov734ff5a2014-02-26 10:20:43 -0800674 /**
675 * Port removed event.
676 *
677 * @param portEvent the port event.
678 */
Pavlin Radoslavovc1cfde52014-02-19 11:35:29 -0800679 @Override
Pavlin Radoslavov6ea84a42014-02-19 15:50:01 -0800680 public void removePortDiscoveryEvent(PortEvent portEvent) {
Ray Milkey269ffb92014-04-03 14:43:30 -0700681 if (datastore.deactivatePort(portEvent)) {
Jonathan Hart92c819f2014-05-30 10:53:30 -0700682 log.debug("Sending remove port: {}", portEvent);
Ray Milkey269ffb92014-04-03 14:43:30 -0700683 // Send out notification
684 eventChannel.removeEntry(portEvent.getID());
Pavlin Radoslavov26d83402014-02-20 15:24:30 -0800685
Ray Milkey269ffb92014-04-03 14:43:30 -0700686 // Cleanup the Port Event from the local cache
687 Map<ByteBuffer, PortEvent> oldPortEvents =
688 discoveredAddedPortEvents.get(portEvent.getDpid());
689 if (oldPortEvents != null) {
690 ByteBuffer id = portEvent.getIDasByteBuffer();
691 oldPortEvents.remove(id);
692 }
Pavlin Radoslavov26d83402014-02-20 15:24:30 -0800693
Ray Milkey269ffb92014-04-03 14:43:30 -0700694 // Cleanup for the incoming link
695 Map<ByteBuffer, LinkEvent> oldLinkEvents =
696 discoveredAddedLinkEvents.get(portEvent.getDpid());
697 if (oldLinkEvents != null) {
698 for (LinkEvent linkEvent : new ArrayList<>(oldLinkEvents.values())) {
699 if (linkEvent.getDst().equals(portEvent.id)) {
700 removeLinkDiscoveryEvent(linkEvent);
701 // XXX If we change our model to allow multiple Link on
702 // a Port, this loop must be fixed to allow continuing.
703 break;
704 }
705 }
706 }
Pavlin Radoslavov26d83402014-02-20 15:24:30 -0800707
Ray Milkey269ffb92014-04-03 14:43:30 -0700708 // Cleanup for the connected devices
709 // TODO: The implementation below is probably wrong
710 List<DeviceEvent> removedDeviceEvents = new LinkedList<>();
711 Map<ByteBuffer, DeviceEvent> oldDeviceEvents =
712 discoveredAddedDeviceEvents.get(portEvent.getDpid());
713 if (oldDeviceEvents != null) {
714 for (DeviceEvent deviceEvent : new ArrayList<>(oldDeviceEvents.values())) {
715 for (SwitchPort swp : deviceEvent.getAttachmentPoints()) {
716 if (swp.equals(portEvent.id)) {
717 removedDeviceEvents.add(deviceEvent);
718 }
719 }
720 }
Ray Milkeyb29e6262014-04-09 16:02:14 -0700721 for (DeviceEvent deviceEvent : removedDeviceEvents) {
Ray Milkey269ffb92014-04-03 14:43:30 -0700722 removeDeviceDiscoveryEvent(deviceEvent);
Ray Milkeyb29e6262014-04-09 16:02:14 -0700723 }
Ray Milkey269ffb92014-04-03 14:43:30 -0700724 }
725 }
Pavlin Radoslavovc1cfde52014-02-19 11:35:29 -0800726 }
727
Pavlin Radoslavov734ff5a2014-02-26 10:20:43 -0800728 /**
729 * Link discovered event.
730 *
731 * @param linkEvent the link event.
732 */
Pavlin Radoslavovc1cfde52014-02-19 11:35:29 -0800733 @Override
Pavlin Radoslavov6ea84a42014-02-19 15:50:01 -0800734 public void putLinkDiscoveryEvent(LinkEvent linkEvent) {
Ray Milkey269ffb92014-04-03 14:43:30 -0700735 if (datastore.addLink(linkEvent)) {
Jonathan Hart92c819f2014-05-30 10:53:30 -0700736 log.debug("Sending add link: {}", linkEvent);
Ray Milkey269ffb92014-04-03 14:43:30 -0700737 // Send out notification
738 TopologyEvent topologyEvent = new TopologyEvent(linkEvent);
739 eventChannel.addEntry(topologyEvent.getID(), topologyEvent);
Pavlin Radoslavov26d83402014-02-20 15:24:30 -0800740
Ray Milkey269ffb92014-04-03 14:43:30 -0700741 // Store the new Link Event in the local cache
742 Map<ByteBuffer, LinkEvent> oldLinkEvents =
743 discoveredAddedLinkEvents.get(linkEvent.getDst().getDpid());
744 if (oldLinkEvents == null) {
745 oldLinkEvents = new HashMap<>();
746 discoveredAddedLinkEvents.put(linkEvent.getDst().getDpid(),
747 oldLinkEvents);
748 }
749 ByteBuffer id = linkEvent.getIDasByteBuffer();
750 oldLinkEvents.put(id, linkEvent);
751 }
Pavlin Radoslavovc1cfde52014-02-19 11:35:29 -0800752 }
753
Pavlin Radoslavov734ff5a2014-02-26 10:20:43 -0800754 /**
755 * Link removed event.
756 *
757 * @param linkEvent the link event.
758 */
Pavlin Radoslavovc1cfde52014-02-19 11:35:29 -0800759 @Override
Pavlin Radoslavov6ea84a42014-02-19 15:50:01 -0800760 public void removeLinkDiscoveryEvent(LinkEvent linkEvent) {
Ray Milkey269ffb92014-04-03 14:43:30 -0700761 if (datastore.removeLink(linkEvent)) {
Jonathan Hart92c819f2014-05-30 10:53:30 -0700762 log.debug("Sending remove link: {}", linkEvent);
Ray Milkey269ffb92014-04-03 14:43:30 -0700763 // Send out notification
764 eventChannel.removeEntry(linkEvent.getID());
Pavlin Radoslavov26d83402014-02-20 15:24:30 -0800765
Ray Milkey269ffb92014-04-03 14:43:30 -0700766 // Cleanup the Link Event from the local cache
767 Map<ByteBuffer, LinkEvent> oldLinkEvents =
768 discoveredAddedLinkEvents.get(linkEvent.getDst().getDpid());
769 if (oldLinkEvents != null) {
770 ByteBuffer id = linkEvent.getIDasByteBuffer();
771 oldLinkEvents.remove(id);
772 }
773 }
Pavlin Radoslavovc1cfde52014-02-19 11:35:29 -0800774 }
Jonathan Hart22eb9882014-02-11 15:52:59 -0800775
Pavlin Radoslavov734ff5a2014-02-26 10:20:43 -0800776 /**
777 * Device discovered event.
778 *
779 * @param deviceEvent the device event.
780 */
Pavlin Radoslavovc1cfde52014-02-19 11:35:29 -0800781 @Override
Pavlin Radoslavov6ea84a42014-02-19 15:50:01 -0800782 public void putDeviceDiscoveryEvent(DeviceEvent deviceEvent) {
Ray Milkey269ffb92014-04-03 14:43:30 -0700783 if (datastore.addDevice(deviceEvent)) {
784 // Send out notification
785 TopologyEvent topologyEvent = new TopologyEvent(deviceEvent);
786 eventChannel.addEntry(topologyEvent.getID(), topologyEvent);
Jonathan Harte37e4e22014-05-13 19:12:02 -0700787 log.debug("Put the device info into the cache of the topology. mac {}", deviceEvent.getMac());
Ray Milkey269ffb92014-04-03 14:43:30 -0700788
789 // Store the new Device Event in the local cache
790 // TODO: The implementation below is probably wrong
791 for (SwitchPort swp : deviceEvent.getAttachmentPoints()) {
792 Map<ByteBuffer, DeviceEvent> oldDeviceEvents =
793 discoveredAddedDeviceEvents.get(swp.getDpid());
794 if (oldDeviceEvents == null) {
795 oldDeviceEvents = new HashMap<>();
796 discoveredAddedDeviceEvents.put(swp.getDpid(),
797 oldDeviceEvents);
798 }
799 ByteBuffer id = deviceEvent.getIDasByteBuffer();
800 oldDeviceEvents.put(id, deviceEvent);
801 }
802 }
Pavlin Radoslavovc1cfde52014-02-19 11:35:29 -0800803 }
Jonathan Hart22eb9882014-02-11 15:52:59 -0800804
Pavlin Radoslavov734ff5a2014-02-26 10:20:43 -0800805 /**
806 * Device removed event.
807 *
808 * @param deviceEvent the device event.
809 */
Pavlin Radoslavovc1cfde52014-02-19 11:35:29 -0800810 @Override
Pavlin Radoslavov6ea84a42014-02-19 15:50:01 -0800811 public void removeDeviceDiscoveryEvent(DeviceEvent deviceEvent) {
Ray Milkey269ffb92014-04-03 14:43:30 -0700812 if (datastore.removeDevice(deviceEvent)) {
813 // Send out notification
814 eventChannel.removeEntry(deviceEvent.getID());
Jonathan Harte37e4e22014-05-13 19:12:02 -0700815 log.debug("Remove the device info into the cache of the topology. mac {}", deviceEvent.getMac());
Pavlin Radoslavov26d83402014-02-20 15:24:30 -0800816
Ray Milkey269ffb92014-04-03 14:43:30 -0700817 // Cleanup the Device Event from the local cache
818 // TODO: The implementation below is probably wrong
819 ByteBuffer id = ByteBuffer.wrap(deviceEvent.getID());
820 for (SwitchPort swp : deviceEvent.getAttachmentPoints()) {
821 Map<ByteBuffer, DeviceEvent> oldDeviceEvents =
822 discoveredAddedDeviceEvents.get(swp.getDpid());
823 if (oldDeviceEvents != null) {
824 oldDeviceEvents.remove(id);
825 }
826 }
827 }
Pavlin Radoslavovc1cfde52014-02-19 11:35:29 -0800828 }
Jonathan Hart22eb9882014-02-11 15:52:59 -0800829
Pavlin Radoslavov734ff5a2014-02-26 10:20:43 -0800830 /**
Jonathan Harte37e4e22014-05-13 19:12:02 -0700831 * Add a switch to the topology.
Pavlin Radoslavov734ff5a2014-02-26 10:20:43 -0800832 *
833 * @param switchEvent the Switch Event with the switch to add.
834 */
Yuta HIGUCHIbc67a052014-06-30 10:37:09 -0700835 @GuardedBy("topology.writeLock")
Pavlin Radoslavov74986ce2014-02-20 13:17:20 -0800836 private void addSwitch(SwitchEvent switchEvent) {
Jonathan Harte37e4e22014-05-13 19:12:02 -0700837 Switch sw = topology.getSwitch(switchEvent.getDpid());
Ray Milkey269ffb92014-04-03 14:43:30 -0700838 if (sw == null) {
Jonathan Harte37e4e22014-05-13 19:12:02 -0700839 sw = new SwitchImpl(topology, switchEvent.getDpid());
840 topology.putSwitch(sw);
Ray Milkey269ffb92014-04-03 14:43:30 -0700841 } else {
842 // TODO: Update the switch attributes
843 // TODO: Nothing to do for now
Ray Milkey1aa71f82014-04-08 16:23:24 -0700844 log.debug("Update switch attributes");
Ray Milkey269ffb92014-04-03 14:43:30 -0700845 }
846 apiAddedSwitchEvents.add(switchEvent);
Pavlin Radoslavov3c9cc552014-02-20 09:58:38 -0800847 }
848
Pavlin Radoslavov734ff5a2014-02-26 10:20:43 -0800849 /**
Jonathan Harte37e4e22014-05-13 19:12:02 -0700850 * Remove a switch from the topology.
Pavlin Radoslavov734ff5a2014-02-26 10:20:43 -0800851 *
852 * @param switchEvent the Switch Event with the switch to remove.
853 */
Yuta HIGUCHIbc67a052014-06-30 10:37:09 -0700854 @GuardedBy("topology.writeLock")
Pavlin Radoslavov74986ce2014-02-20 13:17:20 -0800855 private void removeSwitch(SwitchEvent switchEvent) {
Jonathan Harte37e4e22014-05-13 19:12:02 -0700856 Switch sw = topology.getSwitch(switchEvent.getDpid());
Ray Milkey269ffb92014-04-03 14:43:30 -0700857 if (sw == null) {
858 log.warn("Switch {} already removed, ignoring", switchEvent);
859 return;
860 }
Pavlin Radoslavov3c9cc552014-02-20 09:58:38 -0800861
Ray Milkey269ffb92014-04-03 14:43:30 -0700862 //
863 // Remove all Ports on the Switch
864 //
865 ArrayList<PortEvent> portsToRemove = new ArrayList<>();
866 for (Port port : sw.getPorts()) {
867 log.warn("Port {} on Switch {} should be removed prior to removing Switch. Removing Port now.",
868 port, switchEvent);
869 PortEvent portEvent = new PortEvent(port.getDpid(),
870 port.getNumber());
871 portsToRemove.add(portEvent);
872 }
Ray Milkeyb29e6262014-04-09 16:02:14 -0700873 for (PortEvent portEvent : portsToRemove) {
Ray Milkey269ffb92014-04-03 14:43:30 -0700874 removePort(portEvent);
Ray Milkeyb29e6262014-04-09 16:02:14 -0700875 }
Pavlin Radoslavov3c9cc552014-02-20 09:58:38 -0800876
Jonathan Harte37e4e22014-05-13 19:12:02 -0700877 topology.removeSwitch(switchEvent.getDpid());
Ray Milkey269ffb92014-04-03 14:43:30 -0700878 apiRemovedSwitchEvents.add(switchEvent);
Pavlin Radoslavov3c9cc552014-02-20 09:58:38 -0800879 }
880
Pavlin Radoslavov734ff5a2014-02-26 10:20:43 -0800881 /**
Jonathan Harte37e4e22014-05-13 19:12:02 -0700882 * Add a port to the topology.
Pavlin Radoslavov734ff5a2014-02-26 10:20:43 -0800883 *
884 * @param portEvent the Port Event with the port to add.
885 */
Yuta HIGUCHIbc67a052014-06-30 10:37:09 -0700886 @GuardedBy("topology.writeLock")
Pavlin Radoslavov3c9cc552014-02-20 09:58:38 -0800887 private void addPort(PortEvent portEvent) {
Jonathan Harte37e4e22014-05-13 19:12:02 -0700888 Switch sw = topology.getSwitch(portEvent.getDpid());
Ray Milkey269ffb92014-04-03 14:43:30 -0700889 if (sw == null) {
Jonathan Hartf1675202014-05-23 14:59:07 -0700890 log.debug("{} reordered because switch is null", portEvent);
Ray Milkey269ffb92014-04-03 14:43:30 -0700891 // Reordered event: delay the event in local cache
892 ByteBuffer id = portEvent.getIDasByteBuffer();
893 reorderedAddedPortEvents.put(id, portEvent);
894 return;
895 }
896 SwitchImpl switchImpl = getSwitchImpl(sw);
Pavlin Radoslavov3c9cc552014-02-20 09:58:38 -0800897
Ray Milkey269ffb92014-04-03 14:43:30 -0700898 Port port = sw.getPort(portEvent.getNumber());
899 if (port == null) {
Jonathan Harte37e4e22014-05-13 19:12:02 -0700900 port = new PortImpl(topology, sw, portEvent.getNumber());
Ray Milkey269ffb92014-04-03 14:43:30 -0700901 switchImpl.addPort(port);
902 } else {
903 // TODO: Update the port attributes
Ray Milkey1aa71f82014-04-08 16:23:24 -0700904 log.debug("Update port attributes");
Ray Milkey269ffb92014-04-03 14:43:30 -0700905 }
906 apiAddedPortEvents.add(portEvent);
Pavlin Radoslavov3c9cc552014-02-20 09:58:38 -0800907 }
908
Pavlin Radoslavov734ff5a2014-02-26 10:20:43 -0800909 /**
Jonathan Harte37e4e22014-05-13 19:12:02 -0700910 * Remove a port from the topology.
Pavlin Radoslavov734ff5a2014-02-26 10:20:43 -0800911 *
912 * @param portEvent the Port Event with the port to remove.
913 */
Yuta HIGUCHIbc67a052014-06-30 10:37:09 -0700914 @GuardedBy("topology.writeLock")
Pavlin Radoslavov3c9cc552014-02-20 09:58:38 -0800915 private void removePort(PortEvent portEvent) {
Jonathan Harte37e4e22014-05-13 19:12:02 -0700916 Switch sw = topology.getSwitch(portEvent.getDpid());
Ray Milkey269ffb92014-04-03 14:43:30 -0700917 if (sw == null) {
918 log.warn("Parent Switch for Port {} already removed, ignoring",
919 portEvent);
920 return;
921 }
Pavlin Radoslavov3c9cc552014-02-20 09:58:38 -0800922
Ray Milkey269ffb92014-04-03 14:43:30 -0700923 Port port = sw.getPort(portEvent.getNumber());
924 if (port == null) {
925 log.warn("Port {} already removed, ignoring", portEvent);
926 return;
927 }
Pavlin Radoslavov3c9cc552014-02-20 09:58:38 -0800928
Ray Milkey269ffb92014-04-03 14:43:30 -0700929 //
930 // Remove all Devices attached to the Port
931 //
932 ArrayList<DeviceEvent> devicesToRemove = new ArrayList<>();
933 for (Device device : port.getDevices()) {
934 log.debug("Removing Device {} on Port {}", device, portEvent);
935 DeviceEvent deviceEvent = new DeviceEvent(device.getMacAddress());
936 SwitchPort switchPort = new SwitchPort(port.getSwitch().getDpid(),
937 port.getNumber());
938 deviceEvent.addAttachmentPoint(switchPort);
939 devicesToRemove.add(deviceEvent);
940 }
Ray Milkeyb29e6262014-04-09 16:02:14 -0700941 for (DeviceEvent deviceEvent : devicesToRemove) {
Ray Milkey269ffb92014-04-03 14:43:30 -0700942 removeDevice(deviceEvent);
Ray Milkeyb29e6262014-04-09 16:02:14 -0700943 }
Pavlin Radoslavov3c9cc552014-02-20 09:58:38 -0800944
Ray Milkey269ffb92014-04-03 14:43:30 -0700945 //
946 // Remove all Links connected to the Port
947 //
948 Set<Link> links = new HashSet<>();
949 links.add(port.getOutgoingLink());
950 links.add(port.getIncomingLink());
951 ArrayList<LinkEvent> linksToRemove = new ArrayList<>();
952 for (Link link : links) {
Ray Milkeyb29e6262014-04-09 16:02:14 -0700953 if (link == null) {
Ray Milkey269ffb92014-04-03 14:43:30 -0700954 continue;
Ray Milkeyb29e6262014-04-09 16:02:14 -0700955 }
Ray Milkey269ffb92014-04-03 14:43:30 -0700956 log.debug("Removing Link {} on Port {}", link, portEvent);
957 LinkEvent linkEvent = new LinkEvent(link.getSrcSwitch().getDpid(),
958 link.getSrcPort().getNumber(),
959 link.getDstSwitch().getDpid(),
960 link.getDstPort().getNumber());
961 linksToRemove.add(linkEvent);
962 }
Ray Milkeyb29e6262014-04-09 16:02:14 -0700963 for (LinkEvent linkEvent : linksToRemove) {
Ray Milkey269ffb92014-04-03 14:43:30 -0700964 removeLink(linkEvent);
Ray Milkeyb29e6262014-04-09 16:02:14 -0700965 }
Pavlin Radoslavov3c9cc552014-02-20 09:58:38 -0800966
Ray Milkey269ffb92014-04-03 14:43:30 -0700967 // Remove the Port from the Switch
968 SwitchImpl switchImpl = getSwitchImpl(sw);
969 switchImpl.removePort(port);
Pavlin Radoslavov74986ce2014-02-20 13:17:20 -0800970
Ray Milkey269ffb92014-04-03 14:43:30 -0700971 apiRemovedPortEvents.add(portEvent);
Pavlin Radoslavov3c9cc552014-02-20 09:58:38 -0800972 }
973
Pavlin Radoslavov734ff5a2014-02-26 10:20:43 -0800974 /**
Jonathan Harte37e4e22014-05-13 19:12:02 -0700975 * Add a link to the topology.
Pavlin Radoslavov734ff5a2014-02-26 10:20:43 -0800976 *
977 * @param linkEvent the Link Event with the link to add.
978 */
Yuta HIGUCHIbc67a052014-06-30 10:37:09 -0700979 @GuardedBy("topology.writeLock")
Pavlin Radoslavov3c9cc552014-02-20 09:58:38 -0800980 private void addLink(LinkEvent linkEvent) {
Yuta HIGUCHI8f3dfa32014-06-25 00:14:25 -0700981 Port srcPort = topology.getPort(linkEvent.getSrc().getDpid(),
982 linkEvent.getSrc().getNumber());
983 Port dstPort = topology.getPort(linkEvent.getDst().getDpid(),
984 linkEvent.getDst().getNumber());
Ray Milkey269ffb92014-04-03 14:43:30 -0700985 if ((srcPort == null) || (dstPort == null)) {
Jonathan Hartf1675202014-05-23 14:59:07 -0700986 log.debug("{} reordered because {} port is null", linkEvent,
987 (srcPort == null) ? "src" : "dst");
988
Ray Milkey269ffb92014-04-03 14:43:30 -0700989 // Reordered event: delay the event in local cache
990 ByteBuffer id = linkEvent.getIDasByteBuffer();
991 reorderedAddedLinkEvents.put(id, linkEvent);
992 return;
993 }
Pavlin Radoslavov3c9cc552014-02-20 09:58:38 -0800994
Ray Milkey269ffb92014-04-03 14:43:30 -0700995 // Get the Link instance from the Destination Port Incoming Link
996 Link link = dstPort.getIncomingLink();
997 assert (link == srcPort.getOutgoingLink());
998 if (link == null) {
Jonathan Harte37e4e22014-05-13 19:12:02 -0700999 link = new LinkImpl(topology, srcPort, dstPort);
1000 topology.putLink(link);
Pavlin Radoslavov3c9cc552014-02-20 09:58:38 -08001001
Ray Milkey269ffb92014-04-03 14:43:30 -07001002 // Remove all Devices attached to the Ports
1003 ArrayList<DeviceEvent> devicesToRemove = new ArrayList<>();
1004 ArrayList<Port> ports = new ArrayList<>();
1005 ports.add(srcPort);
1006 ports.add(dstPort);
1007 for (Port port : ports) {
1008 for (Device device : port.getDevices()) {
1009 log.error("Device {} on Port {} should have been removed prior to adding Link {}",
1010 device, port, linkEvent);
1011 DeviceEvent deviceEvent =
1012 new DeviceEvent(device.getMacAddress());
1013 SwitchPort switchPort =
1014 new SwitchPort(port.getSwitch().getDpid(),
1015 port.getNumber());
1016 deviceEvent.addAttachmentPoint(switchPort);
1017 devicesToRemove.add(deviceEvent);
1018 }
1019 }
Ray Milkeyb29e6262014-04-09 16:02:14 -07001020 for (DeviceEvent deviceEvent : devicesToRemove) {
Ray Milkey269ffb92014-04-03 14:43:30 -07001021 removeDevice(deviceEvent);
Ray Milkeyb29e6262014-04-09 16:02:14 -07001022 }
Ray Milkey269ffb92014-04-03 14:43:30 -07001023 } else {
1024 // TODO: Update the link attributes
Ray Milkey1aa71f82014-04-08 16:23:24 -07001025 log.debug("Update link attributes");
Ray Milkey269ffb92014-04-03 14:43:30 -07001026 }
Pavlin Radoslavov74986ce2014-02-20 13:17:20 -08001027
Ray Milkey269ffb92014-04-03 14:43:30 -07001028 apiAddedLinkEvents.add(linkEvent);
Pavlin Radoslavov3c9cc552014-02-20 09:58:38 -08001029 }
1030
Pavlin Radoslavov734ff5a2014-02-26 10:20:43 -08001031 /**
Jonathan Harte37e4e22014-05-13 19:12:02 -07001032 * Remove a link from the topology.
Pavlin Radoslavov734ff5a2014-02-26 10:20:43 -08001033 *
1034 * @param linkEvent the Link Event with the link to remove.
1035 */
Yuta HIGUCHIbc67a052014-06-30 10:37:09 -07001036 @GuardedBy("topology.writeLock")
Pavlin Radoslavov3c9cc552014-02-20 09:58:38 -08001037 private void removeLink(LinkEvent linkEvent) {
Yuta HIGUCHI8f3dfa32014-06-25 00:14:25 -07001038 Port srcPort = topology.getPort(linkEvent.getSrc().getDpid(),
1039 linkEvent.getSrc().getNumber());
Ray Milkey269ffb92014-04-03 14:43:30 -07001040 if (srcPort == null) {
1041 log.warn("Src Port for Link {} already removed, ignoring",
1042 linkEvent);
1043 return;
1044 }
Pavlin Radoslavov3c9cc552014-02-20 09:58:38 -08001045
Yuta HIGUCHI8f3dfa32014-06-25 00:14:25 -07001046 Port dstPort = topology.getPort(linkEvent.getDst().getDpid(),
1047 linkEvent.getDst().getNumber());
Ray Milkey269ffb92014-04-03 14:43:30 -07001048 if (dstPort == null) {
1049 log.warn("Dst Port for Link {} already removed, ignoring",
1050 linkEvent);
1051 return;
1052 }
Pavlin Radoslavov3c9cc552014-02-20 09:58:38 -08001053
Ray Milkey269ffb92014-04-03 14:43:30 -07001054 //
1055 // Remove the Link instance from the Destination Port Incoming Link
1056 // and the Source Port Outgoing Link.
1057 //
1058 Link link = dstPort.getIncomingLink();
1059 if (link == null) {
1060 log.warn("Link {} already removed on destination Port", linkEvent);
1061 }
1062 link = srcPort.getOutgoingLink();
1063 if (link == null) {
1064 log.warn("Link {} already removed on src Port", linkEvent);
1065 }
Jonathan Hart25bd53e2014-04-30 23:44:09 -07001066
1067 // TODO should we check that we get the same link from each port?
1068 if (link != null) {
Jonathan Harte37e4e22014-05-13 19:12:02 -07001069 topology.removeLink(link);
Jonathan Hart25bd53e2014-04-30 23:44:09 -07001070 }
Pavlin Radoslavov74986ce2014-02-20 13:17:20 -08001071
Ray Milkey269ffb92014-04-03 14:43:30 -07001072 apiRemovedLinkEvents.add(linkEvent);
Pavlin Radoslavov3c9cc552014-02-20 09:58:38 -08001073 }
1074
Pavlin Radoslavov734ff5a2014-02-26 10:20:43 -08001075 /**
Jonathan Harte37e4e22014-05-13 19:12:02 -07001076 * Add a device to the topology.
Ray Milkey269ffb92014-04-03 14:43:30 -07001077 * <p/>
Pavlin Radoslavov734ff5a2014-02-26 10:20:43 -08001078 * TODO: Device-related work is incomplete.
1079 * TODO: Eventually, we might need to consider reordering
1080 * or addLink() and addDevice() events on the same port.
1081 *
1082 * @param deviceEvent the Device Event with the device to add.
1083 */
Yuta HIGUCHIbc67a052014-06-30 10:37:09 -07001084 @GuardedBy("topology.writeLock")
Pavlin Radoslavov3c9cc552014-02-20 09:58:38 -08001085 private void addDevice(DeviceEvent deviceEvent) {
Jonathan Harte37e4e22014-05-13 19:12:02 -07001086 log.debug("Adding a device to the topology with mac {}", deviceEvent.getMac());
1087 Device device = topology.getDeviceByMac(deviceEvent.getMac());
Pavlin Radoslavov3c9cc552014-02-20 09:58:38 -08001088
Ray Milkey269ffb92014-04-03 14:43:30 -07001089 if (device == null) {
Jonathan Harte37e4e22014-05-13 19:12:02 -07001090 log.debug("Existing device was not found in the Topology: Adding new device: mac {}", deviceEvent.getMac());
1091 device = new DeviceImpl(topology, deviceEvent.getMac());
Ray Milkey269ffb92014-04-03 14:43:30 -07001092 }
Pavlin Radoslavov3c9cc552014-02-20 09:58:38 -08001093
Ray Milkey269ffb92014-04-03 14:43:30 -07001094 DeviceImpl deviceImpl = getDeviceImpl(device);
Pavlin Radoslavov3c9cc552014-02-20 09:58:38 -08001095
Ray Milkey269ffb92014-04-03 14:43:30 -07001096 // Process each attachment point
1097 boolean attachmentFound = false;
1098 for (SwitchPort swp : deviceEvent.getAttachmentPoints()) {
1099 // Attached Ports must exist
Yuta HIGUCHI8f3dfa32014-06-25 00:14:25 -07001100 Port port = topology.getPort(swp.getDpid(), swp.getNumber());
Ray Milkey269ffb92014-04-03 14:43:30 -07001101 if (port == null) {
1102 // Reordered event: delay the event in local cache
1103 ByteBuffer id = deviceEvent.getIDasByteBuffer();
1104 reorderedAddedDeviceEvents.put(id, deviceEvent);
1105 continue;
1106 }
1107 // Attached Ports must not have Link
1108 if (port.getOutgoingLink() != null ||
1109 port.getIncomingLink() != null) {
1110 log.warn("Link (Out:{},In:{}) exist on the attachment point, skipping mutation.",
1111 port.getOutgoingLink(),
1112 port.getIncomingLink());
1113 continue;
1114 }
1115
1116 // Add Device <-> Port attachment
1117 PortImpl portImpl = getPortImpl(port);
1118 portImpl.addDevice(device);
1119 deviceImpl.addAttachmentPoint(port);
1120 attachmentFound = true;
1121 }
1122
TeruU5d2c9392014-06-09 20:02:02 -07001123 deviceImpl.setLastSeenTime(deviceEvent.getLastSeenTime());
1124
Jonathan Harte37e4e22014-05-13 19:12:02 -07001125 // Update the device in the topology
Ray Milkey269ffb92014-04-03 14:43:30 -07001126 if (attachmentFound) {
Jonathan Harte37e4e22014-05-13 19:12:02 -07001127 log.debug("Storing the device info into the Topology: mac {}", deviceEvent.getMac());
1128 topology.putDevice(device);
Ray Milkey269ffb92014-04-03 14:43:30 -07001129 apiAddedDeviceEvents.add(deviceEvent);
1130 }
Pavlin Radoslavov3c9cc552014-02-20 09:58:38 -08001131 }
1132
Pavlin Radoslavov734ff5a2014-02-26 10:20:43 -08001133 /**
Jonathan Harte37e4e22014-05-13 19:12:02 -07001134 * Remove a device from the topology.
Ray Milkey269ffb92014-04-03 14:43:30 -07001135 * <p/>
Pavlin Radoslavov734ff5a2014-02-26 10:20:43 -08001136 * TODO: Device-related work is incomplete.
1137 *
1138 * @param deviceEvent the Device Event with the device to remove.
1139 */
Yuta HIGUCHIbc67a052014-06-30 10:37:09 -07001140 @GuardedBy("topology.writeLock")
Pavlin Radoslavov3c9cc552014-02-20 09:58:38 -08001141 private void removeDevice(DeviceEvent deviceEvent) {
Jonathan Harte37e4e22014-05-13 19:12:02 -07001142 log.debug("Removing a device to the topology: mac {}", deviceEvent.getMac());
1143 Device device = topology.getDeviceByMac(deviceEvent.getMac());
Ray Milkey269ffb92014-04-03 14:43:30 -07001144 if (device == null) {
1145 log.warn("Device {} already removed, ignoring", deviceEvent);
1146 return;
1147 }
1148 DeviceImpl deviceImpl = getDeviceImpl(device);
Pavlin Radoslavov3c9cc552014-02-20 09:58:38 -08001149
Ray Milkey269ffb92014-04-03 14:43:30 -07001150 // Process each attachment point
1151 for (SwitchPort swp : deviceEvent.getAttachmentPoints()) {
1152 // Attached Ports must exist
Yuta HIGUCHI8f3dfa32014-06-25 00:14:25 -07001153 Port port = topology.getPort(swp.getDpid(), swp.getNumber());
Ray Milkey269ffb92014-04-03 14:43:30 -07001154 if (port == null) {
1155 log.warn("Port for the attachment point {} did not exist. skipping attachment point mutation", swp);
1156 continue;
1157 }
Pavlin Radoslavov3c9cc552014-02-20 09:58:38 -08001158
Ray Milkey269ffb92014-04-03 14:43:30 -07001159 // Remove Device <-> Port attachment
1160 PortImpl portImpl = getPortImpl(port);
1161 portImpl.removeDevice(device);
1162 deviceImpl.removeAttachmentPoint(port);
1163 }
Pavlin Radoslavov74986ce2014-02-20 13:17:20 -08001164
Jonathan Harte37e4e22014-05-13 19:12:02 -07001165 log.debug("Removing the device info into the Topology: mac {}", deviceEvent.getMac());
1166 topology.removeDevice(device);
Ray Milkey269ffb92014-04-03 14:43:30 -07001167 apiRemovedDeviceEvents.add(deviceEvent);
Pavlin Radoslavov3c9cc552014-02-20 09:58:38 -08001168 }
Jonathan Hart22eb9882014-02-11 15:52:59 -08001169
Pavlin Radoslavovc1cfde52014-02-19 11:35:29 -08001170 /**
Pavlin Radoslavov734ff5a2014-02-26 10:20:43 -08001171 * Get the SwitchImpl-casted switch implementation.
Pavlin Radoslavovc1cfde52014-02-19 11:35:29 -08001172 *
Pavlin Radoslavov734ff5a2014-02-26 10:20:43 -08001173 * @param sw the Switch to cast.
1174 * @return the SwitchImpl-casted switch implementation.
Pavlin Radoslavovc1cfde52014-02-19 11:35:29 -08001175 */
Pavlin Radoslavovc1cfde52014-02-19 11:35:29 -08001176 private SwitchImpl getSwitchImpl(Switch sw) {
Ray Milkey269ffb92014-04-03 14:43:30 -07001177 if (sw instanceof SwitchImpl) {
1178 return (SwitchImpl) sw;
1179 }
1180 throw new ClassCastException("SwitchImpl expected, but found: " + sw);
Pavlin Radoslavovc1cfde52014-02-19 11:35:29 -08001181 }
1182
Pavlin Radoslavov734ff5a2014-02-26 10:20:43 -08001183 /**
1184 * Get the PortImpl-casted port implementation.
1185 *
1186 * @param port the Port to cast.
1187 * @return the PortImpl-casted port implementation.
1188 */
1189 private PortImpl getPortImpl(Port port) {
Ray Milkey269ffb92014-04-03 14:43:30 -07001190 if (port instanceof PortImpl) {
1191 return (PortImpl) port;
1192 }
1193 throw new ClassCastException("PortImpl expected, but found: " + port);
Pavlin Radoslavovc1cfde52014-02-19 11:35:29 -08001194 }
1195
Pavlin Radoslavov734ff5a2014-02-26 10:20:43 -08001196 /**
1197 * Get the LinkImpl-casted link implementation.
1198 *
1199 * @param link the Link to cast.
1200 * @return the LinkImpl-casted link implementation.
1201 */
1202 private LinkImpl getLinkImpl(Link link) {
Ray Milkey269ffb92014-04-03 14:43:30 -07001203 if (link instanceof LinkImpl) {
1204 return (LinkImpl) link;
1205 }
1206 throw new ClassCastException("LinkImpl expected, but found: " + link);
Pavlin Radoslavovc1cfde52014-02-19 11:35:29 -08001207 }
1208
Pavlin Radoslavov734ff5a2014-02-26 10:20:43 -08001209 /**
1210 * Get the DeviceImpl-casted device implementation.
1211 *
1212 * @param device the Device to cast.
1213 * @return the DeviceImpl-casted device implementation.
1214 */
1215 private DeviceImpl getDeviceImpl(Device device) {
Ray Milkey269ffb92014-04-03 14:43:30 -07001216 if (device instanceof DeviceImpl) {
1217 return (DeviceImpl) device;
1218 }
1219 throw new ClassCastException("DeviceImpl expected, but found: " + device);
Pavlin Radoslavovc1cfde52014-02-19 11:35:29 -08001220 }
1221
Pavlin Radoslavov734ff5a2014-02-26 10:20:43 -08001222 /**
1223 * Read the whole topology from the database.
1224 *
1225 * @return a collection of EventEntry-encapsulated Topology Events for
1226 * the whole topology.
1227 */
Pavlin Radoslavov018d5332014-02-19 23:08:35 -08001228 private Collection<EventEntry<TopologyEvent>> readWholeTopologyFromDB() {
Ray Milkey269ffb92014-04-03 14:43:30 -07001229 Collection<EventEntry<TopologyEvent>> collection =
1230 new LinkedList<EventEntry<TopologyEvent>>();
Pavlin Radoslavov018d5332014-02-19 23:08:35 -08001231
Ray Milkey269ffb92014-04-03 14:43:30 -07001232 // XXX May need to clear whole topology first, depending on
1233 // how we initially subscribe to replication events
Pavlin Radoslavovc1cfde52014-02-19 11:35:29 -08001234
Ray Milkey269ffb92014-04-03 14:43:30 -07001235 // Add all active switches
1236 for (KVSwitch sw : KVSwitch.getAllSwitches()) {
1237 if (sw.getStatus() != KVSwitch.STATUS.ACTIVE) {
1238 continue;
1239 }
Pavlin Radoslavov018d5332014-02-19 23:08:35 -08001240
Ray Milkey269ffb92014-04-03 14:43:30 -07001241 SwitchEvent switchEvent = new SwitchEvent(sw.getDpid());
1242 TopologyEvent topologyEvent = new TopologyEvent(switchEvent);
1243 EventEntry<TopologyEvent> eventEntry =
1244 new EventEntry<TopologyEvent>(EventEntry.Type.ENTRY_ADD,
1245 topologyEvent);
1246 collection.add(eventEntry);
1247 }
Yuta HIGUCHIa536e762014-02-17 21:47:28 -08001248
Ray Milkey269ffb92014-04-03 14:43:30 -07001249 // Add all active ports
1250 for (KVPort p : KVPort.getAllPorts()) {
1251 if (p.getStatus() != KVPort.STATUS.ACTIVE) {
1252 continue;
1253 }
Pavlin Radoslavov018d5332014-02-19 23:08:35 -08001254
Ray Milkey269ffb92014-04-03 14:43:30 -07001255 PortEvent portEvent = new PortEvent(p.getDpid(), p.getNumber());
1256 TopologyEvent topologyEvent = new TopologyEvent(portEvent);
1257 EventEntry<TopologyEvent> eventEntry =
1258 new EventEntry<TopologyEvent>(EventEntry.Type.ENTRY_ADD,
1259 topologyEvent);
1260 collection.add(eventEntry);
1261 }
Yuta HIGUCHIa536e762014-02-17 21:47:28 -08001262
TeruU28adcc32014-04-15 17:57:35 -07001263 for (KVDevice d : KVDevice.getAllDevices()) {
1264 DeviceEvent devEvent = new DeviceEvent(MACAddress.valueOf(d.getMac()));
1265 for (byte[] portId : d.getAllPortIds()) {
Jonathan Hartc00f5c22014-06-10 15:14:40 -07001266 devEvent.addAttachmentPoint(
1267 new SwitchPort(KVPort.getDpidFromKey(portId),
1268 KVPort.getNumberFromKey(portId)));
TeruU28adcc32014-04-15 17:57:35 -07001269 }
1270 }
Pavlin Radoslavovc1cfde52014-02-19 11:35:29 -08001271
Ray Milkey269ffb92014-04-03 14:43:30 -07001272 for (KVLink l : KVLink.getAllLinks()) {
1273 LinkEvent linkEvent = new LinkEvent(l.getSrc().dpid,
1274 l.getSrc().number,
1275 l.getDst().dpid,
1276 l.getDst().number);
1277 TopologyEvent topologyEvent = new TopologyEvent(linkEvent);
1278 EventEntry<TopologyEvent> eventEntry =
1279 new EventEntry<TopologyEvent>(EventEntry.Type.ENTRY_ADD,
1280 topologyEvent);
1281 collection.add(eventEntry);
1282 }
Pavlin Radoslavov018d5332014-02-19 23:08:35 -08001283
Ray Milkey269ffb92014-04-03 14:43:30 -07001284 return collection;
Pavlin Radoslavovc1cfde52014-02-19 11:35:29 -08001285 }
Jonathan Hart062a2e82014-02-03 09:41:57 -08001286}