blob: 8302ff3f769f352bfb1aa34ee4731b0985dd968e [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;
Yuta HIGUCHI8f3dfa32014-06-25 00:14:25 -070027import net.onrc.onos.core.util.Dpid;
Jonathan Hart23701d12014-04-03 10:45:48 -070028import net.onrc.onos.core.util.EventEntry;
Yuta HIGUCHI5c8cbeb2014-06-27 11:13:48 -070029import net.onrc.onos.core.util.SwitchPort;
30
Jonathan Hart062a2e82014-02-03 09:41:57 -080031import org.slf4j.Logger;
32import org.slf4j.LoggerFactory;
33
Yuta HIGUCHI181d34d2014-02-05 15:05:46 -080034/**
Jonathan Harte37e4e22014-05-13 19:12:02 -070035 * The TopologyManager receives topology updates from the southbound discovery
36 * modules and from other ONOS instances. These updates are processed and
37 * applied to the in-memory topology instance.
Ray Milkey269ffb92014-04-03 14:43:30 -070038 * <p/>
Yuta HIGUCHI4bfdd532014-02-07 13:47:36 -080039 * - Maintain Invariant/Relationships between Topology Objects.
Ray Milkey269ffb92014-04-03 14:43:30 -070040 * <p/>
Yuta HIGUCHI765cd0d2014-02-06 12:46:41 -080041 * TODO To be synchronized based on TopologyEvent Notification.
Ray Milkey269ffb92014-04-03 14:43:30 -070042 * <p/>
Yuta HIGUCHIcb951982014-02-11 13:31:44 -080043 * TODO TBD: Caller is expected to maintain parent/child calling order. Parent
Yuta HIGUCHI1c700102014-02-12 16:30:52 -080044 * Object must exist before adding sub component(Add Switch -> Port).
Ray Milkey269ffb92014-04-03 14:43:30 -070045 * <p/>
Yuta HIGUCHI4bfdd532014-02-07 13:47:36 -080046 * TODO TBD: This class may delay the requested change to handle event
47 * re-ordering. e.g.) Link Add came in, but Switch was not there.
Yuta HIGUCHI181d34d2014-02-05 15:05:46 -080048 */
Jonathan Harte37e4e22014-05-13 19:12:02 -070049public class TopologyManager implements TopologyDiscoveryInterface {
Jonathan Hart062a2e82014-02-03 09:41:57 -080050
Yuta HIGUCHI80829d12014-02-05 20:16:56 -080051 private static final Logger log = LoggerFactory
Ray Milkey269ffb92014-04-03 14:43:30 -070052 .getLogger(TopologyManager.class);
Yuta HIGUCHIcd922f42014-02-11 18:59:11 -080053
Pavlin Radoslavov721a2e02014-02-14 23:40:14 -080054 private IEventChannel<byte[], TopologyEvent> eventChannel;
Jonathan Hart10a7e2b2014-02-21 18:30:08 -080055 public static final String EVENT_CHANNEL_NAME = "onos.topology";
Pavlin Radoslavov721a2e02014-02-14 23:40:14 -080056 private EventHandler eventHandler = new EventHandler();
57
Jonathan Harte37e4e22014-05-13 19:12:02 -070058 private final TopologyDatastore datastore;
59 private final TopologyImpl topology = new TopologyImpl();
Yuta HIGUCHI170229f2014-02-17 15:47:54 -080060 private final IControllerRegistryService registryService;
Jonathan Harte37e4e22014-05-13 19:12:02 -070061 private CopyOnWriteArrayList<ITopologyListener> topologyListeners;
Yuta HIGUCHI181d34d2014-02-05 15:05:46 -080062
Pavlin Radoslavov706add22014-02-20 12:15:59 -080063 //
64 // Local state for keeping track of reordered events.
65 // NOTE: Switch Events are not affected by the event reordering.
66 //
67 private Map<ByteBuffer, PortEvent> reorderedAddedPortEvents =
Ray Milkey269ffb92014-04-03 14:43:30 -070068 new HashMap<ByteBuffer, PortEvent>();
Pavlin Radoslavov706add22014-02-20 12:15:59 -080069 private Map<ByteBuffer, LinkEvent> reorderedAddedLinkEvents =
Ray Milkey269ffb92014-04-03 14:43:30 -070070 new HashMap<ByteBuffer, LinkEvent>();
Pavlin Radoslavov706add22014-02-20 12:15:59 -080071 private Map<ByteBuffer, DeviceEvent> reorderedAddedDeviceEvents =
Ray Milkey269ffb92014-04-03 14:43:30 -070072 new HashMap<ByteBuffer, DeviceEvent>();
Pavlin Radoslavov018d5332014-02-19 23:08:35 -080073
Pavlin Radoslavov74986ce2014-02-20 13:17:20 -080074 //
Pavlin Radoslavov26d83402014-02-20 15:24:30 -080075 // Local state for keeping track of locally discovered events so we can
76 // cleanup properly when a Switch or Port is removed.
77 //
Yuta HIGUCHIbc67a052014-06-30 10:37:09 -070078 // We keep all Port, (incoming) Link and Device events per Switch DPID:
Pavlin Radoslavov26d83402014-02-20 15:24:30 -080079 // - If a switch goes down, we remove all corresponding Port, Link and
80 // Device events.
81 // - If a port on a switch goes down, we remove all corresponding Link
Yuta HIGUCHIbc67a052014-06-30 10:37:09 -070082 // and Device events discovered by this instance.
83 //
84 // How to handle side-effect of remote events.
85 // - Remote Port Down event -> Link Down
86 // Not handled. (XXX Shouldn't it be removed from discovered.. Map)
87 // - Remote Device Added -> lose ownership of Device)
88 // Not handled. (XXX Shouldn't it be removed from discovered.. Map)
89 //
90 // XXX Domain knowledge based invariant maintenance should be moved to
91 // driver module, since the invariant may be different on optical, etc.
92 //
93 // What happens on leadership change?
94 // - Probably should: remove from discovered.. Maps, but not send DELETE events
95 // XXX Switch/Port can be rediscovered by new leader, but Link, Device?
96 // - Current: There is no way to recognize leadership change?
97 // ZookeeperRegistry.requestControl(long, ControlChangeCallback)
98 // is the only way to register listener, and it allows only 1 listener,
99 // which is already used by Controller class.
100 //
101 // FIXME Replace with concurrent variant.
102 // #removeSwitchDiscoveryEvent(SwitchEvent) runs in different thread.
Pavlin Radoslavov26d83402014-02-20 15:24:30 -0800103 //
Yuta HIGUCHI8f3dfa32014-06-25 00:14:25 -0700104 private Map<Dpid, Map<ByteBuffer, PortEvent>> discoveredAddedPortEvents =
Ray Milkey269ffb92014-04-03 14:43:30 -0700105 new HashMap<>();
Yuta HIGUCHI8f3dfa32014-06-25 00:14:25 -0700106 private Map<Dpid, Map<ByteBuffer, LinkEvent>> discoveredAddedLinkEvents =
Ray Milkey269ffb92014-04-03 14:43:30 -0700107 new HashMap<>();
Yuta HIGUCHI8f3dfa32014-06-25 00:14:25 -0700108 private Map<Dpid, Map<ByteBuffer, DeviceEvent>> discoveredAddedDeviceEvents =
Ray Milkey269ffb92014-04-03 14:43:30 -0700109 new HashMap<>();
Pavlin Radoslavov26d83402014-02-20 15:24:30 -0800110
111 //
Pavlin Radoslavov74986ce2014-02-20 13:17:20 -0800112 // Local state for keeping track of the application event notifications
113 //
Yuta HIGUCHIbc67a052014-06-30 10:37:09 -0700114 // - Queue of events, which will be dispatched to local listeners
115 // on next notification.
Yuta HIGUCHI703696c2014-06-25 20:36:45 -0700116
117 private List<SwitchEvent> apiAddedSwitchEvents = new LinkedList<>();
118 private List<SwitchEvent> apiRemovedSwitchEvents = new LinkedList<>();
119 private List<PortEvent> apiAddedPortEvents = new LinkedList<>();
120 private List<PortEvent> apiRemovedPortEvents = new LinkedList<>();
121 private List<LinkEvent> apiAddedLinkEvents = new LinkedList<>();
122 private List<LinkEvent> apiRemovedLinkEvents = new LinkedList<>();
123 private List<DeviceEvent> apiAddedDeviceEvents = new LinkedList<>();
124 private List<DeviceEvent> apiRemovedDeviceEvents = new LinkedList<>();
Pavlin Radoslavov74986ce2014-02-20 13:17:20 -0800125
Pavlin Radoslavovc1cfde52014-02-19 11:35:29 -0800126 /**
127 * Constructor.
128 *
Jonathan Harte37e4e22014-05-13 19:12:02 -0700129 * @param registryService the Registry Service to use.
130 * @param topologyListeners the collection of topology listeners to use.
Pavlin Radoslavovc1cfde52014-02-19 11:35:29 -0800131 */
132 public TopologyManager(IControllerRegistryService registryService,
Jonathan Harte37e4e22014-05-13 19:12:02 -0700133 CopyOnWriteArrayList<ITopologyListener> topologyListeners) {
134 datastore = new TopologyDatastore();
Ray Milkey269ffb92014-04-03 14:43:30 -0700135 this.registryService = registryService;
Jonathan Harte37e4e22014-05-13 19:12:02 -0700136 this.topologyListeners = topologyListeners;
Yuta HIGUCHI80829d12014-02-05 20:16:56 -0800137 }
Yuta HIGUCHI181d34d2014-02-05 15:05:46 -0800138
Pavlin Radoslavovc1cfde52014-02-19 11:35:29 -0800139 /**
Jonathan Harte37e4e22014-05-13 19:12:02 -0700140 * Get the Topology.
Pavlin Radoslavovc1cfde52014-02-19 11:35:29 -0800141 *
Jonathan Harte37e4e22014-05-13 19:12:02 -0700142 * @return the Topology.
Pavlin Radoslavovc1cfde52014-02-19 11:35:29 -0800143 */
Jonathan Harte37e4e22014-05-13 19:12:02 -0700144 Topology getTopology() {
145 return topology;
Pavlin Radoslavov6d224ee2014-02-18 16:43:15 -0800146 }
147
Yuta HIGUCHI4bfdd532014-02-07 13:47:36 -0800148 /**
Pavlin Radoslavov721a2e02014-02-14 23:40:14 -0800149 * Event handler class.
150 */
151 private class EventHandler extends Thread implements
Ray Milkey269ffb92014-04-03 14:43:30 -0700152 IEventChannelListener<byte[], TopologyEvent> {
153 private BlockingQueue<EventEntry<TopologyEvent>> topologyEvents =
154 new LinkedBlockingQueue<EventEntry<TopologyEvent>>();
Pavlin Radoslavov721a2e02014-02-14 23:40:14 -0800155
Ray Milkey269ffb92014-04-03 14:43:30 -0700156 /**
157 * Startup processing.
158 */
159 private void startup() {
160 //
161 // TODO: Read all state from the database:
162 //
163 // Collection<EventEntry<TopologyEvent>> collection =
164 // readWholeTopologyFromDB();
165 //
166 // For now, as a shortcut we read it from the datagrid
167 //
Ray Milkey5df613b2014-04-15 10:50:56 -0700168 Collection<TopologyEvent> allTopologyEvents =
Ray Milkey269ffb92014-04-03 14:43:30 -0700169 eventChannel.getAllEntries();
170 Collection<EventEntry<TopologyEvent>> collection =
171 new LinkedList<EventEntry<TopologyEvent>>();
Pavlin Radoslavov721a2e02014-02-14 23:40:14 -0800172
Ray Milkey5df613b2014-04-15 10:50:56 -0700173 for (TopologyEvent topologyEvent : allTopologyEvents) {
Ray Milkey269ffb92014-04-03 14:43:30 -0700174 EventEntry<TopologyEvent> eventEntry =
175 new EventEntry<TopologyEvent>(EventEntry.Type.ENTRY_ADD,
176 topologyEvent);
177 collection.add(eventEntry);
178 }
179 processEvents(collection);
180 }
Pavlin Radoslavov721a2e02014-02-14 23:40:14 -0800181
Ray Milkey269ffb92014-04-03 14:43:30 -0700182 /**
183 * Run the thread.
184 */
185 @Override
186 public void run() {
187 Collection<EventEntry<TopologyEvent>> collection =
188 new LinkedList<EventEntry<TopologyEvent>>();
Pavlin Radoslavov721a2e02014-02-14 23:40:14 -0800189
Ray Milkey269ffb92014-04-03 14:43:30 -0700190 this.setName("TopologyManager.EventHandler " + this.getId());
191 startup();
Pavlin Radoslavov721a2e02014-02-14 23:40:14 -0800192
Ray Milkey269ffb92014-04-03 14:43:30 -0700193 //
194 // The main loop
195 //
Pavlin Radoslavov8e881a42014-06-24 16:58:07 -0700196 while (true) {
197 try {
198 EventEntry<TopologyEvent> eventEntry =
199 topologyEvents.take();
Ray Milkey269ffb92014-04-03 14:43:30 -0700200 collection.add(eventEntry);
201 topologyEvents.drainTo(collection);
Pavlin Radoslavov721a2e02014-02-14 23:40:14 -0800202
Ray Milkey269ffb92014-04-03 14:43:30 -0700203 processEvents(collection);
204 collection.clear();
Pavlin Radoslavov8e881a42014-06-24 16:58:07 -0700205 } catch (Exception exception) {
206 log.debug("Exception processing Topology Events: ",
207 exception);
Ray Milkey269ffb92014-04-03 14:43:30 -0700208 }
Ray Milkey269ffb92014-04-03 14:43:30 -0700209 }
210 }
Pavlin Radoslavov721a2e02014-02-14 23:40:14 -0800211
Ray Milkey269ffb92014-04-03 14:43:30 -0700212 /**
213 * Process all topology events.
214 *
215 * @param events the events to process.
216 */
217 private void processEvents(Collection<EventEntry<TopologyEvent>> events) {
218 // Local state for computing the final set of events
219 Map<ByteBuffer, SwitchEvent> addedSwitchEvents = new HashMap<>();
220 Map<ByteBuffer, SwitchEvent> removedSwitchEvents = new HashMap<>();
221 Map<ByteBuffer, PortEvent> addedPortEvents = new HashMap<>();
222 Map<ByteBuffer, PortEvent> removedPortEvents = new HashMap<>();
223 Map<ByteBuffer, LinkEvent> addedLinkEvents = new HashMap<>();
224 Map<ByteBuffer, LinkEvent> removedLinkEvents = new HashMap<>();
225 Map<ByteBuffer, DeviceEvent> addedDeviceEvents = new HashMap<>();
226 Map<ByteBuffer, DeviceEvent> removedDeviceEvents = new HashMap<>();
Pavlin Radoslavov3c9cc552014-02-20 09:58:38 -0800227
Ray Milkey269ffb92014-04-03 14:43:30 -0700228 //
229 // Classify and suppress matching events
230 //
231 for (EventEntry<TopologyEvent> event : events) {
232 TopologyEvent topologyEvent = event.eventData();
233 SwitchEvent switchEvent = topologyEvent.switchEvent;
234 PortEvent portEvent = topologyEvent.portEvent;
235 LinkEvent linkEvent = topologyEvent.linkEvent;
236 DeviceEvent deviceEvent = topologyEvent.deviceEvent;
Pavlin Radoslavov018d5332014-02-19 23:08:35 -0800237
Ray Milkey269ffb92014-04-03 14:43:30 -0700238 //
239 // Extract the events
240 //
241 switch (event.eventType()) {
242 case ENTRY_ADD:
243 log.debug("Topology event ENTRY_ADD: {}", topologyEvent);
244 if (switchEvent != null) {
245 ByteBuffer id = switchEvent.getIDasByteBuffer();
246 addedSwitchEvents.put(id, switchEvent);
247 removedSwitchEvents.remove(id);
248 // Switch Events are not affected by event reordering
249 }
250 if (portEvent != null) {
251 ByteBuffer id = portEvent.getIDasByteBuffer();
252 addedPortEvents.put(id, portEvent);
253 removedPortEvents.remove(id);
254 reorderedAddedPortEvents.remove(id);
255 }
256 if (linkEvent != null) {
257 ByteBuffer id = linkEvent.getIDasByteBuffer();
258 addedLinkEvents.put(id, linkEvent);
259 removedLinkEvents.remove(id);
260 reorderedAddedLinkEvents.remove(id);
261 }
262 if (deviceEvent != null) {
263 ByteBuffer id = deviceEvent.getIDasByteBuffer();
264 addedDeviceEvents.put(id, deviceEvent);
265 removedDeviceEvents.remove(id);
266 reorderedAddedDeviceEvents.remove(id);
267 }
268 break;
269 case ENTRY_REMOVE:
270 log.debug("Topology event ENTRY_REMOVE: {}", topologyEvent);
271 if (switchEvent != null) {
272 ByteBuffer id = switchEvent.getIDasByteBuffer();
273 addedSwitchEvents.remove(id);
274 removedSwitchEvents.put(id, switchEvent);
275 // Switch Events are not affected by event reordering
276 }
277 if (portEvent != null) {
278 ByteBuffer id = portEvent.getIDasByteBuffer();
279 addedPortEvents.remove(id);
280 removedPortEvents.put(id, portEvent);
281 reorderedAddedPortEvents.remove(id);
282 }
283 if (linkEvent != null) {
284 ByteBuffer id = linkEvent.getIDasByteBuffer();
285 addedLinkEvents.remove(id);
286 removedLinkEvents.put(id, linkEvent);
287 reorderedAddedLinkEvents.remove(id);
288 }
289 if (deviceEvent != null) {
290 ByteBuffer id = deviceEvent.getIDasByteBuffer();
291 addedDeviceEvents.remove(id);
292 removedDeviceEvents.put(id, deviceEvent);
293 reorderedAddedDeviceEvents.remove(id);
294 }
295 break;
Ray Milkey0b122ed2014-04-14 10:06:03 -0700296 default:
297 log.error("Unknown topology event {}",
298 event.eventType());
Ray Milkey269ffb92014-04-03 14:43:30 -0700299 }
300 }
Pavlin Radoslavov3c9cc552014-02-20 09:58:38 -0800301
Ray Milkey269ffb92014-04-03 14:43:30 -0700302 //
Jonathan Harte37e4e22014-05-13 19:12:02 -0700303 // Lock the topology while it is modified
Ray Milkey269ffb92014-04-03 14:43:30 -0700304 //
Jonathan Harte37e4e22014-05-13 19:12:02 -0700305 topology.acquireWriteLock();
Pavlin Radoslavov8ffb8bf2014-02-20 15:34:26 -0800306
Ray Milkey269ffb92014-04-03 14:43:30 -0700307 try {
308 //
309 // Apply the classified events.
310 //
311 // Apply the "add" events in the proper order:
312 // switch, port, link, device
313 //
Ray Milkeyb29e6262014-04-09 16:02:14 -0700314 for (SwitchEvent switchEvent : addedSwitchEvents.values()) {
Ray Milkey269ffb92014-04-03 14:43:30 -0700315 addSwitch(switchEvent);
Ray Milkeyb29e6262014-04-09 16:02:14 -0700316 }
317 for (PortEvent portEvent : addedPortEvents.values()) {
Ray Milkey269ffb92014-04-03 14:43:30 -0700318 addPort(portEvent);
Ray Milkeyb29e6262014-04-09 16:02:14 -0700319 }
320 for (LinkEvent linkEvent : addedLinkEvents.values()) {
Ray Milkey269ffb92014-04-03 14:43:30 -0700321 addLink(linkEvent);
Ray Milkeyb29e6262014-04-09 16:02:14 -0700322 }
323 for (DeviceEvent deviceEvent : addedDeviceEvents.values()) {
Ray Milkey269ffb92014-04-03 14:43:30 -0700324 addDevice(deviceEvent);
Ray Milkeyb29e6262014-04-09 16:02:14 -0700325 }
Ray Milkey269ffb92014-04-03 14:43:30 -0700326 //
327 // Apply the "remove" events in the reverse order:
328 // device, link, port, switch
329 //
Ray Milkeyb29e6262014-04-09 16:02:14 -0700330 for (DeviceEvent deviceEvent : removedDeviceEvents.values()) {
Ray Milkey269ffb92014-04-03 14:43:30 -0700331 removeDevice(deviceEvent);
Ray Milkeyb29e6262014-04-09 16:02:14 -0700332 }
333 for (LinkEvent linkEvent : removedLinkEvents.values()) {
Ray Milkey269ffb92014-04-03 14:43:30 -0700334 removeLink(linkEvent);
Ray Milkeyb29e6262014-04-09 16:02:14 -0700335 }
336 for (PortEvent portEvent : removedPortEvents.values()) {
Ray Milkey269ffb92014-04-03 14:43:30 -0700337 removePort(portEvent);
Ray Milkeyb29e6262014-04-09 16:02:14 -0700338 }
339 for (SwitchEvent switchEvent : removedSwitchEvents.values()) {
Ray Milkey269ffb92014-04-03 14:43:30 -0700340 removeSwitch(switchEvent);
Ray Milkeyb29e6262014-04-09 16:02:14 -0700341 }
Yuta HIGUCHI3aca81a2014-02-23 12:41:19 -0800342
Ray Milkey269ffb92014-04-03 14:43:30 -0700343 //
344 // Apply reordered events
345 //
346 applyReorderedEvents(!addedSwitchEvents.isEmpty(),
347 !addedPortEvents.isEmpty());
Yuta HIGUCHI3aca81a2014-02-23 12:41:19 -0800348
Ray Milkey269ffb92014-04-03 14:43:30 -0700349 } finally {
350 //
Jonathan Harte37e4e22014-05-13 19:12:02 -0700351 // Topology modifications completed: Release the lock
Ray Milkey269ffb92014-04-03 14:43:30 -0700352 //
Jonathan Harte37e4e22014-05-13 19:12:02 -0700353 topology.releaseWriteLock();
Ray Milkey269ffb92014-04-03 14:43:30 -0700354 }
Yuta HIGUCHI3aca81a2014-02-23 12:41:19 -0800355
Ray Milkey269ffb92014-04-03 14:43:30 -0700356 //
357 // Dispatch the Topology Notification Events to the applications
358 //
Jonathan Harte37e4e22014-05-13 19:12:02 -0700359 dispatchTopologyEvents();
Ray Milkey269ffb92014-04-03 14:43:30 -0700360 }
Pavlin Radoslavov721a2e02014-02-14 23:40:14 -0800361
Ray Milkey269ffb92014-04-03 14:43:30 -0700362 /**
363 * Receive a notification that an entry is added.
364 *
365 * @param value the value for the entry.
366 */
367 @Override
368 public void entryAdded(TopologyEvent value) {
369 EventEntry<TopologyEvent> eventEntry =
370 new EventEntry<TopologyEvent>(EventEntry.Type.ENTRY_ADD,
371 value);
372 topologyEvents.add(eventEntry);
373 }
Pavlin Radoslavov721a2e02014-02-14 23:40:14 -0800374
Ray Milkey269ffb92014-04-03 14:43:30 -0700375 /**
376 * Receive a notification that an entry is removed.
377 *
378 * @param value the value for the entry.
379 */
380 @Override
381 public void entryRemoved(TopologyEvent value) {
382 EventEntry<TopologyEvent> eventEntry =
383 new EventEntry<TopologyEvent>(EventEntry.Type.ENTRY_REMOVE,
384 value);
385 topologyEvents.add(eventEntry);
386 }
Pavlin Radoslavov721a2e02014-02-14 23:40:14 -0800387
Ray Milkey269ffb92014-04-03 14:43:30 -0700388 /**
389 * Receive a notification that an entry is updated.
390 *
391 * @param value the value for the entry.
392 */
393 @Override
394 public void entryUpdated(TopologyEvent value) {
395 // NOTE: The ADD and UPDATE events are processed in same way
396 entryAdded(value);
397 }
Pavlin Radoslavov721a2e02014-02-14 23:40:14 -0800398 }
399
400 /**
401 * Startup processing.
402 *
403 * @param datagridService the datagrid service to use.
404 */
405 void startup(IDatagridService datagridService) {
Ray Milkey269ffb92014-04-03 14:43:30 -0700406 eventChannel = datagridService.addListener(EVENT_CHANNEL_NAME,
407 eventHandler,
408 byte[].class,
409 TopologyEvent.class);
410 eventHandler.start();
Pavlin Radoslavov721a2e02014-02-14 23:40:14 -0800411 }
412
Pavlin Radoslavov74986ce2014-02-20 13:17:20 -0800413 /**
Jonathan Harte37e4e22014-05-13 19:12:02 -0700414 * Dispatch Topology Events to the listeners.
Pavlin Radoslavov74986ce2014-02-20 13:17:20 -0800415 */
Jonathan Harte37e4e22014-05-13 19:12:02 -0700416 private void dispatchTopologyEvents() {
Ray Milkey269ffb92014-04-03 14:43:30 -0700417 if (apiAddedSwitchEvents.isEmpty() &&
418 apiRemovedSwitchEvents.isEmpty() &&
419 apiAddedPortEvents.isEmpty() &&
420 apiRemovedPortEvents.isEmpty() &&
421 apiAddedLinkEvents.isEmpty() &&
422 apiRemovedLinkEvents.isEmpty() &&
423 apiAddedDeviceEvents.isEmpty() &&
424 apiRemovedDeviceEvents.isEmpty()) {
425 return; // No events to dispatch
426 }
Pavlin Radoslavov74986ce2014-02-20 13:17:20 -0800427
Ray Milkey269ffb92014-04-03 14:43:30 -0700428 if (log.isDebugEnabled()) {
429 //
430 // Debug statements
431 // TODO: Those statements should be removed in the future
432 //
Ray Milkeyb29e6262014-04-09 16:02:14 -0700433 for (SwitchEvent switchEvent : apiAddedSwitchEvents) {
Jonathan Harte37e4e22014-05-13 19:12:02 -0700434 log.debug("Dispatch Topology Event: ADDED {}", switchEvent);
Ray Milkeyb29e6262014-04-09 16:02:14 -0700435 }
436 for (SwitchEvent switchEvent : apiRemovedSwitchEvents) {
Jonathan Harte37e4e22014-05-13 19:12:02 -0700437 log.debug("Dispatch Topology Event: REMOVED {}", switchEvent);
Ray Milkeyb29e6262014-04-09 16:02:14 -0700438 }
439 for (PortEvent portEvent : apiAddedPortEvents) {
Jonathan Harte37e4e22014-05-13 19:12:02 -0700440 log.debug("Dispatch Topology Event: ADDED {}", portEvent);
Ray Milkeyb29e6262014-04-09 16:02:14 -0700441 }
442 for (PortEvent portEvent : apiRemovedPortEvents) {
Jonathan Harte37e4e22014-05-13 19:12:02 -0700443 log.debug("Dispatch Topology Event: REMOVED {}", portEvent);
Ray Milkeyb29e6262014-04-09 16:02:14 -0700444 }
445 for (LinkEvent linkEvent : apiAddedLinkEvents) {
Jonathan Harte37e4e22014-05-13 19:12:02 -0700446 log.debug("Dispatch Topology Event: ADDED {}", linkEvent);
Ray Milkeyb29e6262014-04-09 16:02:14 -0700447 }
448 for (LinkEvent linkEvent : apiRemovedLinkEvents) {
Jonathan Harte37e4e22014-05-13 19:12:02 -0700449 log.debug("Dispatch Topology Event: REMOVED {}", linkEvent);
Ray Milkeyb29e6262014-04-09 16:02:14 -0700450 }
451 for (DeviceEvent deviceEvent : apiAddedDeviceEvents) {
Jonathan Harte37e4e22014-05-13 19:12:02 -0700452 log.debug("Dispatch Topology Event: ADDED {}", deviceEvent);
Ray Milkeyb29e6262014-04-09 16:02:14 -0700453 }
454 for (DeviceEvent deviceEvent : apiRemovedDeviceEvents) {
Jonathan Harte37e4e22014-05-13 19:12:02 -0700455 log.debug("Dispatch Topology Event: REMOVED {}", deviceEvent);
Ray Milkeyb29e6262014-04-09 16:02:14 -0700456 }
Ray Milkey269ffb92014-04-03 14:43:30 -0700457 }
adminbc181552014-02-21 18:36:42 -0800458
Ray Milkey269ffb92014-04-03 14:43:30 -0700459 // Deliver the events
Jonathan Harte37e4e22014-05-13 19:12:02 -0700460 for (ITopologyListener listener : this.topologyListeners) {
Ray Milkey269ffb92014-04-03 14:43:30 -0700461 // TODO: Should copy before handing them over to listener?
Jonathan Harte37e4e22014-05-13 19:12:02 -0700462 listener.topologyEvents(apiAddedSwitchEvents,
Ray Milkey269ffb92014-04-03 14:43:30 -0700463 apiRemovedSwitchEvents,
464 apiAddedPortEvents,
465 apiRemovedPortEvents,
466 apiAddedLinkEvents,
467 apiRemovedLinkEvents,
468 apiAddedDeviceEvents,
469 apiRemovedDeviceEvents);
470 }
Pavlin Radoslavov74986ce2014-02-20 13:17:20 -0800471
Ray Milkey269ffb92014-04-03 14:43:30 -0700472 //
473 // Cleanup
474 //
475 apiAddedSwitchEvents.clear();
476 apiRemovedSwitchEvents.clear();
477 apiAddedPortEvents.clear();
478 apiRemovedPortEvents.clear();
479 apiAddedLinkEvents.clear();
480 apiRemovedLinkEvents.clear();
481 apiAddedDeviceEvents.clear();
482 apiRemovedDeviceEvents.clear();
Pavlin Radoslavov74986ce2014-02-20 13:17:20 -0800483 }
484
485 /**
486 * Apply reordered events.
487 *
488 * @param hasAddedSwitchEvents true if there were Added Switch Events.
Ray Milkey269ffb92014-04-03 14:43:30 -0700489 * @param hasAddedPortEvents true if there were Added Port Events.
Pavlin Radoslavov74986ce2014-02-20 13:17:20 -0800490 */
Yuta HIGUCHIbc67a052014-06-30 10:37:09 -0700491 @GuardedBy("topology.writeLock")
Pavlin Radoslavov74986ce2014-02-20 13:17:20 -0800492 private void applyReorderedEvents(boolean hasAddedSwitchEvents,
Ray Milkey269ffb92014-04-03 14:43:30 -0700493 boolean hasAddedPortEvents) {
Ray Milkeyb29e6262014-04-09 16:02:14 -0700494 if (!(hasAddedSwitchEvents || hasAddedPortEvents)) {
Ray Milkey269ffb92014-04-03 14:43:30 -0700495 return; // Nothing to do
Ray Milkeyb29e6262014-04-09 16:02:14 -0700496 }
Pavlin Radoslavov74986ce2014-02-20 13:17:20 -0800497
Ray Milkey269ffb92014-04-03 14:43:30 -0700498 //
499 // Try to apply the reordered events.
500 //
501 // NOTE: For simplicity we try to apply all events of a particular
502 // type if any "parent" type event was processed:
503 // - Apply reordered Port Events if Switches were added
504 // - Apply reordered Link and Device Events if Switches or Ports
505 // were added
506 //
adminbc181552014-02-21 18:36:42 -0800507
Ray Milkey269ffb92014-04-03 14:43:30 -0700508 //
509 // Apply reordered Port Events if Switches were added
510 //
511 if (hasAddedSwitchEvents) {
512 Map<ByteBuffer, PortEvent> portEvents = reorderedAddedPortEvents;
513 reorderedAddedPortEvents = new HashMap<>();
Ray Milkeyb29e6262014-04-09 16:02:14 -0700514 for (PortEvent portEvent : portEvents.values()) {
Ray Milkey269ffb92014-04-03 14:43:30 -0700515 addPort(portEvent);
Ray Milkeyb29e6262014-04-09 16:02:14 -0700516 }
Ray Milkey269ffb92014-04-03 14:43:30 -0700517 }
518 //
519 // Apply reordered Link and Device Events if Switches or Ports
520 // were added.
521 //
522 Map<ByteBuffer, LinkEvent> linkEvents = reorderedAddedLinkEvents;
523 reorderedAddedLinkEvents = new HashMap<>();
Ray Milkeyb29e6262014-04-09 16:02:14 -0700524 for (LinkEvent linkEvent : linkEvents.values()) {
Ray Milkey269ffb92014-04-03 14:43:30 -0700525 addLink(linkEvent);
Ray Milkeyb29e6262014-04-09 16:02:14 -0700526 }
Ray Milkey269ffb92014-04-03 14:43:30 -0700527 //
528 Map<ByteBuffer, DeviceEvent> deviceEvents = reorderedAddedDeviceEvents;
529 reorderedAddedDeviceEvents = new HashMap<>();
Ray Milkeyb29e6262014-04-09 16:02:14 -0700530 for (DeviceEvent deviceEvent : deviceEvents.values()) {
Ray Milkey269ffb92014-04-03 14:43:30 -0700531 addDevice(deviceEvent);
Ray Milkeyb29e6262014-04-09 16:02:14 -0700532 }
Pavlin Radoslavov74986ce2014-02-20 13:17:20 -0800533 }
534
Pavlin Radoslavov734ff5a2014-02-26 10:20:43 -0800535 /**
536 * Switch discovered event.
537 *
538 * @param switchEvent the switch event.
Ray Milkey269ffb92014-04-03 14:43:30 -0700539 * @param portEvents the corresponding port events for the switch.
Pavlin Radoslavov734ff5a2014-02-26 10:20:43 -0800540 */
Pavlin Radoslavovc1cfde52014-02-19 11:35:29 -0800541 @Override
Pavlin Radoslavov018d5332014-02-19 23:08:35 -0800542 public void putSwitchDiscoveryEvent(SwitchEvent switchEvent,
Ray Milkey269ffb92014-04-03 14:43:30 -0700543 Collection<PortEvent> portEvents) {
544 if (datastore.addSwitch(switchEvent, portEvents)) {
Jonathan Hart92c819f2014-05-30 10:53:30 -0700545 log.debug("Sending add switch: {}", switchEvent);
Ray Milkey269ffb92014-04-03 14:43:30 -0700546 // Send out notification
547 TopologyEvent topologyEvent = new TopologyEvent(switchEvent);
548 eventChannel.addEntry(topologyEvent.getID(), topologyEvent);
Pavlin Radoslavov26d83402014-02-20 15:24:30 -0800549
Ray Milkey269ffb92014-04-03 14:43:30 -0700550 // Send out notification for each port
551 for (PortEvent portEvent : portEvents) {
Jonathan Hart92c819f2014-05-30 10:53:30 -0700552 log.debug("Sending add port: {}", portEvent);
Ray Milkey269ffb92014-04-03 14:43:30 -0700553 topologyEvent = new TopologyEvent(portEvent);
554 eventChannel.addEntry(topologyEvent.getID(), topologyEvent);
555 }
Pavlin Radoslavov26d83402014-02-20 15:24:30 -0800556
Ray Milkey269ffb92014-04-03 14:43:30 -0700557 //
558 // Keep track of the added ports
559 //
560 // Get the old Port Events
561 Map<ByteBuffer, PortEvent> oldPortEvents =
562 discoveredAddedPortEvents.get(switchEvent.getDpid());
Ray Milkeyb29e6262014-04-09 16:02:14 -0700563 if (oldPortEvents == null) {
Ray Milkey269ffb92014-04-03 14:43:30 -0700564 oldPortEvents = new HashMap<>();
Ray Milkeyb29e6262014-04-09 16:02:14 -0700565 }
Pavlin Radoslavov26d83402014-02-20 15:24:30 -0800566
Ray Milkey269ffb92014-04-03 14:43:30 -0700567 // Store the new Port Events in the local cache
568 Map<ByteBuffer, PortEvent> newPortEvents = new HashMap<>();
569 for (PortEvent portEvent : portEvents) {
570 ByteBuffer id = portEvent.getIDasByteBuffer();
571 newPortEvents.put(id, portEvent);
572 }
573 discoveredAddedPortEvents.put(switchEvent.getDpid(),
574 newPortEvents);
Pavlin Radoslavov26d83402014-02-20 15:24:30 -0800575
Ray Milkey269ffb92014-04-03 14:43:30 -0700576 //
577 // Extract the removed ports
578 //
579 List<PortEvent> removedPortEvents = new LinkedList<>();
580 for (Map.Entry<ByteBuffer, PortEvent> entry : oldPortEvents.entrySet()) {
581 ByteBuffer key = entry.getKey();
582 PortEvent portEvent = entry.getValue();
Ray Milkeyb29e6262014-04-09 16:02:14 -0700583 if (!newPortEvents.containsKey(key)) {
Ray Milkey269ffb92014-04-03 14:43:30 -0700584 removedPortEvents.add(portEvent);
Ray Milkeyb29e6262014-04-09 16:02:14 -0700585 }
Ray Milkey269ffb92014-04-03 14:43:30 -0700586 }
587
588 // Cleanup old removed ports
Ray Milkeyb29e6262014-04-09 16:02:14 -0700589 for (PortEvent portEvent : removedPortEvents) {
Ray Milkey269ffb92014-04-03 14:43:30 -0700590 removePortDiscoveryEvent(portEvent);
Ray Milkeyb29e6262014-04-09 16:02:14 -0700591 }
Ray Milkey269ffb92014-04-03 14:43:30 -0700592 }
Pavlin Radoslavovc1cfde52014-02-19 11:35:29 -0800593 }
594
Pavlin Radoslavov734ff5a2014-02-26 10:20:43 -0800595 /**
Yuta HIGUCHIbc67a052014-06-30 10:37:09 -0700596 * {@inheritDoc}
597 * <p/>
598 * Called by {@link TopologyPublisher.SwitchCleanup} thread.
Pavlin Radoslavov734ff5a2014-02-26 10:20:43 -0800599 */
Pavlin Radoslavovc1cfde52014-02-19 11:35:29 -0800600 @Override
Pavlin Radoslavov6ea84a42014-02-19 15:50:01 -0800601 public void removeSwitchDiscoveryEvent(SwitchEvent switchEvent) {
Ray Milkey269ffb92014-04-03 14:43:30 -0700602 // Get the old Port Events
603 Map<ByteBuffer, PortEvent> oldPortEvents =
604 discoveredAddedPortEvents.get(switchEvent.getDpid());
Ray Milkeyb29e6262014-04-09 16:02:14 -0700605 if (oldPortEvents == null) {
Ray Milkey269ffb92014-04-03 14:43:30 -0700606 oldPortEvents = new HashMap<>();
Ray Milkeyb29e6262014-04-09 16:02:14 -0700607 }
Pavlin Radoslavov018d5332014-02-19 23:08:35 -0800608
Ray Milkey269ffb92014-04-03 14:43:30 -0700609 if (datastore.deactivateSwitch(switchEvent, oldPortEvents.values())) {
Jonathan Hart92c819f2014-05-30 10:53:30 -0700610 log.debug("Sending remove switch: {}", switchEvent);
Ray Milkey269ffb92014-04-03 14:43:30 -0700611 // Send out notification
612 eventChannel.removeEntry(switchEvent.getID());
Pavlin Radoslavov018d5332014-02-19 23:08:35 -0800613
Ray Milkey269ffb92014-04-03 14:43:30 -0700614 //
615 // Send out notification for each port.
616 //
617 // NOTE: We don't use removePortDiscoveryEvent() for the cleanup,
618 // because it will attempt to remove the port from the database,
619 // and the deactiveSwitch() call above already removed all ports.
620 //
Ray Milkeyb29e6262014-04-09 16:02:14 -0700621 for (PortEvent portEvent : oldPortEvents.values()) {
Jonathan Hart92c819f2014-05-30 10:53:30 -0700622 log.debug("Sending remove port:", portEvent);
Ray Milkey269ffb92014-04-03 14:43:30 -0700623 eventChannel.removeEntry(portEvent.getID());
Ray Milkeyb29e6262014-04-09 16:02:14 -0700624 }
Ray Milkey269ffb92014-04-03 14:43:30 -0700625 discoveredAddedPortEvents.remove(switchEvent.getDpid());
Pavlin Radoslavov26d83402014-02-20 15:24:30 -0800626
Ray Milkey269ffb92014-04-03 14:43:30 -0700627 // Cleanup for each link
628 Map<ByteBuffer, LinkEvent> oldLinkEvents =
629 discoveredAddedLinkEvents.get(switchEvent.getDpid());
630 if (oldLinkEvents != null) {
631 for (LinkEvent linkEvent : new ArrayList<>(oldLinkEvents.values())) {
632 removeLinkDiscoveryEvent(linkEvent);
633 }
634 discoveredAddedLinkEvents.remove(switchEvent.getDpid());
635 }
Pavlin Radoslavov26d83402014-02-20 15:24:30 -0800636
Ray Milkey269ffb92014-04-03 14:43:30 -0700637 // Cleanup for each device
638 Map<ByteBuffer, DeviceEvent> oldDeviceEvents =
639 discoveredAddedDeviceEvents.get(switchEvent.getDpid());
640 if (oldDeviceEvents != null) {
641 for (DeviceEvent deviceEvent : new ArrayList<>(oldDeviceEvents.values())) {
642 removeDeviceDiscoveryEvent(deviceEvent);
643 }
644 discoveredAddedDeviceEvents.remove(switchEvent.getDpid());
645 }
646 }
Pavlin Radoslavovc1cfde52014-02-19 11:35:29 -0800647 }
648
Pavlin Radoslavov734ff5a2014-02-26 10:20:43 -0800649 /**
650 * Port discovered event.
651 *
652 * @param portEvent the port event.
653 */
Pavlin Radoslavovc1cfde52014-02-19 11:35:29 -0800654 @Override
Pavlin Radoslavov6ea84a42014-02-19 15:50:01 -0800655 public void putPortDiscoveryEvent(PortEvent portEvent) {
Ray Milkey269ffb92014-04-03 14:43:30 -0700656 if (datastore.addPort(portEvent)) {
Jonathan Hart92c819f2014-05-30 10:53:30 -0700657 log.debug("Sending add port: {}", portEvent);
Ray Milkey269ffb92014-04-03 14:43:30 -0700658 // Send out notification
659 TopologyEvent topologyEvent = new TopologyEvent(portEvent);
660 eventChannel.addEntry(topologyEvent.getID(), topologyEvent);
Pavlin Radoslavov26d83402014-02-20 15:24:30 -0800661
Ray Milkey269ffb92014-04-03 14:43:30 -0700662 // Store the new Port Event in the local cache
663 Map<ByteBuffer, PortEvent> oldPortEvents =
664 discoveredAddedPortEvents.get(portEvent.getDpid());
665 if (oldPortEvents == null) {
666 oldPortEvents = new HashMap<>();
667 discoveredAddedPortEvents.put(portEvent.getDpid(),
668 oldPortEvents);
669 }
670 ByteBuffer id = portEvent.getIDasByteBuffer();
671 oldPortEvents.put(id, portEvent);
672 }
Pavlin Radoslavovc1cfde52014-02-19 11:35:29 -0800673 }
674
Pavlin Radoslavov734ff5a2014-02-26 10:20:43 -0800675 /**
676 * Port removed event.
677 *
678 * @param portEvent the port event.
679 */
Pavlin Radoslavovc1cfde52014-02-19 11:35:29 -0800680 @Override
Pavlin Radoslavov6ea84a42014-02-19 15:50:01 -0800681 public void removePortDiscoveryEvent(PortEvent portEvent) {
Ray Milkey269ffb92014-04-03 14:43:30 -0700682 if (datastore.deactivatePort(portEvent)) {
Jonathan Hart92c819f2014-05-30 10:53:30 -0700683 log.debug("Sending remove port: {}", portEvent);
Ray Milkey269ffb92014-04-03 14:43:30 -0700684 // Send out notification
685 eventChannel.removeEntry(portEvent.getID());
Pavlin Radoslavov26d83402014-02-20 15:24:30 -0800686
Ray Milkey269ffb92014-04-03 14:43:30 -0700687 // Cleanup the Port Event from the local cache
688 Map<ByteBuffer, PortEvent> oldPortEvents =
689 discoveredAddedPortEvents.get(portEvent.getDpid());
690 if (oldPortEvents != null) {
691 ByteBuffer id = portEvent.getIDasByteBuffer();
692 oldPortEvents.remove(id);
693 }
Pavlin Radoslavov26d83402014-02-20 15:24:30 -0800694
Ray Milkey269ffb92014-04-03 14:43:30 -0700695 // Cleanup for the incoming link
696 Map<ByteBuffer, LinkEvent> oldLinkEvents =
697 discoveredAddedLinkEvents.get(portEvent.getDpid());
698 if (oldLinkEvents != null) {
699 for (LinkEvent linkEvent : new ArrayList<>(oldLinkEvents.values())) {
700 if (linkEvent.getDst().equals(portEvent.id)) {
701 removeLinkDiscoveryEvent(linkEvent);
702 // XXX If we change our model to allow multiple Link on
703 // a Port, this loop must be fixed to allow continuing.
704 break;
705 }
706 }
707 }
Pavlin Radoslavov26d83402014-02-20 15:24:30 -0800708
Ray Milkey269ffb92014-04-03 14:43:30 -0700709 // Cleanup for the connected devices
710 // TODO: The implementation below is probably wrong
711 List<DeviceEvent> removedDeviceEvents = new LinkedList<>();
712 Map<ByteBuffer, DeviceEvent> oldDeviceEvents =
713 discoveredAddedDeviceEvents.get(portEvent.getDpid());
714 if (oldDeviceEvents != null) {
715 for (DeviceEvent deviceEvent : new ArrayList<>(oldDeviceEvents.values())) {
716 for (SwitchPort swp : deviceEvent.getAttachmentPoints()) {
717 if (swp.equals(portEvent.id)) {
718 removedDeviceEvents.add(deviceEvent);
719 }
720 }
721 }
Ray Milkeyb29e6262014-04-09 16:02:14 -0700722 for (DeviceEvent deviceEvent : removedDeviceEvents) {
Ray Milkey269ffb92014-04-03 14:43:30 -0700723 removeDeviceDiscoveryEvent(deviceEvent);
Ray Milkeyb29e6262014-04-09 16:02:14 -0700724 }
Ray Milkey269ffb92014-04-03 14:43:30 -0700725 }
726 }
Pavlin Radoslavovc1cfde52014-02-19 11:35:29 -0800727 }
728
Pavlin Radoslavov734ff5a2014-02-26 10:20:43 -0800729 /**
730 * Link discovered event.
731 *
732 * @param linkEvent the link event.
733 */
Pavlin Radoslavovc1cfde52014-02-19 11:35:29 -0800734 @Override
Pavlin Radoslavov6ea84a42014-02-19 15:50:01 -0800735 public void putLinkDiscoveryEvent(LinkEvent linkEvent) {
Ray Milkey269ffb92014-04-03 14:43:30 -0700736 if (datastore.addLink(linkEvent)) {
Jonathan Hart92c819f2014-05-30 10:53:30 -0700737 log.debug("Sending add link: {}", linkEvent);
Ray Milkey269ffb92014-04-03 14:43:30 -0700738 // Send out notification
739 TopologyEvent topologyEvent = new TopologyEvent(linkEvent);
740 eventChannel.addEntry(topologyEvent.getID(), topologyEvent);
Pavlin Radoslavov26d83402014-02-20 15:24:30 -0800741
Ray Milkey269ffb92014-04-03 14:43:30 -0700742 // Store the new Link Event in the local cache
743 Map<ByteBuffer, LinkEvent> oldLinkEvents =
744 discoveredAddedLinkEvents.get(linkEvent.getDst().getDpid());
745 if (oldLinkEvents == null) {
746 oldLinkEvents = new HashMap<>();
747 discoveredAddedLinkEvents.put(linkEvent.getDst().getDpid(),
748 oldLinkEvents);
749 }
750 ByteBuffer id = linkEvent.getIDasByteBuffer();
751 oldLinkEvents.put(id, linkEvent);
752 }
Pavlin Radoslavovc1cfde52014-02-19 11:35:29 -0800753 }
754
Pavlin Radoslavov734ff5a2014-02-26 10:20:43 -0800755 /**
756 * Link removed event.
757 *
758 * @param linkEvent the link event.
759 */
Pavlin Radoslavovc1cfde52014-02-19 11:35:29 -0800760 @Override
Pavlin Radoslavov6ea84a42014-02-19 15:50:01 -0800761 public void removeLinkDiscoveryEvent(LinkEvent linkEvent) {
Ray Milkey269ffb92014-04-03 14:43:30 -0700762 if (datastore.removeLink(linkEvent)) {
Jonathan Hart92c819f2014-05-30 10:53:30 -0700763 log.debug("Sending remove link: {}", linkEvent);
Ray Milkey269ffb92014-04-03 14:43:30 -0700764 // Send out notification
765 eventChannel.removeEntry(linkEvent.getID());
Pavlin Radoslavov26d83402014-02-20 15:24:30 -0800766
Ray Milkey269ffb92014-04-03 14:43:30 -0700767 // Cleanup the Link Event from the local cache
768 Map<ByteBuffer, LinkEvent> oldLinkEvents =
769 discoveredAddedLinkEvents.get(linkEvent.getDst().getDpid());
770 if (oldLinkEvents != null) {
771 ByteBuffer id = linkEvent.getIDasByteBuffer();
772 oldLinkEvents.remove(id);
773 }
774 }
Pavlin Radoslavovc1cfde52014-02-19 11:35:29 -0800775 }
Jonathan Hart22eb9882014-02-11 15:52:59 -0800776
Pavlin Radoslavov734ff5a2014-02-26 10:20:43 -0800777 /**
778 * Device discovered event.
779 *
780 * @param deviceEvent the device event.
781 */
Pavlin Radoslavovc1cfde52014-02-19 11:35:29 -0800782 @Override
Pavlin Radoslavov6ea84a42014-02-19 15:50:01 -0800783 public void putDeviceDiscoveryEvent(DeviceEvent deviceEvent) {
Ray Milkey269ffb92014-04-03 14:43:30 -0700784 if (datastore.addDevice(deviceEvent)) {
785 // Send out notification
786 TopologyEvent topologyEvent = new TopologyEvent(deviceEvent);
787 eventChannel.addEntry(topologyEvent.getID(), topologyEvent);
Jonathan Harte37e4e22014-05-13 19:12:02 -0700788 log.debug("Put the device info into the cache of the topology. mac {}", deviceEvent.getMac());
Ray Milkey269ffb92014-04-03 14:43:30 -0700789
790 // Store the new Device Event in the local cache
791 // TODO: The implementation below is probably wrong
792 for (SwitchPort swp : deviceEvent.getAttachmentPoints()) {
793 Map<ByteBuffer, DeviceEvent> oldDeviceEvents =
794 discoveredAddedDeviceEvents.get(swp.getDpid());
795 if (oldDeviceEvents == null) {
796 oldDeviceEvents = new HashMap<>();
797 discoveredAddedDeviceEvents.put(swp.getDpid(),
798 oldDeviceEvents);
799 }
800 ByteBuffer id = deviceEvent.getIDasByteBuffer();
801 oldDeviceEvents.put(id, deviceEvent);
802 }
803 }
Pavlin Radoslavovc1cfde52014-02-19 11:35:29 -0800804 }
Jonathan Hart22eb9882014-02-11 15:52:59 -0800805
Pavlin Radoslavov734ff5a2014-02-26 10:20:43 -0800806 /**
807 * Device removed event.
808 *
809 * @param deviceEvent the device event.
810 */
Pavlin Radoslavovc1cfde52014-02-19 11:35:29 -0800811 @Override
Pavlin Radoslavov6ea84a42014-02-19 15:50:01 -0800812 public void removeDeviceDiscoveryEvent(DeviceEvent deviceEvent) {
Ray Milkey269ffb92014-04-03 14:43:30 -0700813 if (datastore.removeDevice(deviceEvent)) {
814 // Send out notification
815 eventChannel.removeEntry(deviceEvent.getID());
Jonathan Harte37e4e22014-05-13 19:12:02 -0700816 log.debug("Remove the device info into the cache of the topology. mac {}", deviceEvent.getMac());
Pavlin Radoslavov26d83402014-02-20 15:24:30 -0800817
Ray Milkey269ffb92014-04-03 14:43:30 -0700818 // Cleanup the Device Event from the local cache
819 // TODO: The implementation below is probably wrong
820 ByteBuffer id = ByteBuffer.wrap(deviceEvent.getID());
821 for (SwitchPort swp : deviceEvent.getAttachmentPoints()) {
822 Map<ByteBuffer, DeviceEvent> oldDeviceEvents =
823 discoveredAddedDeviceEvents.get(swp.getDpid());
824 if (oldDeviceEvents != null) {
825 oldDeviceEvents.remove(id);
826 }
827 }
828 }
Pavlin Radoslavovc1cfde52014-02-19 11:35:29 -0800829 }
Jonathan Hart22eb9882014-02-11 15:52:59 -0800830
Pavlin Radoslavov734ff5a2014-02-26 10:20:43 -0800831 /**
Jonathan Harte37e4e22014-05-13 19:12:02 -0700832 * Add a switch to the topology.
Pavlin Radoslavov734ff5a2014-02-26 10:20:43 -0800833 *
834 * @param switchEvent the Switch Event with the switch to add.
835 */
Yuta HIGUCHIbc67a052014-06-30 10:37:09 -0700836 @GuardedBy("topology.writeLock")
Pavlin Radoslavov74986ce2014-02-20 13:17:20 -0800837 private void addSwitch(SwitchEvent switchEvent) {
Jonathan Harte37e4e22014-05-13 19:12:02 -0700838 Switch sw = topology.getSwitch(switchEvent.getDpid());
Ray Milkey269ffb92014-04-03 14:43:30 -0700839 if (sw == null) {
Jonathan Harte37e4e22014-05-13 19:12:02 -0700840 sw = new SwitchImpl(topology, switchEvent.getDpid());
841 topology.putSwitch(sw);
Ray Milkey269ffb92014-04-03 14:43:30 -0700842 } else {
843 // TODO: Update the switch attributes
844 // TODO: Nothing to do for now
Ray Milkey1aa71f82014-04-08 16:23:24 -0700845 log.debug("Update switch attributes");
Ray Milkey269ffb92014-04-03 14:43:30 -0700846 }
847 apiAddedSwitchEvents.add(switchEvent);
Pavlin Radoslavov3c9cc552014-02-20 09:58:38 -0800848 }
849
Pavlin Radoslavov734ff5a2014-02-26 10:20:43 -0800850 /**
Jonathan Harte37e4e22014-05-13 19:12:02 -0700851 * Remove a switch from the topology.
Pavlin Radoslavov734ff5a2014-02-26 10:20:43 -0800852 *
853 * @param switchEvent the Switch Event with the switch to remove.
854 */
Yuta HIGUCHIbc67a052014-06-30 10:37:09 -0700855 @GuardedBy("topology.writeLock")
Pavlin Radoslavov74986ce2014-02-20 13:17:20 -0800856 private void removeSwitch(SwitchEvent switchEvent) {
Jonathan Harte37e4e22014-05-13 19:12:02 -0700857 Switch sw = topology.getSwitch(switchEvent.getDpid());
Ray Milkey269ffb92014-04-03 14:43:30 -0700858 if (sw == null) {
859 log.warn("Switch {} already removed, ignoring", switchEvent);
860 return;
861 }
Pavlin Radoslavov3c9cc552014-02-20 09:58:38 -0800862
Ray Milkey269ffb92014-04-03 14:43:30 -0700863 //
864 // Remove all Ports on the Switch
865 //
866 ArrayList<PortEvent> portsToRemove = new ArrayList<>();
867 for (Port port : sw.getPorts()) {
868 log.warn("Port {} on Switch {} should be removed prior to removing Switch. Removing Port now.",
869 port, switchEvent);
870 PortEvent portEvent = new PortEvent(port.getDpid(),
871 port.getNumber());
872 portsToRemove.add(portEvent);
873 }
Ray Milkeyb29e6262014-04-09 16:02:14 -0700874 for (PortEvent portEvent : portsToRemove) {
Ray Milkey269ffb92014-04-03 14:43:30 -0700875 removePort(portEvent);
Ray Milkeyb29e6262014-04-09 16:02:14 -0700876 }
Pavlin Radoslavov3c9cc552014-02-20 09:58:38 -0800877
Jonathan Harte37e4e22014-05-13 19:12:02 -0700878 topology.removeSwitch(switchEvent.getDpid());
Ray Milkey269ffb92014-04-03 14:43:30 -0700879 apiRemovedSwitchEvents.add(switchEvent);
Pavlin Radoslavov3c9cc552014-02-20 09:58:38 -0800880 }
881
Pavlin Radoslavov734ff5a2014-02-26 10:20:43 -0800882 /**
Jonathan Harte37e4e22014-05-13 19:12:02 -0700883 * Add a port to the topology.
Pavlin Radoslavov734ff5a2014-02-26 10:20:43 -0800884 *
885 * @param portEvent the Port Event with the port to add.
886 */
Yuta HIGUCHIbc67a052014-06-30 10:37:09 -0700887 @GuardedBy("topology.writeLock")
Pavlin Radoslavov3c9cc552014-02-20 09:58:38 -0800888 private void addPort(PortEvent portEvent) {
Jonathan Harte37e4e22014-05-13 19:12:02 -0700889 Switch sw = topology.getSwitch(portEvent.getDpid());
Ray Milkey269ffb92014-04-03 14:43:30 -0700890 if (sw == null) {
Jonathan Hartf1675202014-05-23 14:59:07 -0700891 log.debug("{} reordered because switch is null", portEvent);
Ray Milkey269ffb92014-04-03 14:43:30 -0700892 // Reordered event: delay the event in local cache
893 ByteBuffer id = portEvent.getIDasByteBuffer();
894 reorderedAddedPortEvents.put(id, portEvent);
895 return;
896 }
897 SwitchImpl switchImpl = getSwitchImpl(sw);
Pavlin Radoslavov3c9cc552014-02-20 09:58:38 -0800898
Yuta HIGUCHIb1e2ab72014-06-30 11:01:31 -0700899 Port port = sw.getPort(portEvent.getPortNumber());
Ray Milkey269ffb92014-04-03 14:43:30 -0700900 if (port == null) {
Yuta HIGUCHIb1e2ab72014-06-30 11:01:31 -0700901 port = new PortImpl(topology, sw, portEvent.getPortNumber());
Ray Milkey269ffb92014-04-03 14:43:30 -0700902 switchImpl.addPort(port);
903 } else {
904 // TODO: Update the port attributes
Ray Milkey1aa71f82014-04-08 16:23:24 -0700905 log.debug("Update port attributes");
Ray Milkey269ffb92014-04-03 14:43:30 -0700906 }
907 apiAddedPortEvents.add(portEvent);
Pavlin Radoslavov3c9cc552014-02-20 09:58:38 -0800908 }
909
Pavlin Radoslavov734ff5a2014-02-26 10:20:43 -0800910 /**
Jonathan Harte37e4e22014-05-13 19:12:02 -0700911 * Remove a port from the topology.
Pavlin Radoslavov734ff5a2014-02-26 10:20:43 -0800912 *
913 * @param portEvent the Port Event with the port to remove.
914 */
Yuta HIGUCHIbc67a052014-06-30 10:37:09 -0700915 @GuardedBy("topology.writeLock")
Pavlin Radoslavov3c9cc552014-02-20 09:58:38 -0800916 private void removePort(PortEvent portEvent) {
Jonathan Harte37e4e22014-05-13 19:12:02 -0700917 Switch sw = topology.getSwitch(portEvent.getDpid());
Ray Milkey269ffb92014-04-03 14:43:30 -0700918 if (sw == null) {
919 log.warn("Parent Switch for Port {} already removed, ignoring",
920 portEvent);
921 return;
922 }
Pavlin Radoslavov3c9cc552014-02-20 09:58:38 -0800923
Yuta HIGUCHIb1e2ab72014-06-30 11:01:31 -0700924 Port port = sw.getPort(portEvent.getPortNumber());
Ray Milkey269ffb92014-04-03 14:43:30 -0700925 if (port == null) {
926 log.warn("Port {} already removed, ignoring", portEvent);
927 return;
928 }
Pavlin Radoslavov3c9cc552014-02-20 09:58:38 -0800929
Ray Milkey269ffb92014-04-03 14:43:30 -0700930 //
931 // Remove all Devices attached to the Port
932 //
933 ArrayList<DeviceEvent> devicesToRemove = new ArrayList<>();
934 for (Device device : port.getDevices()) {
935 log.debug("Removing Device {} on Port {}", device, portEvent);
936 DeviceEvent deviceEvent = new DeviceEvent(device.getMacAddress());
937 SwitchPort switchPort = new SwitchPort(port.getSwitch().getDpid(),
938 port.getNumber());
939 deviceEvent.addAttachmentPoint(switchPort);
940 devicesToRemove.add(deviceEvent);
941 }
Ray Milkeyb29e6262014-04-09 16:02:14 -0700942 for (DeviceEvent deviceEvent : devicesToRemove) {
Ray Milkey269ffb92014-04-03 14:43:30 -0700943 removeDevice(deviceEvent);
Ray Milkeyb29e6262014-04-09 16:02:14 -0700944 }
Pavlin Radoslavov3c9cc552014-02-20 09:58:38 -0800945
Ray Milkey269ffb92014-04-03 14:43:30 -0700946 //
947 // Remove all Links connected to the Port
948 //
949 Set<Link> links = new HashSet<>();
950 links.add(port.getOutgoingLink());
951 links.add(port.getIncomingLink());
952 ArrayList<LinkEvent> linksToRemove = new ArrayList<>();
953 for (Link link : links) {
Ray Milkeyb29e6262014-04-09 16:02:14 -0700954 if (link == null) {
Ray Milkey269ffb92014-04-03 14:43:30 -0700955 continue;
Ray Milkeyb29e6262014-04-09 16:02:14 -0700956 }
Ray Milkey269ffb92014-04-03 14:43:30 -0700957 log.debug("Removing Link {} on Port {}", link, portEvent);
958 LinkEvent linkEvent = new LinkEvent(link.getSrcSwitch().getDpid(),
959 link.getSrcPort().getNumber(),
960 link.getDstSwitch().getDpid(),
961 link.getDstPort().getNumber());
962 linksToRemove.add(linkEvent);
963 }
Ray Milkeyb29e6262014-04-09 16:02:14 -0700964 for (LinkEvent linkEvent : linksToRemove) {
Ray Milkey269ffb92014-04-03 14:43:30 -0700965 removeLink(linkEvent);
Ray Milkeyb29e6262014-04-09 16:02:14 -0700966 }
Pavlin Radoslavov3c9cc552014-02-20 09:58:38 -0800967
Ray Milkey269ffb92014-04-03 14:43:30 -0700968 // Remove the Port from the Switch
969 SwitchImpl switchImpl = getSwitchImpl(sw);
970 switchImpl.removePort(port);
Pavlin Radoslavov74986ce2014-02-20 13:17:20 -0800971
Ray Milkey269ffb92014-04-03 14:43:30 -0700972 apiRemovedPortEvents.add(portEvent);
Pavlin Radoslavov3c9cc552014-02-20 09:58:38 -0800973 }
974
Pavlin Radoslavov734ff5a2014-02-26 10:20:43 -0800975 /**
Jonathan Harte37e4e22014-05-13 19:12:02 -0700976 * Add a link to the topology.
Pavlin Radoslavov734ff5a2014-02-26 10:20:43 -0800977 *
978 * @param linkEvent the Link Event with the link to add.
979 */
Yuta HIGUCHIbc67a052014-06-30 10:37:09 -0700980 @GuardedBy("topology.writeLock")
Pavlin Radoslavov3c9cc552014-02-20 09:58:38 -0800981 private void addLink(LinkEvent linkEvent) {
Yuta HIGUCHI8f3dfa32014-06-25 00:14:25 -0700982 Port srcPort = topology.getPort(linkEvent.getSrc().getDpid(),
Yuta HIGUCHIb1e2ab72014-06-30 11:01:31 -0700983 linkEvent.getSrc().getPortNumber());
Yuta HIGUCHI8f3dfa32014-06-25 00:14:25 -0700984 Port dstPort = topology.getPort(linkEvent.getDst().getDpid(),
Yuta HIGUCHIb1e2ab72014-06-30 11:01:31 -0700985 linkEvent.getDst().getPortNumber());
Ray Milkey269ffb92014-04-03 14:43:30 -0700986 if ((srcPort == null) || (dstPort == null)) {
Jonathan Hartf1675202014-05-23 14:59:07 -0700987 log.debug("{} reordered because {} port is null", linkEvent,
988 (srcPort == null) ? "src" : "dst");
989
Ray Milkey269ffb92014-04-03 14:43:30 -0700990 // Reordered event: delay the event in local cache
991 ByteBuffer id = linkEvent.getIDasByteBuffer();
992 reorderedAddedLinkEvents.put(id, linkEvent);
993 return;
994 }
Pavlin Radoslavov3c9cc552014-02-20 09:58:38 -0800995
Ray Milkey269ffb92014-04-03 14:43:30 -0700996 // Get the Link instance from the Destination Port Incoming Link
997 Link link = dstPort.getIncomingLink();
998 assert (link == srcPort.getOutgoingLink());
999 if (link == null) {
Jonathan Harte37e4e22014-05-13 19:12:02 -07001000 link = new LinkImpl(topology, srcPort, dstPort);
1001 topology.putLink(link);
Pavlin Radoslavov3c9cc552014-02-20 09:58:38 -08001002
Ray Milkey269ffb92014-04-03 14:43:30 -07001003 // Remove all Devices attached to the Ports
1004 ArrayList<DeviceEvent> devicesToRemove = new ArrayList<>();
1005 ArrayList<Port> ports = new ArrayList<>();
1006 ports.add(srcPort);
1007 ports.add(dstPort);
1008 for (Port port : ports) {
1009 for (Device device : port.getDevices()) {
1010 log.error("Device {} on Port {} should have been removed prior to adding Link {}",
1011 device, port, linkEvent);
1012 DeviceEvent deviceEvent =
1013 new DeviceEvent(device.getMacAddress());
1014 SwitchPort switchPort =
1015 new SwitchPort(port.getSwitch().getDpid(),
1016 port.getNumber());
1017 deviceEvent.addAttachmentPoint(switchPort);
1018 devicesToRemove.add(deviceEvent);
1019 }
1020 }
Ray Milkeyb29e6262014-04-09 16:02:14 -07001021 for (DeviceEvent deviceEvent : devicesToRemove) {
Ray Milkey269ffb92014-04-03 14:43:30 -07001022 removeDevice(deviceEvent);
Ray Milkeyb29e6262014-04-09 16:02:14 -07001023 }
Ray Milkey269ffb92014-04-03 14:43:30 -07001024 } else {
1025 // TODO: Update the link attributes
Ray Milkey1aa71f82014-04-08 16:23:24 -07001026 log.debug("Update link attributes");
Ray Milkey269ffb92014-04-03 14:43:30 -07001027 }
Pavlin Radoslavov74986ce2014-02-20 13:17:20 -08001028
Ray Milkey269ffb92014-04-03 14:43:30 -07001029 apiAddedLinkEvents.add(linkEvent);
Pavlin Radoslavov3c9cc552014-02-20 09:58:38 -08001030 }
1031
Pavlin Radoslavov734ff5a2014-02-26 10:20:43 -08001032 /**
Jonathan Harte37e4e22014-05-13 19:12:02 -07001033 * Remove a link from the topology.
Pavlin Radoslavov734ff5a2014-02-26 10:20:43 -08001034 *
1035 * @param linkEvent the Link Event with the link to remove.
1036 */
Yuta HIGUCHIbc67a052014-06-30 10:37:09 -07001037 @GuardedBy("topology.writeLock")
Pavlin Radoslavov3c9cc552014-02-20 09:58:38 -08001038 private void removeLink(LinkEvent linkEvent) {
Yuta HIGUCHI8f3dfa32014-06-25 00:14:25 -07001039 Port srcPort = topology.getPort(linkEvent.getSrc().getDpid(),
Yuta HIGUCHIb1e2ab72014-06-30 11:01:31 -07001040 linkEvent.getSrc().getPortNumber());
Ray Milkey269ffb92014-04-03 14:43:30 -07001041 if (srcPort == null) {
1042 log.warn("Src Port for Link {} already removed, ignoring",
1043 linkEvent);
1044 return;
1045 }
Pavlin Radoslavov3c9cc552014-02-20 09:58:38 -08001046
Yuta HIGUCHI8f3dfa32014-06-25 00:14:25 -07001047 Port dstPort = topology.getPort(linkEvent.getDst().getDpid(),
Yuta HIGUCHIb1e2ab72014-06-30 11:01:31 -07001048 linkEvent.getDst().getPortNumber());
Ray Milkey269ffb92014-04-03 14:43:30 -07001049 if (dstPort == null) {
1050 log.warn("Dst Port for Link {} already removed, ignoring",
1051 linkEvent);
1052 return;
1053 }
Pavlin Radoslavov3c9cc552014-02-20 09:58:38 -08001054
Ray Milkey269ffb92014-04-03 14:43:30 -07001055 //
1056 // Remove the Link instance from the Destination Port Incoming Link
1057 // and the Source Port Outgoing Link.
1058 //
1059 Link link = dstPort.getIncomingLink();
1060 if (link == null) {
1061 log.warn("Link {} already removed on destination Port", linkEvent);
1062 }
1063 link = srcPort.getOutgoingLink();
1064 if (link == null) {
1065 log.warn("Link {} already removed on src Port", linkEvent);
1066 }
Jonathan Hart25bd53e2014-04-30 23:44:09 -07001067
1068 // TODO should we check that we get the same link from each port?
1069 if (link != null) {
Jonathan Harte37e4e22014-05-13 19:12:02 -07001070 topology.removeLink(link);
Jonathan Hart25bd53e2014-04-30 23:44:09 -07001071 }
Pavlin Radoslavov74986ce2014-02-20 13:17:20 -08001072
Ray Milkey269ffb92014-04-03 14:43:30 -07001073 apiRemovedLinkEvents.add(linkEvent);
Pavlin Radoslavov3c9cc552014-02-20 09:58:38 -08001074 }
1075
Pavlin Radoslavov734ff5a2014-02-26 10:20:43 -08001076 /**
Jonathan Harte37e4e22014-05-13 19:12:02 -07001077 * Add a device to the topology.
Ray Milkey269ffb92014-04-03 14:43:30 -07001078 * <p/>
Pavlin Radoslavov734ff5a2014-02-26 10:20:43 -08001079 * TODO: Device-related work is incomplete.
1080 * TODO: Eventually, we might need to consider reordering
1081 * or addLink() and addDevice() events on the same port.
1082 *
1083 * @param deviceEvent the Device Event with the device to add.
1084 */
Yuta HIGUCHIbc67a052014-06-30 10:37:09 -07001085 @GuardedBy("topology.writeLock")
Pavlin Radoslavov3c9cc552014-02-20 09:58:38 -08001086 private void addDevice(DeviceEvent deviceEvent) {
Jonathan Harte37e4e22014-05-13 19:12:02 -07001087 log.debug("Adding a device to the topology with mac {}", deviceEvent.getMac());
1088 Device device = topology.getDeviceByMac(deviceEvent.getMac());
Pavlin Radoslavov3c9cc552014-02-20 09:58:38 -08001089
Ray Milkey269ffb92014-04-03 14:43:30 -07001090 if (device == null) {
Jonathan Harte37e4e22014-05-13 19:12:02 -07001091 log.debug("Existing device was not found in the Topology: Adding new device: mac {}", deviceEvent.getMac());
1092 device = new DeviceImpl(topology, deviceEvent.getMac());
Ray Milkey269ffb92014-04-03 14:43:30 -07001093 }
Pavlin Radoslavov3c9cc552014-02-20 09:58:38 -08001094
Ray Milkey269ffb92014-04-03 14:43:30 -07001095 DeviceImpl deviceImpl = getDeviceImpl(device);
Pavlin Radoslavov3c9cc552014-02-20 09:58:38 -08001096
Ray Milkey269ffb92014-04-03 14:43:30 -07001097 // Process each attachment point
1098 boolean attachmentFound = false;
1099 for (SwitchPort swp : deviceEvent.getAttachmentPoints()) {
1100 // Attached Ports must exist
Yuta HIGUCHIb1e2ab72014-06-30 11:01:31 -07001101 Port port = topology.getPort(swp.getDpid(), swp.getPortNumber());
Ray Milkey269ffb92014-04-03 14:43:30 -07001102 if (port == null) {
1103 // Reordered event: delay the event in local cache
1104 ByteBuffer id = deviceEvent.getIDasByteBuffer();
1105 reorderedAddedDeviceEvents.put(id, deviceEvent);
1106 continue;
1107 }
1108 // Attached Ports must not have Link
1109 if (port.getOutgoingLink() != null ||
1110 port.getIncomingLink() != null) {
1111 log.warn("Link (Out:{},In:{}) exist on the attachment point, skipping mutation.",
1112 port.getOutgoingLink(),
1113 port.getIncomingLink());
1114 continue;
1115 }
1116
1117 // Add Device <-> Port attachment
1118 PortImpl portImpl = getPortImpl(port);
1119 portImpl.addDevice(device);
1120 deviceImpl.addAttachmentPoint(port);
1121 attachmentFound = true;
1122 }
1123
TeruU5d2c9392014-06-09 20:02:02 -07001124 deviceImpl.setLastSeenTime(deviceEvent.getLastSeenTime());
1125
Jonathan Harte37e4e22014-05-13 19:12:02 -07001126 // Update the device in the topology
Ray Milkey269ffb92014-04-03 14:43:30 -07001127 if (attachmentFound) {
Jonathan Harte37e4e22014-05-13 19:12:02 -07001128 log.debug("Storing the device info into the Topology: mac {}", deviceEvent.getMac());
1129 topology.putDevice(device);
Ray Milkey269ffb92014-04-03 14:43:30 -07001130 apiAddedDeviceEvents.add(deviceEvent);
1131 }
Pavlin Radoslavov3c9cc552014-02-20 09:58:38 -08001132 }
1133
Pavlin Radoslavov734ff5a2014-02-26 10:20:43 -08001134 /**
Jonathan Harte37e4e22014-05-13 19:12:02 -07001135 * Remove a device from the topology.
Ray Milkey269ffb92014-04-03 14:43:30 -07001136 * <p/>
Pavlin Radoslavov734ff5a2014-02-26 10:20:43 -08001137 * TODO: Device-related work is incomplete.
1138 *
1139 * @param deviceEvent the Device Event with the device to remove.
1140 */
Yuta HIGUCHIbc67a052014-06-30 10:37:09 -07001141 @GuardedBy("topology.writeLock")
Pavlin Radoslavov3c9cc552014-02-20 09:58:38 -08001142 private void removeDevice(DeviceEvent deviceEvent) {
Jonathan Harte37e4e22014-05-13 19:12:02 -07001143 log.debug("Removing a device to the topology: mac {}", deviceEvent.getMac());
1144 Device device = topology.getDeviceByMac(deviceEvent.getMac());
Ray Milkey269ffb92014-04-03 14:43:30 -07001145 if (device == null) {
1146 log.warn("Device {} already removed, ignoring", deviceEvent);
1147 return;
1148 }
1149 DeviceImpl deviceImpl = getDeviceImpl(device);
Pavlin Radoslavov3c9cc552014-02-20 09:58:38 -08001150
Ray Milkey269ffb92014-04-03 14:43:30 -07001151 // Process each attachment point
1152 for (SwitchPort swp : deviceEvent.getAttachmentPoints()) {
1153 // Attached Ports must exist
Yuta HIGUCHIb1e2ab72014-06-30 11:01:31 -07001154 Port port = topology.getPort(swp.getDpid(), swp.getPortNumber());
Ray Milkey269ffb92014-04-03 14:43:30 -07001155 if (port == null) {
1156 log.warn("Port for the attachment point {} did not exist. skipping attachment point mutation", swp);
1157 continue;
1158 }
Pavlin Radoslavov3c9cc552014-02-20 09:58:38 -08001159
Ray Milkey269ffb92014-04-03 14:43:30 -07001160 // Remove Device <-> Port attachment
1161 PortImpl portImpl = getPortImpl(port);
1162 portImpl.removeDevice(device);
1163 deviceImpl.removeAttachmentPoint(port);
1164 }
Pavlin Radoslavov74986ce2014-02-20 13:17:20 -08001165
Jonathan Harte37e4e22014-05-13 19:12:02 -07001166 log.debug("Removing the device info into the Topology: mac {}", deviceEvent.getMac());
1167 topology.removeDevice(device);
Ray Milkey269ffb92014-04-03 14:43:30 -07001168 apiRemovedDeviceEvents.add(deviceEvent);
Pavlin Radoslavov3c9cc552014-02-20 09:58:38 -08001169 }
Jonathan Hart22eb9882014-02-11 15:52:59 -08001170
Pavlin Radoslavovc1cfde52014-02-19 11:35:29 -08001171 /**
Pavlin Radoslavov734ff5a2014-02-26 10:20:43 -08001172 * Get the SwitchImpl-casted switch implementation.
Pavlin Radoslavovc1cfde52014-02-19 11:35:29 -08001173 *
Pavlin Radoslavov734ff5a2014-02-26 10:20:43 -08001174 * @param sw the Switch to cast.
1175 * @return the SwitchImpl-casted switch implementation.
Pavlin Radoslavovc1cfde52014-02-19 11:35:29 -08001176 */
Pavlin Radoslavovc1cfde52014-02-19 11:35:29 -08001177 private SwitchImpl getSwitchImpl(Switch sw) {
Ray Milkey269ffb92014-04-03 14:43:30 -07001178 if (sw instanceof SwitchImpl) {
1179 return (SwitchImpl) sw;
1180 }
1181 throw new ClassCastException("SwitchImpl expected, but found: " + sw);
Pavlin Radoslavovc1cfde52014-02-19 11:35:29 -08001182 }
1183
Pavlin Radoslavov734ff5a2014-02-26 10:20:43 -08001184 /**
1185 * Get the PortImpl-casted port implementation.
1186 *
1187 * @param port the Port to cast.
1188 * @return the PortImpl-casted port implementation.
1189 */
1190 private PortImpl getPortImpl(Port port) {
Ray Milkey269ffb92014-04-03 14:43:30 -07001191 if (port instanceof PortImpl) {
1192 return (PortImpl) port;
1193 }
1194 throw new ClassCastException("PortImpl expected, but found: " + port);
Pavlin Radoslavovc1cfde52014-02-19 11:35:29 -08001195 }
1196
Pavlin Radoslavov734ff5a2014-02-26 10:20:43 -08001197 /**
1198 * Get the LinkImpl-casted link implementation.
1199 *
1200 * @param link the Link to cast.
1201 * @return the LinkImpl-casted link implementation.
1202 */
1203 private LinkImpl getLinkImpl(Link link) {
Ray Milkey269ffb92014-04-03 14:43:30 -07001204 if (link instanceof LinkImpl) {
1205 return (LinkImpl) link;
1206 }
1207 throw new ClassCastException("LinkImpl expected, but found: " + link);
Pavlin Radoslavovc1cfde52014-02-19 11:35:29 -08001208 }
1209
Pavlin Radoslavov734ff5a2014-02-26 10:20:43 -08001210 /**
1211 * Get the DeviceImpl-casted device implementation.
1212 *
1213 * @param device the Device to cast.
1214 * @return the DeviceImpl-casted device implementation.
1215 */
1216 private DeviceImpl getDeviceImpl(Device device) {
Ray Milkey269ffb92014-04-03 14:43:30 -07001217 if (device instanceof DeviceImpl) {
1218 return (DeviceImpl) device;
1219 }
1220 throw new ClassCastException("DeviceImpl expected, but found: " + device);
Pavlin Radoslavovc1cfde52014-02-19 11:35:29 -08001221 }
1222
Pavlin Radoslavov734ff5a2014-02-26 10:20:43 -08001223 /**
1224 * Read the whole topology from the database.
1225 *
1226 * @return a collection of EventEntry-encapsulated Topology Events for
1227 * the whole topology.
1228 */
Pavlin Radoslavov018d5332014-02-19 23:08:35 -08001229 private Collection<EventEntry<TopologyEvent>> readWholeTopologyFromDB() {
Ray Milkey269ffb92014-04-03 14:43:30 -07001230 Collection<EventEntry<TopologyEvent>> collection =
1231 new LinkedList<EventEntry<TopologyEvent>>();
Pavlin Radoslavov018d5332014-02-19 23:08:35 -08001232
Ray Milkey269ffb92014-04-03 14:43:30 -07001233 // XXX May need to clear whole topology first, depending on
1234 // how we initially subscribe to replication events
Pavlin Radoslavovc1cfde52014-02-19 11:35:29 -08001235
Ray Milkey269ffb92014-04-03 14:43:30 -07001236 // Add all active switches
1237 for (KVSwitch sw : KVSwitch.getAllSwitches()) {
1238 if (sw.getStatus() != KVSwitch.STATUS.ACTIVE) {
1239 continue;
1240 }
Pavlin Radoslavov018d5332014-02-19 23:08:35 -08001241
Ray Milkey269ffb92014-04-03 14:43:30 -07001242 SwitchEvent switchEvent = new SwitchEvent(sw.getDpid());
1243 TopologyEvent topologyEvent = new TopologyEvent(switchEvent);
1244 EventEntry<TopologyEvent> eventEntry =
1245 new EventEntry<TopologyEvent>(EventEntry.Type.ENTRY_ADD,
1246 topologyEvent);
1247 collection.add(eventEntry);
1248 }
Yuta HIGUCHIa536e762014-02-17 21:47:28 -08001249
Ray Milkey269ffb92014-04-03 14:43:30 -07001250 // Add all active ports
1251 for (KVPort p : KVPort.getAllPorts()) {
1252 if (p.getStatus() != KVPort.STATUS.ACTIVE) {
1253 continue;
1254 }
Pavlin Radoslavov018d5332014-02-19 23:08:35 -08001255
Ray Milkey269ffb92014-04-03 14:43:30 -07001256 PortEvent portEvent = new PortEvent(p.getDpid(), p.getNumber());
1257 TopologyEvent topologyEvent = new TopologyEvent(portEvent);
1258 EventEntry<TopologyEvent> eventEntry =
1259 new EventEntry<TopologyEvent>(EventEntry.Type.ENTRY_ADD,
1260 topologyEvent);
1261 collection.add(eventEntry);
1262 }
Yuta HIGUCHIa536e762014-02-17 21:47:28 -08001263
TeruU28adcc32014-04-15 17:57:35 -07001264 for (KVDevice d : KVDevice.getAllDevices()) {
1265 DeviceEvent devEvent = new DeviceEvent(MACAddress.valueOf(d.getMac()));
1266 for (byte[] portId : d.getAllPortIds()) {
Jonathan Hartc00f5c22014-06-10 15:14:40 -07001267 devEvent.addAttachmentPoint(
1268 new SwitchPort(KVPort.getDpidFromKey(portId),
1269 KVPort.getNumberFromKey(portId)));
TeruU28adcc32014-04-15 17:57:35 -07001270 }
1271 }
Pavlin Radoslavovc1cfde52014-02-19 11:35:29 -08001272
Ray Milkey269ffb92014-04-03 14:43:30 -07001273 for (KVLink l : KVLink.getAllLinks()) {
1274 LinkEvent linkEvent = new LinkEvent(l.getSrc().dpid,
1275 l.getSrc().number,
1276 l.getDst().dpid,
1277 l.getDst().number);
1278 TopologyEvent topologyEvent = new TopologyEvent(linkEvent);
1279 EventEntry<TopologyEvent> eventEntry =
1280 new EventEntry<TopologyEvent>(EventEntry.Type.ENTRY_ADD,
1281 topologyEvent);
1282 collection.add(eventEntry);
1283 }
Pavlin Radoslavov018d5332014-02-19 23:08:35 -08001284
Ray Milkey269ffb92014-04-03 14:43:30 -07001285 return collection;
Pavlin Radoslavovc1cfde52014-02-19 11:35:29 -08001286 }
Jonathan Hart062a2e82014-02-03 09:41:57 -08001287}