blob: 3a07693ee064c69b6d84f2801e73972b5a01f94f [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;
Pavlin Radoslavov4eaab992014-07-03 18:39:42 -070030import net.onrc.onos.core.util.serializers.KryoFactory;
Yuta HIGUCHI5c8cbeb2014-06-27 11:13:48 -070031
Jonathan Hart062a2e82014-02-03 09:41:57 -080032import org.slf4j.Logger;
33import org.slf4j.LoggerFactory;
34
Pavlin Radoslavov4eaab992014-07-03 18:39:42 -070035import com.esotericsoftware.kryo.Kryo;
36
Yuta HIGUCHI181d34d2014-02-05 15:05:46 -080037/**
Jonathan Harte37e4e22014-05-13 19:12:02 -070038 * The TopologyManager receives topology updates from the southbound discovery
39 * modules and from other ONOS instances. These updates are processed and
40 * applied to the in-memory topology instance.
Ray Milkey269ffb92014-04-03 14:43:30 -070041 * <p/>
Yuta HIGUCHI4bfdd532014-02-07 13:47:36 -080042 * - Maintain Invariant/Relationships between Topology Objects.
Ray Milkey269ffb92014-04-03 14:43:30 -070043 * <p/>
Yuta HIGUCHI765cd0d2014-02-06 12:46:41 -080044 * TODO To be synchronized based on TopologyEvent Notification.
Ray Milkey269ffb92014-04-03 14:43:30 -070045 * <p/>
Yuta HIGUCHIcb951982014-02-11 13:31:44 -080046 * TODO TBD: Caller is expected to maintain parent/child calling order. Parent
Yuta HIGUCHI1c700102014-02-12 16:30:52 -080047 * Object must exist before adding sub component(Add Switch -> Port).
Ray Milkey269ffb92014-04-03 14:43:30 -070048 * <p/>
Yuta HIGUCHI4bfdd532014-02-07 13:47:36 -080049 * TODO TBD: This class may delay the requested change to handle event
50 * re-ordering. e.g.) Link Add came in, but Switch was not there.
Yuta HIGUCHI181d34d2014-02-05 15:05:46 -080051 */
Jonathan Harte37e4e22014-05-13 19:12:02 -070052public class TopologyManager implements TopologyDiscoveryInterface {
Jonathan Hart062a2e82014-02-03 09:41:57 -080053
Yuta HIGUCHI80829d12014-02-05 20:16:56 -080054 private static final Logger log = LoggerFactory
Ray Milkey269ffb92014-04-03 14:43:30 -070055 .getLogger(TopologyManager.class);
Yuta HIGUCHIcd922f42014-02-11 18:59:11 -080056
Pavlin Radoslavov721a2e02014-02-14 23:40:14 -080057 private IEventChannel<byte[], TopologyEvent> eventChannel;
Jonathan Hart10a7e2b2014-02-21 18:30:08 -080058 public static final String EVENT_CHANNEL_NAME = "onos.topology";
Pavlin Radoslavov721a2e02014-02-14 23:40:14 -080059 private EventHandler eventHandler = new EventHandler();
60
Jonathan Harte37e4e22014-05-13 19:12:02 -070061 private final TopologyDatastore datastore;
62 private final TopologyImpl topology = new TopologyImpl();
Yuta HIGUCHI170229f2014-02-17 15:47:54 -080063 private final IControllerRegistryService registryService;
Jonathan Harte37e4e22014-05-13 19:12:02 -070064 private CopyOnWriteArrayList<ITopologyListener> topologyListeners;
Pavlin Radoslavov4eaab992014-07-03 18:39:42 -070065 private Kryo kryo = KryoFactory.newKryoObject();
Yuta HIGUCHI181d34d2014-02-05 15:05:46 -080066
Pavlin Radoslavov706add22014-02-20 12:15:59 -080067 //
68 // Local state for keeping track of reordered events.
69 // NOTE: Switch Events are not affected by the event reordering.
70 //
71 private Map<ByteBuffer, PortEvent> reorderedAddedPortEvents =
Ray Milkey269ffb92014-04-03 14:43:30 -070072 new HashMap<ByteBuffer, PortEvent>();
Pavlin Radoslavov706add22014-02-20 12:15:59 -080073 private Map<ByteBuffer, LinkEvent> reorderedAddedLinkEvents =
Ray Milkey269ffb92014-04-03 14:43:30 -070074 new HashMap<ByteBuffer, LinkEvent>();
Pavlin Radoslavov706add22014-02-20 12:15:59 -080075 private Map<ByteBuffer, DeviceEvent> reorderedAddedDeviceEvents =
Ray Milkey269ffb92014-04-03 14:43:30 -070076 new HashMap<ByteBuffer, DeviceEvent>();
Pavlin Radoslavov018d5332014-02-19 23:08:35 -080077
Pavlin Radoslavov74986ce2014-02-20 13:17:20 -080078 //
Pavlin Radoslavov26d83402014-02-20 15:24:30 -080079 // Local state for keeping track of locally discovered events so we can
80 // cleanup properly when a Switch or Port is removed.
81 //
Yuta HIGUCHIbc67a052014-06-30 10:37:09 -070082 // We keep all Port, (incoming) Link and Device events per Switch DPID:
Pavlin Radoslavov26d83402014-02-20 15:24:30 -080083 // - If a switch goes down, we remove all corresponding Port, Link and
84 // Device events.
85 // - If a port on a switch goes down, we remove all corresponding Link
Yuta HIGUCHIbc67a052014-06-30 10:37:09 -070086 // and Device events discovered by this instance.
87 //
88 // How to handle side-effect of remote events.
89 // - Remote Port Down event -> Link Down
90 // Not handled. (XXX Shouldn't it be removed from discovered.. Map)
91 // - Remote Device Added -> lose ownership of Device)
92 // Not handled. (XXX Shouldn't it be removed from discovered.. Map)
93 //
94 // XXX Domain knowledge based invariant maintenance should be moved to
95 // driver module, since the invariant may be different on optical, etc.
96 //
97 // What happens on leadership change?
98 // - Probably should: remove from discovered.. Maps, but not send DELETE events
99 // XXX Switch/Port can be rediscovered by new leader, but Link, Device?
100 // - Current: There is no way to recognize leadership change?
101 // ZookeeperRegistry.requestControl(long, ControlChangeCallback)
102 // is the only way to register listener, and it allows only 1 listener,
103 // which is already used by Controller class.
104 //
105 // FIXME Replace with concurrent variant.
106 // #removeSwitchDiscoveryEvent(SwitchEvent) runs in different thread.
Pavlin Radoslavov26d83402014-02-20 15:24:30 -0800107 //
Yuta HIGUCHI8f3dfa32014-06-25 00:14:25 -0700108 private Map<Dpid, Map<ByteBuffer, PortEvent>> discoveredAddedPortEvents =
Ray Milkey269ffb92014-04-03 14:43:30 -0700109 new HashMap<>();
Yuta HIGUCHI8f3dfa32014-06-25 00:14:25 -0700110 private Map<Dpid, Map<ByteBuffer, LinkEvent>> discoveredAddedLinkEvents =
Ray Milkey269ffb92014-04-03 14:43:30 -0700111 new HashMap<>();
Yuta HIGUCHI8f3dfa32014-06-25 00:14:25 -0700112 private Map<Dpid, Map<ByteBuffer, DeviceEvent>> discoveredAddedDeviceEvents =
Ray Milkey269ffb92014-04-03 14:43:30 -0700113 new HashMap<>();
Pavlin Radoslavov26d83402014-02-20 15:24:30 -0800114
115 //
Pavlin Radoslavov74986ce2014-02-20 13:17:20 -0800116 // Local state for keeping track of the application event notifications
117 //
Yuta HIGUCHIbc67a052014-06-30 10:37:09 -0700118 // - Queue of events, which will be dispatched to local listeners
119 // on next notification.
Yuta HIGUCHI703696c2014-06-25 20:36:45 -0700120
121 private List<SwitchEvent> apiAddedSwitchEvents = new LinkedList<>();
122 private List<SwitchEvent> apiRemovedSwitchEvents = new LinkedList<>();
123 private List<PortEvent> apiAddedPortEvents = new LinkedList<>();
124 private List<PortEvent> apiRemovedPortEvents = new LinkedList<>();
125 private List<LinkEvent> apiAddedLinkEvents = new LinkedList<>();
126 private List<LinkEvent> apiRemovedLinkEvents = new LinkedList<>();
127 private List<DeviceEvent> apiAddedDeviceEvents = new LinkedList<>();
128 private List<DeviceEvent> apiRemovedDeviceEvents = new LinkedList<>();
Pavlin Radoslavov74986ce2014-02-20 13:17:20 -0800129
Pavlin Radoslavovc1cfde52014-02-19 11:35:29 -0800130 /**
131 * Constructor.
132 *
Jonathan Harte37e4e22014-05-13 19:12:02 -0700133 * @param registryService the Registry Service to use.
134 * @param topologyListeners the collection of topology listeners to use.
Pavlin Radoslavovc1cfde52014-02-19 11:35:29 -0800135 */
136 public TopologyManager(IControllerRegistryService registryService,
Jonathan Harte37e4e22014-05-13 19:12:02 -0700137 CopyOnWriteArrayList<ITopologyListener> topologyListeners) {
138 datastore = new TopologyDatastore();
Ray Milkey269ffb92014-04-03 14:43:30 -0700139 this.registryService = registryService;
Jonathan Harte37e4e22014-05-13 19:12:02 -0700140 this.topologyListeners = topologyListeners;
Yuta HIGUCHI80829d12014-02-05 20:16:56 -0800141 }
Yuta HIGUCHI181d34d2014-02-05 15:05:46 -0800142
Pavlin Radoslavovc1cfde52014-02-19 11:35:29 -0800143 /**
Jonathan Harte37e4e22014-05-13 19:12:02 -0700144 * Get the Topology.
Pavlin Radoslavovc1cfde52014-02-19 11:35:29 -0800145 *
Jonathan Harte37e4e22014-05-13 19:12:02 -0700146 * @return the Topology.
Pavlin Radoslavovc1cfde52014-02-19 11:35:29 -0800147 */
Jonathan Harte37e4e22014-05-13 19:12:02 -0700148 Topology getTopology() {
149 return topology;
Pavlin Radoslavov6d224ee2014-02-18 16:43:15 -0800150 }
151
Yuta HIGUCHI4bfdd532014-02-07 13:47:36 -0800152 /**
Pavlin Radoslavov721a2e02014-02-14 23:40:14 -0800153 * Event handler class.
154 */
155 private class EventHandler extends Thread implements
Ray Milkey269ffb92014-04-03 14:43:30 -0700156 IEventChannelListener<byte[], TopologyEvent> {
157 private BlockingQueue<EventEntry<TopologyEvent>> topologyEvents =
158 new LinkedBlockingQueue<EventEntry<TopologyEvent>>();
Pavlin Radoslavov721a2e02014-02-14 23:40:14 -0800159
Ray Milkey269ffb92014-04-03 14:43:30 -0700160 /**
161 * Startup processing.
162 */
163 private void startup() {
164 //
165 // TODO: Read all state from the database:
166 //
167 // Collection<EventEntry<TopologyEvent>> collection =
168 // readWholeTopologyFromDB();
169 //
170 // For now, as a shortcut we read it from the datagrid
171 //
Ray Milkey5df613b2014-04-15 10:50:56 -0700172 Collection<TopologyEvent> allTopologyEvents =
Ray Milkey269ffb92014-04-03 14:43:30 -0700173 eventChannel.getAllEntries();
174 Collection<EventEntry<TopologyEvent>> collection =
175 new LinkedList<EventEntry<TopologyEvent>>();
Pavlin Radoslavov721a2e02014-02-14 23:40:14 -0800176
Ray Milkey5df613b2014-04-15 10:50:56 -0700177 for (TopologyEvent topologyEvent : allTopologyEvents) {
Ray Milkey269ffb92014-04-03 14:43:30 -0700178 EventEntry<TopologyEvent> eventEntry =
179 new EventEntry<TopologyEvent>(EventEntry.Type.ENTRY_ADD,
180 topologyEvent);
181 collection.add(eventEntry);
182 }
183 processEvents(collection);
184 }
Pavlin Radoslavov721a2e02014-02-14 23:40:14 -0800185
Ray Milkey269ffb92014-04-03 14:43:30 -0700186 /**
187 * Run the thread.
188 */
189 @Override
190 public void run() {
191 Collection<EventEntry<TopologyEvent>> collection =
192 new LinkedList<EventEntry<TopologyEvent>>();
Pavlin Radoslavov721a2e02014-02-14 23:40:14 -0800193
Ray Milkey269ffb92014-04-03 14:43:30 -0700194 this.setName("TopologyManager.EventHandler " + this.getId());
195 startup();
Pavlin Radoslavov721a2e02014-02-14 23:40:14 -0800196
Ray Milkey269ffb92014-04-03 14:43:30 -0700197 //
198 // The main loop
199 //
Pavlin Radoslavov8e881a42014-06-24 16:58:07 -0700200 while (true) {
201 try {
202 EventEntry<TopologyEvent> eventEntry =
203 topologyEvents.take();
Ray Milkey269ffb92014-04-03 14:43:30 -0700204 collection.add(eventEntry);
205 topologyEvents.drainTo(collection);
Pavlin Radoslavov721a2e02014-02-14 23:40:14 -0800206
Ray Milkey269ffb92014-04-03 14:43:30 -0700207 processEvents(collection);
208 collection.clear();
Pavlin Radoslavov8e881a42014-06-24 16:58:07 -0700209 } catch (Exception exception) {
210 log.debug("Exception processing Topology Events: ",
211 exception);
Ray Milkey269ffb92014-04-03 14:43:30 -0700212 }
Ray Milkey269ffb92014-04-03 14:43:30 -0700213 }
214 }
Pavlin Radoslavov721a2e02014-02-14 23:40:14 -0800215
Ray Milkey269ffb92014-04-03 14:43:30 -0700216 /**
217 * Process all topology events.
218 *
219 * @param events the events to process.
220 */
221 private void processEvents(Collection<EventEntry<TopologyEvent>> events) {
222 // Local state for computing the final set of events
223 Map<ByteBuffer, SwitchEvent> addedSwitchEvents = new HashMap<>();
224 Map<ByteBuffer, SwitchEvent> removedSwitchEvents = new HashMap<>();
225 Map<ByteBuffer, PortEvent> addedPortEvents = new HashMap<>();
226 Map<ByteBuffer, PortEvent> removedPortEvents = new HashMap<>();
227 Map<ByteBuffer, LinkEvent> addedLinkEvents = new HashMap<>();
228 Map<ByteBuffer, LinkEvent> removedLinkEvents = new HashMap<>();
229 Map<ByteBuffer, DeviceEvent> addedDeviceEvents = new HashMap<>();
230 Map<ByteBuffer, DeviceEvent> removedDeviceEvents = new HashMap<>();
Pavlin Radoslavov3c9cc552014-02-20 09:58:38 -0800231
Ray Milkey269ffb92014-04-03 14:43:30 -0700232 //
233 // Classify and suppress matching events
234 //
235 for (EventEntry<TopologyEvent> event : events) {
236 TopologyEvent topologyEvent = event.eventData();
237 SwitchEvent switchEvent = topologyEvent.switchEvent;
238 PortEvent portEvent = topologyEvent.portEvent;
239 LinkEvent linkEvent = topologyEvent.linkEvent;
240 DeviceEvent deviceEvent = topologyEvent.deviceEvent;
Pavlin Radoslavov018d5332014-02-19 23:08:35 -0800241
Ray Milkey269ffb92014-04-03 14:43:30 -0700242 //
243 // Extract the events
244 //
245 switch (event.eventType()) {
246 case ENTRY_ADD:
247 log.debug("Topology event ENTRY_ADD: {}", topologyEvent);
248 if (switchEvent != null) {
249 ByteBuffer id = switchEvent.getIDasByteBuffer();
250 addedSwitchEvents.put(id, switchEvent);
251 removedSwitchEvents.remove(id);
252 // Switch Events are not affected by event reordering
253 }
254 if (portEvent != null) {
255 ByteBuffer id = portEvent.getIDasByteBuffer();
256 addedPortEvents.put(id, portEvent);
257 removedPortEvents.remove(id);
258 reorderedAddedPortEvents.remove(id);
259 }
260 if (linkEvent != null) {
261 ByteBuffer id = linkEvent.getIDasByteBuffer();
262 addedLinkEvents.put(id, linkEvent);
263 removedLinkEvents.remove(id);
264 reorderedAddedLinkEvents.remove(id);
265 }
266 if (deviceEvent != null) {
267 ByteBuffer id = deviceEvent.getIDasByteBuffer();
268 addedDeviceEvents.put(id, deviceEvent);
269 removedDeviceEvents.remove(id);
270 reorderedAddedDeviceEvents.remove(id);
271 }
272 break;
273 case ENTRY_REMOVE:
274 log.debug("Topology event ENTRY_REMOVE: {}", topologyEvent);
275 if (switchEvent != null) {
276 ByteBuffer id = switchEvent.getIDasByteBuffer();
277 addedSwitchEvents.remove(id);
278 removedSwitchEvents.put(id, switchEvent);
279 // Switch Events are not affected by event reordering
280 }
281 if (portEvent != null) {
282 ByteBuffer id = portEvent.getIDasByteBuffer();
283 addedPortEvents.remove(id);
284 removedPortEvents.put(id, portEvent);
285 reorderedAddedPortEvents.remove(id);
286 }
287 if (linkEvent != null) {
288 ByteBuffer id = linkEvent.getIDasByteBuffer();
289 addedLinkEvents.remove(id);
290 removedLinkEvents.put(id, linkEvent);
291 reorderedAddedLinkEvents.remove(id);
292 }
293 if (deviceEvent != null) {
294 ByteBuffer id = deviceEvent.getIDasByteBuffer();
295 addedDeviceEvents.remove(id);
296 removedDeviceEvents.put(id, deviceEvent);
297 reorderedAddedDeviceEvents.remove(id);
298 }
299 break;
Ray Milkey0b122ed2014-04-14 10:06:03 -0700300 default:
301 log.error("Unknown topology event {}",
302 event.eventType());
Ray Milkey269ffb92014-04-03 14:43:30 -0700303 }
304 }
Pavlin Radoslavov3c9cc552014-02-20 09:58:38 -0800305
Ray Milkey269ffb92014-04-03 14:43:30 -0700306 //
Jonathan Harte37e4e22014-05-13 19:12:02 -0700307 // Lock the topology while it is modified
Ray Milkey269ffb92014-04-03 14:43:30 -0700308 //
Jonathan Harte37e4e22014-05-13 19:12:02 -0700309 topology.acquireWriteLock();
Pavlin Radoslavov8ffb8bf2014-02-20 15:34:26 -0800310
Ray Milkey269ffb92014-04-03 14:43:30 -0700311 try {
312 //
313 // Apply the classified events.
314 //
315 // Apply the "add" events in the proper order:
316 // switch, port, link, device
317 //
Ray Milkeyb29e6262014-04-09 16:02:14 -0700318 for (SwitchEvent switchEvent : addedSwitchEvents.values()) {
Ray Milkey269ffb92014-04-03 14:43:30 -0700319 addSwitch(switchEvent);
Ray Milkeyb29e6262014-04-09 16:02:14 -0700320 }
321 for (PortEvent portEvent : addedPortEvents.values()) {
Ray Milkey269ffb92014-04-03 14:43:30 -0700322 addPort(portEvent);
Ray Milkeyb29e6262014-04-09 16:02:14 -0700323 }
324 for (LinkEvent linkEvent : addedLinkEvents.values()) {
Ray Milkey269ffb92014-04-03 14:43:30 -0700325 addLink(linkEvent);
Ray Milkeyb29e6262014-04-09 16:02:14 -0700326 }
327 for (DeviceEvent deviceEvent : addedDeviceEvents.values()) {
Ray Milkey269ffb92014-04-03 14:43:30 -0700328 addDevice(deviceEvent);
Ray Milkeyb29e6262014-04-09 16:02:14 -0700329 }
Ray Milkey269ffb92014-04-03 14:43:30 -0700330 //
331 // Apply the "remove" events in the reverse order:
332 // device, link, port, switch
333 //
Ray Milkeyb29e6262014-04-09 16:02:14 -0700334 for (DeviceEvent deviceEvent : removedDeviceEvents.values()) {
Ray Milkey269ffb92014-04-03 14:43:30 -0700335 removeDevice(deviceEvent);
Ray Milkeyb29e6262014-04-09 16:02:14 -0700336 }
337 for (LinkEvent linkEvent : removedLinkEvents.values()) {
Ray Milkey269ffb92014-04-03 14:43:30 -0700338 removeLink(linkEvent);
Ray Milkeyb29e6262014-04-09 16:02:14 -0700339 }
340 for (PortEvent portEvent : removedPortEvents.values()) {
Ray Milkey269ffb92014-04-03 14:43:30 -0700341 removePort(portEvent);
Ray Milkeyb29e6262014-04-09 16:02:14 -0700342 }
343 for (SwitchEvent switchEvent : removedSwitchEvents.values()) {
Ray Milkey269ffb92014-04-03 14:43:30 -0700344 removeSwitch(switchEvent);
Ray Milkeyb29e6262014-04-09 16:02:14 -0700345 }
Yuta HIGUCHI3aca81a2014-02-23 12:41:19 -0800346
Ray Milkey269ffb92014-04-03 14:43:30 -0700347 //
348 // Apply reordered events
349 //
350 applyReorderedEvents(!addedSwitchEvents.isEmpty(),
351 !addedPortEvents.isEmpty());
Yuta HIGUCHI3aca81a2014-02-23 12:41:19 -0800352
Ray Milkey269ffb92014-04-03 14:43:30 -0700353 } finally {
354 //
Jonathan Harte37e4e22014-05-13 19:12:02 -0700355 // Topology modifications completed: Release the lock
Ray Milkey269ffb92014-04-03 14:43:30 -0700356 //
Jonathan Harte37e4e22014-05-13 19:12:02 -0700357 topology.releaseWriteLock();
Ray Milkey269ffb92014-04-03 14:43:30 -0700358 }
Yuta HIGUCHI3aca81a2014-02-23 12:41:19 -0800359
Ray Milkey269ffb92014-04-03 14:43:30 -0700360 //
361 // Dispatch the Topology Notification Events to the applications
362 //
Jonathan Harte37e4e22014-05-13 19:12:02 -0700363 dispatchTopologyEvents();
Ray Milkey269ffb92014-04-03 14:43:30 -0700364 }
Pavlin Radoslavov721a2e02014-02-14 23:40:14 -0800365
Ray Milkey269ffb92014-04-03 14:43:30 -0700366 /**
367 * Receive a notification that an entry is added.
368 *
369 * @param value the value for the entry.
370 */
371 @Override
372 public void entryAdded(TopologyEvent value) {
373 EventEntry<TopologyEvent> eventEntry =
374 new EventEntry<TopologyEvent>(EventEntry.Type.ENTRY_ADD,
375 value);
376 topologyEvents.add(eventEntry);
377 }
Pavlin Radoslavov721a2e02014-02-14 23:40:14 -0800378
Ray Milkey269ffb92014-04-03 14:43:30 -0700379 /**
380 * Receive a notification that an entry is removed.
381 *
382 * @param value the value for the entry.
383 */
384 @Override
385 public void entryRemoved(TopologyEvent value) {
386 EventEntry<TopologyEvent> eventEntry =
387 new EventEntry<TopologyEvent>(EventEntry.Type.ENTRY_REMOVE,
388 value);
389 topologyEvents.add(eventEntry);
390 }
Pavlin Radoslavov721a2e02014-02-14 23:40:14 -0800391
Ray Milkey269ffb92014-04-03 14:43:30 -0700392 /**
393 * Receive a notification that an entry is updated.
394 *
395 * @param value the value for the entry.
396 */
397 @Override
398 public void entryUpdated(TopologyEvent value) {
399 // NOTE: The ADD and UPDATE events are processed in same way
400 entryAdded(value);
401 }
Pavlin Radoslavov721a2e02014-02-14 23:40:14 -0800402 }
403
404 /**
405 * Startup processing.
406 *
407 * @param datagridService the datagrid service to use.
408 */
409 void startup(IDatagridService datagridService) {
Ray Milkey269ffb92014-04-03 14:43:30 -0700410 eventChannel = datagridService.addListener(EVENT_CHANNEL_NAME,
411 eventHandler,
412 byte[].class,
413 TopologyEvent.class);
414 eventHandler.start();
Pavlin Radoslavov721a2e02014-02-14 23:40:14 -0800415 }
416
Pavlin Radoslavov74986ce2014-02-20 13:17:20 -0800417 /**
Jonathan Harte37e4e22014-05-13 19:12:02 -0700418 * Dispatch Topology Events to the listeners.
Pavlin Radoslavov74986ce2014-02-20 13:17:20 -0800419 */
Jonathan Harte37e4e22014-05-13 19:12:02 -0700420 private void dispatchTopologyEvents() {
Ray Milkey269ffb92014-04-03 14:43:30 -0700421 if (apiAddedSwitchEvents.isEmpty() &&
422 apiRemovedSwitchEvents.isEmpty() &&
423 apiAddedPortEvents.isEmpty() &&
424 apiRemovedPortEvents.isEmpty() &&
425 apiAddedLinkEvents.isEmpty() &&
426 apiRemovedLinkEvents.isEmpty() &&
427 apiAddedDeviceEvents.isEmpty() &&
428 apiRemovedDeviceEvents.isEmpty()) {
429 return; // No events to dispatch
430 }
Pavlin Radoslavov74986ce2014-02-20 13:17:20 -0800431
Ray Milkey269ffb92014-04-03 14:43:30 -0700432 if (log.isDebugEnabled()) {
433 //
434 // Debug statements
435 // TODO: Those statements should be removed in the future
436 //
Ray Milkeyb29e6262014-04-09 16:02:14 -0700437 for (SwitchEvent switchEvent : apiAddedSwitchEvents) {
Jonathan Harte37e4e22014-05-13 19:12:02 -0700438 log.debug("Dispatch Topology Event: ADDED {}", switchEvent);
Ray Milkeyb29e6262014-04-09 16:02:14 -0700439 }
440 for (SwitchEvent switchEvent : apiRemovedSwitchEvents) {
Jonathan Harte37e4e22014-05-13 19:12:02 -0700441 log.debug("Dispatch Topology Event: REMOVED {}", switchEvent);
Ray Milkeyb29e6262014-04-09 16:02:14 -0700442 }
443 for (PortEvent portEvent : apiAddedPortEvents) {
Jonathan Harte37e4e22014-05-13 19:12:02 -0700444 log.debug("Dispatch Topology Event: ADDED {}", portEvent);
Ray Milkeyb29e6262014-04-09 16:02:14 -0700445 }
446 for (PortEvent portEvent : apiRemovedPortEvents) {
Jonathan Harte37e4e22014-05-13 19:12:02 -0700447 log.debug("Dispatch Topology Event: REMOVED {}", portEvent);
Ray Milkeyb29e6262014-04-09 16:02:14 -0700448 }
449 for (LinkEvent linkEvent : apiAddedLinkEvents) {
Jonathan Harte37e4e22014-05-13 19:12:02 -0700450 log.debug("Dispatch Topology Event: ADDED {}", linkEvent);
Ray Milkeyb29e6262014-04-09 16:02:14 -0700451 }
452 for (LinkEvent linkEvent : apiRemovedLinkEvents) {
Jonathan Harte37e4e22014-05-13 19:12:02 -0700453 log.debug("Dispatch Topology Event: REMOVED {}", linkEvent);
Ray Milkeyb29e6262014-04-09 16:02:14 -0700454 }
455 for (DeviceEvent deviceEvent : apiAddedDeviceEvents) {
Jonathan Harte37e4e22014-05-13 19:12:02 -0700456 log.debug("Dispatch Topology Event: ADDED {}", deviceEvent);
Ray Milkeyb29e6262014-04-09 16:02:14 -0700457 }
458 for (DeviceEvent deviceEvent : apiRemovedDeviceEvents) {
Jonathan Harte37e4e22014-05-13 19:12:02 -0700459 log.debug("Dispatch Topology Event: REMOVED {}", deviceEvent);
Ray Milkeyb29e6262014-04-09 16:02:14 -0700460 }
Ray Milkey269ffb92014-04-03 14:43:30 -0700461 }
adminbc181552014-02-21 18:36:42 -0800462
Ray Milkey269ffb92014-04-03 14:43:30 -0700463 // Deliver the events
Pavlin Radoslavov4eaab992014-07-03 18:39:42 -0700464 long timestamp = System.nanoTime();
Jonathan Harte37e4e22014-05-13 19:12:02 -0700465 for (ITopologyListener listener : this.topologyListeners) {
Pavlin Radoslavov4eaab992014-07-03 18:39:42 -0700466 TopologyEvents events =
467 new TopologyEvents(timestamp,
468 kryo.copy(apiAddedSwitchEvents),
469 kryo.copy(apiRemovedSwitchEvents),
470 kryo.copy(apiAddedPortEvents),
471 kryo.copy(apiRemovedPortEvents),
472 kryo.copy(apiAddedLinkEvents),
473 kryo.copy(apiRemovedLinkEvents),
474 kryo.copy(apiAddedDeviceEvents),
475 kryo.copy(apiRemovedDeviceEvents));
476 listener.topologyEvents(events);
Ray Milkey269ffb92014-04-03 14:43:30 -0700477 }
Pavlin Radoslavov74986ce2014-02-20 13:17:20 -0800478
Ray Milkey269ffb92014-04-03 14:43:30 -0700479 //
480 // Cleanup
481 //
482 apiAddedSwitchEvents.clear();
483 apiRemovedSwitchEvents.clear();
484 apiAddedPortEvents.clear();
485 apiRemovedPortEvents.clear();
486 apiAddedLinkEvents.clear();
487 apiRemovedLinkEvents.clear();
488 apiAddedDeviceEvents.clear();
489 apiRemovedDeviceEvents.clear();
Pavlin Radoslavov74986ce2014-02-20 13:17:20 -0800490 }
491
492 /**
493 * Apply reordered events.
494 *
495 * @param hasAddedSwitchEvents true if there were Added Switch Events.
Ray Milkey269ffb92014-04-03 14:43:30 -0700496 * @param hasAddedPortEvents true if there were Added Port Events.
Pavlin Radoslavov74986ce2014-02-20 13:17:20 -0800497 */
Yuta HIGUCHIbc67a052014-06-30 10:37:09 -0700498 @GuardedBy("topology.writeLock")
Pavlin Radoslavov74986ce2014-02-20 13:17:20 -0800499 private void applyReorderedEvents(boolean hasAddedSwitchEvents,
Ray Milkey269ffb92014-04-03 14:43:30 -0700500 boolean hasAddedPortEvents) {
Ray Milkeyb29e6262014-04-09 16:02:14 -0700501 if (!(hasAddedSwitchEvents || hasAddedPortEvents)) {
Ray Milkey269ffb92014-04-03 14:43:30 -0700502 return; // Nothing to do
Ray Milkeyb29e6262014-04-09 16:02:14 -0700503 }
Pavlin Radoslavov74986ce2014-02-20 13:17:20 -0800504
Ray Milkey269ffb92014-04-03 14:43:30 -0700505 //
506 // Try to apply the reordered events.
507 //
508 // NOTE: For simplicity we try to apply all events of a particular
509 // type if any "parent" type event was processed:
510 // - Apply reordered Port Events if Switches were added
511 // - Apply reordered Link and Device Events if Switches or Ports
512 // were added
513 //
adminbc181552014-02-21 18:36:42 -0800514
Ray Milkey269ffb92014-04-03 14:43:30 -0700515 //
516 // Apply reordered Port Events if Switches were added
517 //
518 if (hasAddedSwitchEvents) {
519 Map<ByteBuffer, PortEvent> portEvents = reorderedAddedPortEvents;
520 reorderedAddedPortEvents = new HashMap<>();
Ray Milkeyb29e6262014-04-09 16:02:14 -0700521 for (PortEvent portEvent : portEvents.values()) {
Ray Milkey269ffb92014-04-03 14:43:30 -0700522 addPort(portEvent);
Ray Milkeyb29e6262014-04-09 16:02:14 -0700523 }
Ray Milkey269ffb92014-04-03 14:43:30 -0700524 }
525 //
526 // Apply reordered Link and Device Events if Switches or Ports
527 // were added.
528 //
529 Map<ByteBuffer, LinkEvent> linkEvents = reorderedAddedLinkEvents;
530 reorderedAddedLinkEvents = new HashMap<>();
Ray Milkeyb29e6262014-04-09 16:02:14 -0700531 for (LinkEvent linkEvent : linkEvents.values()) {
Ray Milkey269ffb92014-04-03 14:43:30 -0700532 addLink(linkEvent);
Ray Milkeyb29e6262014-04-09 16:02:14 -0700533 }
Ray Milkey269ffb92014-04-03 14:43:30 -0700534 //
535 Map<ByteBuffer, DeviceEvent> deviceEvents = reorderedAddedDeviceEvents;
536 reorderedAddedDeviceEvents = new HashMap<>();
Ray Milkeyb29e6262014-04-09 16:02:14 -0700537 for (DeviceEvent deviceEvent : deviceEvents.values()) {
Ray Milkey269ffb92014-04-03 14:43:30 -0700538 addDevice(deviceEvent);
Ray Milkeyb29e6262014-04-09 16:02:14 -0700539 }
Pavlin Radoslavov74986ce2014-02-20 13:17:20 -0800540 }
541
Pavlin Radoslavov734ff5a2014-02-26 10:20:43 -0800542 /**
543 * Switch discovered event.
544 *
545 * @param switchEvent the switch event.
Ray Milkey269ffb92014-04-03 14:43:30 -0700546 * @param portEvents the corresponding port events for the switch.
Pavlin Radoslavov734ff5a2014-02-26 10:20:43 -0800547 */
Pavlin Radoslavovc1cfde52014-02-19 11:35:29 -0800548 @Override
Pavlin Radoslavov018d5332014-02-19 23:08:35 -0800549 public void putSwitchDiscoveryEvent(SwitchEvent switchEvent,
Ray Milkey269ffb92014-04-03 14:43:30 -0700550 Collection<PortEvent> portEvents) {
551 if (datastore.addSwitch(switchEvent, portEvents)) {
Jonathan Hart92c819f2014-05-30 10:53:30 -0700552 log.debug("Sending add switch: {}", switchEvent);
Ray Milkey269ffb92014-04-03 14:43:30 -0700553 // Send out notification
554 TopologyEvent topologyEvent = new TopologyEvent(switchEvent);
555 eventChannel.addEntry(topologyEvent.getID(), topologyEvent);
Pavlin Radoslavov26d83402014-02-20 15:24:30 -0800556
Ray Milkey269ffb92014-04-03 14:43:30 -0700557 // Send out notification for each port
558 for (PortEvent portEvent : portEvents) {
Jonathan Hart92c819f2014-05-30 10:53:30 -0700559 log.debug("Sending add port: {}", portEvent);
Ray Milkey269ffb92014-04-03 14:43:30 -0700560 topologyEvent = new TopologyEvent(portEvent);
561 eventChannel.addEntry(topologyEvent.getID(), topologyEvent);
562 }
Pavlin Radoslavov26d83402014-02-20 15:24:30 -0800563
Ray Milkey269ffb92014-04-03 14:43:30 -0700564 //
565 // Keep track of the added ports
566 //
567 // Get the old Port Events
568 Map<ByteBuffer, PortEvent> oldPortEvents =
569 discoveredAddedPortEvents.get(switchEvent.getDpid());
Ray Milkeyb29e6262014-04-09 16:02:14 -0700570 if (oldPortEvents == null) {
Ray Milkey269ffb92014-04-03 14:43:30 -0700571 oldPortEvents = new HashMap<>();
Ray Milkeyb29e6262014-04-09 16:02:14 -0700572 }
Pavlin Radoslavov26d83402014-02-20 15:24:30 -0800573
Ray Milkey269ffb92014-04-03 14:43:30 -0700574 // Store the new Port Events in the local cache
575 Map<ByteBuffer, PortEvent> newPortEvents = new HashMap<>();
576 for (PortEvent portEvent : portEvents) {
577 ByteBuffer id = portEvent.getIDasByteBuffer();
578 newPortEvents.put(id, portEvent);
579 }
580 discoveredAddedPortEvents.put(switchEvent.getDpid(),
581 newPortEvents);
Pavlin Radoslavov26d83402014-02-20 15:24:30 -0800582
Ray Milkey269ffb92014-04-03 14:43:30 -0700583 //
584 // Extract the removed ports
585 //
586 List<PortEvent> removedPortEvents = new LinkedList<>();
587 for (Map.Entry<ByteBuffer, PortEvent> entry : oldPortEvents.entrySet()) {
588 ByteBuffer key = entry.getKey();
589 PortEvent portEvent = entry.getValue();
Ray Milkeyb29e6262014-04-09 16:02:14 -0700590 if (!newPortEvents.containsKey(key)) {
Ray Milkey269ffb92014-04-03 14:43:30 -0700591 removedPortEvents.add(portEvent);
Ray Milkeyb29e6262014-04-09 16:02:14 -0700592 }
Ray Milkey269ffb92014-04-03 14:43:30 -0700593 }
594
595 // Cleanup old removed ports
Ray Milkeyb29e6262014-04-09 16:02:14 -0700596 for (PortEvent portEvent : removedPortEvents) {
Ray Milkey269ffb92014-04-03 14:43:30 -0700597 removePortDiscoveryEvent(portEvent);
Ray Milkeyb29e6262014-04-09 16:02:14 -0700598 }
Ray Milkey269ffb92014-04-03 14:43:30 -0700599 }
Pavlin Radoslavovc1cfde52014-02-19 11:35:29 -0800600 }
601
Pavlin Radoslavov734ff5a2014-02-26 10:20:43 -0800602 /**
Yuta HIGUCHIbc67a052014-06-30 10:37:09 -0700603 * {@inheritDoc}
604 * <p/>
605 * Called by {@link TopologyPublisher.SwitchCleanup} thread.
Pavlin Radoslavov734ff5a2014-02-26 10:20:43 -0800606 */
Pavlin Radoslavovc1cfde52014-02-19 11:35:29 -0800607 @Override
Pavlin Radoslavov6ea84a42014-02-19 15:50:01 -0800608 public void removeSwitchDiscoveryEvent(SwitchEvent switchEvent) {
Ray Milkey269ffb92014-04-03 14:43:30 -0700609 // Get the old Port Events
610 Map<ByteBuffer, PortEvent> oldPortEvents =
611 discoveredAddedPortEvents.get(switchEvent.getDpid());
Ray Milkeyb29e6262014-04-09 16:02:14 -0700612 if (oldPortEvents == null) {
Ray Milkey269ffb92014-04-03 14:43:30 -0700613 oldPortEvents = new HashMap<>();
Ray Milkeyb29e6262014-04-09 16:02:14 -0700614 }
Pavlin Radoslavov018d5332014-02-19 23:08:35 -0800615
Ray Milkey269ffb92014-04-03 14:43:30 -0700616 if (datastore.deactivateSwitch(switchEvent, oldPortEvents.values())) {
Jonathan Hart92c819f2014-05-30 10:53:30 -0700617 log.debug("Sending remove switch: {}", switchEvent);
Ray Milkey269ffb92014-04-03 14:43:30 -0700618 // Send out notification
619 eventChannel.removeEntry(switchEvent.getID());
Pavlin Radoslavov018d5332014-02-19 23:08:35 -0800620
Ray Milkey269ffb92014-04-03 14:43:30 -0700621 //
622 // Send out notification for each port.
623 //
624 // NOTE: We don't use removePortDiscoveryEvent() for the cleanup,
625 // because it will attempt to remove the port from the database,
626 // and the deactiveSwitch() call above already removed all ports.
627 //
Ray Milkeyb29e6262014-04-09 16:02:14 -0700628 for (PortEvent portEvent : oldPortEvents.values()) {
Jonathan Hart92c819f2014-05-30 10:53:30 -0700629 log.debug("Sending remove port:", portEvent);
Ray Milkey269ffb92014-04-03 14:43:30 -0700630 eventChannel.removeEntry(portEvent.getID());
Ray Milkeyb29e6262014-04-09 16:02:14 -0700631 }
Ray Milkey269ffb92014-04-03 14:43:30 -0700632 discoveredAddedPortEvents.remove(switchEvent.getDpid());
Pavlin Radoslavov26d83402014-02-20 15:24:30 -0800633
Ray Milkey269ffb92014-04-03 14:43:30 -0700634 // Cleanup for each link
635 Map<ByteBuffer, LinkEvent> oldLinkEvents =
636 discoveredAddedLinkEvents.get(switchEvent.getDpid());
637 if (oldLinkEvents != null) {
638 for (LinkEvent linkEvent : new ArrayList<>(oldLinkEvents.values())) {
639 removeLinkDiscoveryEvent(linkEvent);
640 }
641 discoveredAddedLinkEvents.remove(switchEvent.getDpid());
642 }
Pavlin Radoslavov26d83402014-02-20 15:24:30 -0800643
Ray Milkey269ffb92014-04-03 14:43:30 -0700644 // Cleanup for each device
645 Map<ByteBuffer, DeviceEvent> oldDeviceEvents =
646 discoveredAddedDeviceEvents.get(switchEvent.getDpid());
647 if (oldDeviceEvents != null) {
648 for (DeviceEvent deviceEvent : new ArrayList<>(oldDeviceEvents.values())) {
649 removeDeviceDiscoveryEvent(deviceEvent);
650 }
651 discoveredAddedDeviceEvents.remove(switchEvent.getDpid());
652 }
653 }
Pavlin Radoslavovc1cfde52014-02-19 11:35:29 -0800654 }
655
Pavlin Radoslavov734ff5a2014-02-26 10:20:43 -0800656 /**
657 * Port discovered event.
658 *
659 * @param portEvent the port event.
660 */
Pavlin Radoslavovc1cfde52014-02-19 11:35:29 -0800661 @Override
Pavlin Radoslavov6ea84a42014-02-19 15:50:01 -0800662 public void putPortDiscoveryEvent(PortEvent portEvent) {
Ray Milkey269ffb92014-04-03 14:43:30 -0700663 if (datastore.addPort(portEvent)) {
Jonathan Hart92c819f2014-05-30 10:53:30 -0700664 log.debug("Sending add port: {}", portEvent);
Ray Milkey269ffb92014-04-03 14:43:30 -0700665 // Send out notification
666 TopologyEvent topologyEvent = new TopologyEvent(portEvent);
667 eventChannel.addEntry(topologyEvent.getID(), topologyEvent);
Pavlin Radoslavov26d83402014-02-20 15:24:30 -0800668
Ray Milkey269ffb92014-04-03 14:43:30 -0700669 // Store the new Port Event in the local cache
670 Map<ByteBuffer, PortEvent> oldPortEvents =
671 discoveredAddedPortEvents.get(portEvent.getDpid());
672 if (oldPortEvents == null) {
673 oldPortEvents = new HashMap<>();
674 discoveredAddedPortEvents.put(portEvent.getDpid(),
675 oldPortEvents);
676 }
677 ByteBuffer id = portEvent.getIDasByteBuffer();
678 oldPortEvents.put(id, portEvent);
679 }
Pavlin Radoslavovc1cfde52014-02-19 11:35:29 -0800680 }
681
Pavlin Radoslavov734ff5a2014-02-26 10:20:43 -0800682 /**
683 * Port removed event.
684 *
685 * @param portEvent the port event.
686 */
Pavlin Radoslavovc1cfde52014-02-19 11:35:29 -0800687 @Override
Pavlin Radoslavov6ea84a42014-02-19 15:50:01 -0800688 public void removePortDiscoveryEvent(PortEvent portEvent) {
Ray Milkey269ffb92014-04-03 14:43:30 -0700689 if (datastore.deactivatePort(portEvent)) {
Jonathan Hart92c819f2014-05-30 10:53:30 -0700690 log.debug("Sending remove port: {}", portEvent);
Ray Milkey269ffb92014-04-03 14:43:30 -0700691 // Send out notification
692 eventChannel.removeEntry(portEvent.getID());
Pavlin Radoslavov26d83402014-02-20 15:24:30 -0800693
Ray Milkey269ffb92014-04-03 14:43:30 -0700694 // Cleanup the Port Event from the local cache
695 Map<ByteBuffer, PortEvent> oldPortEvents =
696 discoveredAddedPortEvents.get(portEvent.getDpid());
697 if (oldPortEvents != null) {
698 ByteBuffer id = portEvent.getIDasByteBuffer();
699 oldPortEvents.remove(id);
700 }
Pavlin Radoslavov26d83402014-02-20 15:24:30 -0800701
Ray Milkey269ffb92014-04-03 14:43:30 -0700702 // Cleanup for the incoming link
703 Map<ByteBuffer, LinkEvent> oldLinkEvents =
704 discoveredAddedLinkEvents.get(portEvent.getDpid());
705 if (oldLinkEvents != null) {
706 for (LinkEvent linkEvent : new ArrayList<>(oldLinkEvents.values())) {
707 if (linkEvent.getDst().equals(portEvent.id)) {
708 removeLinkDiscoveryEvent(linkEvent);
709 // XXX If we change our model to allow multiple Link on
710 // a Port, this loop must be fixed to allow continuing.
711 break;
712 }
713 }
714 }
Pavlin Radoslavov26d83402014-02-20 15:24:30 -0800715
Ray Milkey269ffb92014-04-03 14:43:30 -0700716 // Cleanup for the connected devices
717 // TODO: The implementation below is probably wrong
718 List<DeviceEvent> removedDeviceEvents = new LinkedList<>();
719 Map<ByteBuffer, DeviceEvent> oldDeviceEvents =
720 discoveredAddedDeviceEvents.get(portEvent.getDpid());
721 if (oldDeviceEvents != null) {
722 for (DeviceEvent deviceEvent : new ArrayList<>(oldDeviceEvents.values())) {
723 for (SwitchPort swp : deviceEvent.getAttachmentPoints()) {
724 if (swp.equals(portEvent.id)) {
725 removedDeviceEvents.add(deviceEvent);
726 }
727 }
728 }
Ray Milkeyb29e6262014-04-09 16:02:14 -0700729 for (DeviceEvent deviceEvent : removedDeviceEvents) {
Ray Milkey269ffb92014-04-03 14:43:30 -0700730 removeDeviceDiscoveryEvent(deviceEvent);
Ray Milkeyb29e6262014-04-09 16:02:14 -0700731 }
Ray Milkey269ffb92014-04-03 14:43:30 -0700732 }
733 }
Pavlin Radoslavovc1cfde52014-02-19 11:35:29 -0800734 }
735
Pavlin Radoslavov734ff5a2014-02-26 10:20:43 -0800736 /**
737 * Link discovered event.
738 *
739 * @param linkEvent the link event.
740 */
Pavlin Radoslavovc1cfde52014-02-19 11:35:29 -0800741 @Override
Pavlin Radoslavov6ea84a42014-02-19 15:50:01 -0800742 public void putLinkDiscoveryEvent(LinkEvent linkEvent) {
Ray Milkey269ffb92014-04-03 14:43:30 -0700743 if (datastore.addLink(linkEvent)) {
Jonathan Hart92c819f2014-05-30 10:53:30 -0700744 log.debug("Sending add link: {}", linkEvent);
Ray Milkey269ffb92014-04-03 14:43:30 -0700745 // Send out notification
746 TopologyEvent topologyEvent = new TopologyEvent(linkEvent);
747 eventChannel.addEntry(topologyEvent.getID(), topologyEvent);
Pavlin Radoslavov26d83402014-02-20 15:24:30 -0800748
Ray Milkey269ffb92014-04-03 14:43:30 -0700749 // Store the new Link Event in the local cache
750 Map<ByteBuffer, LinkEvent> oldLinkEvents =
751 discoveredAddedLinkEvents.get(linkEvent.getDst().getDpid());
752 if (oldLinkEvents == null) {
753 oldLinkEvents = new HashMap<>();
754 discoveredAddedLinkEvents.put(linkEvent.getDst().getDpid(),
755 oldLinkEvents);
756 }
757 ByteBuffer id = linkEvent.getIDasByteBuffer();
758 oldLinkEvents.put(id, linkEvent);
759 }
Pavlin Radoslavovc1cfde52014-02-19 11:35:29 -0800760 }
761
Pavlin Radoslavov734ff5a2014-02-26 10:20:43 -0800762 /**
763 * Link removed event.
764 *
765 * @param linkEvent the link event.
766 */
Pavlin Radoslavovc1cfde52014-02-19 11:35:29 -0800767 @Override
Pavlin Radoslavov6ea84a42014-02-19 15:50:01 -0800768 public void removeLinkDiscoveryEvent(LinkEvent linkEvent) {
Ray Milkey269ffb92014-04-03 14:43:30 -0700769 if (datastore.removeLink(linkEvent)) {
Jonathan Hart92c819f2014-05-30 10:53:30 -0700770 log.debug("Sending remove link: {}", linkEvent);
Ray Milkey269ffb92014-04-03 14:43:30 -0700771 // Send out notification
772 eventChannel.removeEntry(linkEvent.getID());
Pavlin Radoslavov26d83402014-02-20 15:24:30 -0800773
Ray Milkey269ffb92014-04-03 14:43:30 -0700774 // Cleanup the Link Event from the local cache
775 Map<ByteBuffer, LinkEvent> oldLinkEvents =
776 discoveredAddedLinkEvents.get(linkEvent.getDst().getDpid());
777 if (oldLinkEvents != null) {
778 ByteBuffer id = linkEvent.getIDasByteBuffer();
779 oldLinkEvents.remove(id);
780 }
781 }
Pavlin Radoslavovc1cfde52014-02-19 11:35:29 -0800782 }
Jonathan Hart22eb9882014-02-11 15:52:59 -0800783
Pavlin Radoslavov734ff5a2014-02-26 10:20:43 -0800784 /**
785 * Device discovered event.
786 *
787 * @param deviceEvent the device event.
788 */
Pavlin Radoslavovc1cfde52014-02-19 11:35:29 -0800789 @Override
Pavlin Radoslavov6ea84a42014-02-19 15:50:01 -0800790 public void putDeviceDiscoveryEvent(DeviceEvent deviceEvent) {
Ray Milkey269ffb92014-04-03 14:43:30 -0700791 if (datastore.addDevice(deviceEvent)) {
792 // Send out notification
793 TopologyEvent topologyEvent = new TopologyEvent(deviceEvent);
794 eventChannel.addEntry(topologyEvent.getID(), topologyEvent);
Jonathan Harte37e4e22014-05-13 19:12:02 -0700795 log.debug("Put the device info into the cache of the topology. mac {}", deviceEvent.getMac());
Ray Milkey269ffb92014-04-03 14:43:30 -0700796
797 // Store the new Device Event in the local cache
798 // TODO: The implementation below is probably wrong
799 for (SwitchPort swp : deviceEvent.getAttachmentPoints()) {
800 Map<ByteBuffer, DeviceEvent> oldDeviceEvents =
801 discoveredAddedDeviceEvents.get(swp.getDpid());
802 if (oldDeviceEvents == null) {
803 oldDeviceEvents = new HashMap<>();
804 discoveredAddedDeviceEvents.put(swp.getDpid(),
805 oldDeviceEvents);
806 }
807 ByteBuffer id = deviceEvent.getIDasByteBuffer();
808 oldDeviceEvents.put(id, deviceEvent);
809 }
810 }
Pavlin Radoslavovc1cfde52014-02-19 11:35:29 -0800811 }
Jonathan Hart22eb9882014-02-11 15:52:59 -0800812
Pavlin Radoslavov734ff5a2014-02-26 10:20:43 -0800813 /**
814 * Device removed event.
815 *
816 * @param deviceEvent the device event.
817 */
Pavlin Radoslavovc1cfde52014-02-19 11:35:29 -0800818 @Override
Pavlin Radoslavov6ea84a42014-02-19 15:50:01 -0800819 public void removeDeviceDiscoveryEvent(DeviceEvent deviceEvent) {
Ray Milkey269ffb92014-04-03 14:43:30 -0700820 if (datastore.removeDevice(deviceEvent)) {
821 // Send out notification
822 eventChannel.removeEntry(deviceEvent.getID());
Jonathan Harte37e4e22014-05-13 19:12:02 -0700823 log.debug("Remove the device info into the cache of the topology. mac {}", deviceEvent.getMac());
Pavlin Radoslavov26d83402014-02-20 15:24:30 -0800824
Ray Milkey269ffb92014-04-03 14:43:30 -0700825 // Cleanup the Device Event from the local cache
826 // TODO: The implementation below is probably wrong
827 ByteBuffer id = ByteBuffer.wrap(deviceEvent.getID());
828 for (SwitchPort swp : deviceEvent.getAttachmentPoints()) {
829 Map<ByteBuffer, DeviceEvent> oldDeviceEvents =
830 discoveredAddedDeviceEvents.get(swp.getDpid());
831 if (oldDeviceEvents != null) {
832 oldDeviceEvents.remove(id);
833 }
834 }
835 }
Pavlin Radoslavovc1cfde52014-02-19 11:35:29 -0800836 }
Jonathan Hart22eb9882014-02-11 15:52:59 -0800837
Pavlin Radoslavov734ff5a2014-02-26 10:20:43 -0800838 /**
Jonathan Harte37e4e22014-05-13 19:12:02 -0700839 * Add a switch to the topology.
Pavlin Radoslavov734ff5a2014-02-26 10:20:43 -0800840 *
841 * @param switchEvent the Switch Event with the switch to add.
842 */
Yuta HIGUCHIbc67a052014-06-30 10:37:09 -0700843 @GuardedBy("topology.writeLock")
Pavlin Radoslavov74986ce2014-02-20 13:17:20 -0800844 private void addSwitch(SwitchEvent switchEvent) {
Jonathan Harte37e4e22014-05-13 19:12:02 -0700845 Switch sw = topology.getSwitch(switchEvent.getDpid());
Ray Milkey269ffb92014-04-03 14:43:30 -0700846 if (sw == null) {
Jonathan Harte37e4e22014-05-13 19:12:02 -0700847 sw = new SwitchImpl(topology, switchEvent.getDpid());
848 topology.putSwitch(sw);
Ray Milkey269ffb92014-04-03 14:43:30 -0700849 } else {
850 // TODO: Update the switch attributes
851 // TODO: Nothing to do for now
Ray Milkey1aa71f82014-04-08 16:23:24 -0700852 log.debug("Update switch attributes");
Ray Milkey269ffb92014-04-03 14:43:30 -0700853 }
854 apiAddedSwitchEvents.add(switchEvent);
Pavlin Radoslavov3c9cc552014-02-20 09:58:38 -0800855 }
856
Pavlin Radoslavov734ff5a2014-02-26 10:20:43 -0800857 /**
Jonathan Harte37e4e22014-05-13 19:12:02 -0700858 * Remove a switch from the topology.
Pavlin Radoslavov734ff5a2014-02-26 10:20:43 -0800859 *
860 * @param switchEvent the Switch Event with the switch to remove.
861 */
Yuta HIGUCHIbc67a052014-06-30 10:37:09 -0700862 @GuardedBy("topology.writeLock")
Pavlin Radoslavov74986ce2014-02-20 13:17:20 -0800863 private void removeSwitch(SwitchEvent switchEvent) {
Jonathan Harte37e4e22014-05-13 19:12:02 -0700864 Switch sw = topology.getSwitch(switchEvent.getDpid());
Ray Milkey269ffb92014-04-03 14:43:30 -0700865 if (sw == null) {
866 log.warn("Switch {} already removed, ignoring", switchEvent);
867 return;
868 }
Pavlin Radoslavov3c9cc552014-02-20 09:58:38 -0800869
Ray Milkey269ffb92014-04-03 14:43:30 -0700870 //
871 // Remove all Ports on the Switch
872 //
873 ArrayList<PortEvent> portsToRemove = new ArrayList<>();
874 for (Port port : sw.getPorts()) {
875 log.warn("Port {} on Switch {} should be removed prior to removing Switch. Removing Port now.",
876 port, switchEvent);
877 PortEvent portEvent = new PortEvent(port.getDpid(),
878 port.getNumber());
879 portsToRemove.add(portEvent);
880 }
Ray Milkeyb29e6262014-04-09 16:02:14 -0700881 for (PortEvent portEvent : portsToRemove) {
Ray Milkey269ffb92014-04-03 14:43:30 -0700882 removePort(portEvent);
Ray Milkeyb29e6262014-04-09 16:02:14 -0700883 }
Pavlin Radoslavov3c9cc552014-02-20 09:58:38 -0800884
Jonathan Harte37e4e22014-05-13 19:12:02 -0700885 topology.removeSwitch(switchEvent.getDpid());
Ray Milkey269ffb92014-04-03 14:43:30 -0700886 apiRemovedSwitchEvents.add(switchEvent);
Pavlin Radoslavov3c9cc552014-02-20 09:58:38 -0800887 }
888
Pavlin Radoslavov734ff5a2014-02-26 10:20:43 -0800889 /**
Jonathan Harte37e4e22014-05-13 19:12:02 -0700890 * Add a port to the topology.
Pavlin Radoslavov734ff5a2014-02-26 10:20:43 -0800891 *
892 * @param portEvent the Port Event with the port to add.
893 */
Yuta HIGUCHIbc67a052014-06-30 10:37:09 -0700894 @GuardedBy("topology.writeLock")
Pavlin Radoslavov3c9cc552014-02-20 09:58:38 -0800895 private void addPort(PortEvent portEvent) {
Jonathan Harte37e4e22014-05-13 19:12:02 -0700896 Switch sw = topology.getSwitch(portEvent.getDpid());
Ray Milkey269ffb92014-04-03 14:43:30 -0700897 if (sw == null) {
Jonathan Hartf1675202014-05-23 14:59:07 -0700898 log.debug("{} reordered because switch is null", portEvent);
Ray Milkey269ffb92014-04-03 14:43:30 -0700899 // Reordered event: delay the event in local cache
900 ByteBuffer id = portEvent.getIDasByteBuffer();
901 reorderedAddedPortEvents.put(id, portEvent);
902 return;
903 }
Pavlin Radoslavov3c9cc552014-02-20 09:58:38 -0800904
Yuta HIGUCHIb1e2ab72014-06-30 11:01:31 -0700905 Port port = sw.getPort(portEvent.getPortNumber());
Ray Milkey269ffb92014-04-03 14:43:30 -0700906 if (port == null) {
Yuta HIGUCHIb1e2ab72014-06-30 11:01:31 -0700907 port = new PortImpl(topology, sw, portEvent.getPortNumber());
Yuta HIGUCHIfa742842014-07-03 22:35:13 -0700908 topology.putPort(port);
Ray Milkey269ffb92014-04-03 14:43:30 -0700909 } else {
910 // TODO: Update the port attributes
Ray Milkey1aa71f82014-04-08 16:23:24 -0700911 log.debug("Update port attributes");
Ray Milkey269ffb92014-04-03 14:43:30 -0700912 }
913 apiAddedPortEvents.add(portEvent);
Pavlin Radoslavov3c9cc552014-02-20 09:58:38 -0800914 }
915
Pavlin Radoslavov734ff5a2014-02-26 10:20:43 -0800916 /**
Jonathan Harte37e4e22014-05-13 19:12:02 -0700917 * Remove a port from the topology.
Pavlin Radoslavov734ff5a2014-02-26 10:20:43 -0800918 *
919 * @param portEvent the Port Event with the port to remove.
920 */
Yuta HIGUCHIbc67a052014-06-30 10:37:09 -0700921 @GuardedBy("topology.writeLock")
Pavlin Radoslavov3c9cc552014-02-20 09:58:38 -0800922 private void removePort(PortEvent portEvent) {
Jonathan Harte37e4e22014-05-13 19:12:02 -0700923 Switch sw = topology.getSwitch(portEvent.getDpid());
Ray Milkey269ffb92014-04-03 14:43:30 -0700924 if (sw == null) {
925 log.warn("Parent Switch for Port {} already removed, ignoring",
926 portEvent);
927 return;
928 }
Pavlin Radoslavov3c9cc552014-02-20 09:58:38 -0800929
Yuta HIGUCHIb1e2ab72014-06-30 11:01:31 -0700930 Port port = sw.getPort(portEvent.getPortNumber());
Ray Milkey269ffb92014-04-03 14:43:30 -0700931 if (port == null) {
932 log.warn("Port {} already removed, ignoring", portEvent);
933 return;
934 }
Pavlin Radoslavov3c9cc552014-02-20 09:58:38 -0800935
Ray Milkey269ffb92014-04-03 14:43:30 -0700936 //
937 // Remove all Devices attached to the Port
938 //
939 ArrayList<DeviceEvent> devicesToRemove = new ArrayList<>();
940 for (Device device : port.getDevices()) {
941 log.debug("Removing Device {} on Port {}", device, portEvent);
942 DeviceEvent deviceEvent = new DeviceEvent(device.getMacAddress());
943 SwitchPort switchPort = new SwitchPort(port.getSwitch().getDpid(),
944 port.getNumber());
945 deviceEvent.addAttachmentPoint(switchPort);
946 devicesToRemove.add(deviceEvent);
947 }
Ray Milkeyb29e6262014-04-09 16:02:14 -0700948 for (DeviceEvent deviceEvent : devicesToRemove) {
Ray Milkey269ffb92014-04-03 14:43:30 -0700949 removeDevice(deviceEvent);
Ray Milkeyb29e6262014-04-09 16:02:14 -0700950 }
Pavlin Radoslavov3c9cc552014-02-20 09:58:38 -0800951
Ray Milkey269ffb92014-04-03 14:43:30 -0700952 //
953 // Remove all Links connected to the Port
954 //
955 Set<Link> links = new HashSet<>();
956 links.add(port.getOutgoingLink());
957 links.add(port.getIncomingLink());
958 ArrayList<LinkEvent> linksToRemove = new ArrayList<>();
959 for (Link link : links) {
Ray Milkeyb29e6262014-04-09 16:02:14 -0700960 if (link == null) {
Ray Milkey269ffb92014-04-03 14:43:30 -0700961 continue;
Ray Milkeyb29e6262014-04-09 16:02:14 -0700962 }
Ray Milkey269ffb92014-04-03 14:43:30 -0700963 log.debug("Removing Link {} on Port {}", link, portEvent);
964 LinkEvent linkEvent = new LinkEvent(link.getSrcSwitch().getDpid(),
965 link.getSrcPort().getNumber(),
966 link.getDstSwitch().getDpid(),
967 link.getDstPort().getNumber());
968 linksToRemove.add(linkEvent);
969 }
Ray Milkeyb29e6262014-04-09 16:02:14 -0700970 for (LinkEvent linkEvent : linksToRemove) {
Ray Milkey269ffb92014-04-03 14:43:30 -0700971 removeLink(linkEvent);
Ray Milkeyb29e6262014-04-09 16:02:14 -0700972 }
Pavlin Radoslavov3c9cc552014-02-20 09:58:38 -0800973
Ray Milkey269ffb92014-04-03 14:43:30 -0700974 // Remove the Port from the Switch
975 SwitchImpl switchImpl = getSwitchImpl(sw);
Yuta HIGUCHIfa742842014-07-03 22:35:13 -0700976 topology.removePort(port);
Pavlin Radoslavov74986ce2014-02-20 13:17:20 -0800977
Ray Milkey269ffb92014-04-03 14:43:30 -0700978 apiRemovedPortEvents.add(portEvent);
Pavlin Radoslavov3c9cc552014-02-20 09:58:38 -0800979 }
980
Pavlin Radoslavov734ff5a2014-02-26 10:20:43 -0800981 /**
Jonathan Harte37e4e22014-05-13 19:12:02 -0700982 * Add a link to the topology.
Pavlin Radoslavov734ff5a2014-02-26 10:20:43 -0800983 *
984 * @param linkEvent the Link Event with the link to add.
985 */
Yuta HIGUCHIbc67a052014-06-30 10:37:09 -0700986 @GuardedBy("topology.writeLock")
Pavlin Radoslavov3c9cc552014-02-20 09:58:38 -0800987 private void addLink(LinkEvent linkEvent) {
Yuta HIGUCHI8f3dfa32014-06-25 00:14:25 -0700988 Port srcPort = topology.getPort(linkEvent.getSrc().getDpid(),
Yuta HIGUCHIb1e2ab72014-06-30 11:01:31 -0700989 linkEvent.getSrc().getPortNumber());
Yuta HIGUCHI8f3dfa32014-06-25 00:14:25 -0700990 Port dstPort = topology.getPort(linkEvent.getDst().getDpid(),
Yuta HIGUCHIb1e2ab72014-06-30 11:01:31 -0700991 linkEvent.getDst().getPortNumber());
Ray Milkey269ffb92014-04-03 14:43:30 -0700992 if ((srcPort == null) || (dstPort == null)) {
Jonathan Hartf1675202014-05-23 14:59:07 -0700993 log.debug("{} reordered because {} port is null", linkEvent,
994 (srcPort == null) ? "src" : "dst");
995
Ray Milkey269ffb92014-04-03 14:43:30 -0700996 // Reordered event: delay the event in local cache
997 ByteBuffer id = linkEvent.getIDasByteBuffer();
998 reorderedAddedLinkEvents.put(id, linkEvent);
999 return;
1000 }
Pavlin Radoslavov3c9cc552014-02-20 09:58:38 -08001001
Ray Milkey269ffb92014-04-03 14:43:30 -07001002 // Get the Link instance from the Destination Port Incoming Link
1003 Link link = dstPort.getIncomingLink();
1004 assert (link == srcPort.getOutgoingLink());
1005 if (link == null) {
Jonathan Harte37e4e22014-05-13 19:12:02 -07001006 link = new LinkImpl(topology, srcPort, dstPort);
1007 topology.putLink(link);
Pavlin Radoslavov3c9cc552014-02-20 09:58:38 -08001008
Ray Milkey269ffb92014-04-03 14:43:30 -07001009 // Remove all Devices attached to the Ports
1010 ArrayList<DeviceEvent> devicesToRemove = new ArrayList<>();
1011 ArrayList<Port> ports = new ArrayList<>();
1012 ports.add(srcPort);
1013 ports.add(dstPort);
1014 for (Port port : ports) {
1015 for (Device device : port.getDevices()) {
1016 log.error("Device {} on Port {} should have been removed prior to adding Link {}",
1017 device, port, linkEvent);
1018 DeviceEvent deviceEvent =
1019 new DeviceEvent(device.getMacAddress());
1020 SwitchPort switchPort =
1021 new SwitchPort(port.getSwitch().getDpid(),
1022 port.getNumber());
1023 deviceEvent.addAttachmentPoint(switchPort);
1024 devicesToRemove.add(deviceEvent);
1025 }
1026 }
Ray Milkeyb29e6262014-04-09 16:02:14 -07001027 for (DeviceEvent deviceEvent : devicesToRemove) {
Ray Milkey269ffb92014-04-03 14:43:30 -07001028 removeDevice(deviceEvent);
Ray Milkeyb29e6262014-04-09 16:02:14 -07001029 }
Ray Milkey269ffb92014-04-03 14:43:30 -07001030 } else {
1031 // TODO: Update the link attributes
Ray Milkey1aa71f82014-04-08 16:23:24 -07001032 log.debug("Update link attributes");
Ray Milkey269ffb92014-04-03 14:43:30 -07001033 }
Pavlin Radoslavov74986ce2014-02-20 13:17:20 -08001034
Ray Milkey269ffb92014-04-03 14:43:30 -07001035 apiAddedLinkEvents.add(linkEvent);
Pavlin Radoslavov3c9cc552014-02-20 09:58:38 -08001036 }
1037
Pavlin Radoslavov734ff5a2014-02-26 10:20:43 -08001038 /**
Jonathan Harte37e4e22014-05-13 19:12:02 -07001039 * Remove a link from the topology.
Pavlin Radoslavov734ff5a2014-02-26 10:20:43 -08001040 *
1041 * @param linkEvent the Link Event with the link to remove.
1042 */
Yuta HIGUCHIbc67a052014-06-30 10:37:09 -07001043 @GuardedBy("topology.writeLock")
Pavlin Radoslavov3c9cc552014-02-20 09:58:38 -08001044 private void removeLink(LinkEvent linkEvent) {
Yuta HIGUCHI8f3dfa32014-06-25 00:14:25 -07001045 Port srcPort = topology.getPort(linkEvent.getSrc().getDpid(),
Yuta HIGUCHIb1e2ab72014-06-30 11:01:31 -07001046 linkEvent.getSrc().getPortNumber());
Ray Milkey269ffb92014-04-03 14:43:30 -07001047 if (srcPort == null) {
1048 log.warn("Src Port for Link {} already removed, ignoring",
1049 linkEvent);
1050 return;
1051 }
Pavlin Radoslavov3c9cc552014-02-20 09:58:38 -08001052
Yuta HIGUCHI8f3dfa32014-06-25 00:14:25 -07001053 Port dstPort = topology.getPort(linkEvent.getDst().getDpid(),
Yuta HIGUCHIb1e2ab72014-06-30 11:01:31 -07001054 linkEvent.getDst().getPortNumber());
Ray Milkey269ffb92014-04-03 14:43:30 -07001055 if (dstPort == null) {
1056 log.warn("Dst Port for Link {} already removed, ignoring",
1057 linkEvent);
1058 return;
1059 }
Pavlin Radoslavov3c9cc552014-02-20 09:58:38 -08001060
Ray Milkey269ffb92014-04-03 14:43:30 -07001061 //
1062 // Remove the Link instance from the Destination Port Incoming Link
1063 // and the Source Port Outgoing Link.
1064 //
1065 Link link = dstPort.getIncomingLink();
1066 if (link == null) {
1067 log.warn("Link {} already removed on destination Port", linkEvent);
1068 }
1069 link = srcPort.getOutgoingLink();
1070 if (link == null) {
1071 log.warn("Link {} already removed on src Port", linkEvent);
1072 }
Jonathan Hart25bd53e2014-04-30 23:44:09 -07001073
1074 // TODO should we check that we get the same link from each port?
1075 if (link != null) {
Jonathan Harte37e4e22014-05-13 19:12:02 -07001076 topology.removeLink(link);
Jonathan Hart25bd53e2014-04-30 23:44:09 -07001077 }
Pavlin Radoslavov74986ce2014-02-20 13:17:20 -08001078
Ray Milkey269ffb92014-04-03 14:43:30 -07001079 apiRemovedLinkEvents.add(linkEvent);
Pavlin Radoslavov3c9cc552014-02-20 09:58:38 -08001080 }
1081
Pavlin Radoslavov734ff5a2014-02-26 10:20:43 -08001082 /**
Jonathan Harte37e4e22014-05-13 19:12:02 -07001083 * Add a device to the topology.
Ray Milkey269ffb92014-04-03 14:43:30 -07001084 * <p/>
Pavlin Radoslavov734ff5a2014-02-26 10:20:43 -08001085 * TODO: Device-related work is incomplete.
1086 * TODO: Eventually, we might need to consider reordering
1087 * or addLink() and addDevice() events on the same port.
1088 *
1089 * @param deviceEvent the Device Event with the device to add.
1090 */
Yuta HIGUCHIbc67a052014-06-30 10:37:09 -07001091 @GuardedBy("topology.writeLock")
Pavlin Radoslavov3c9cc552014-02-20 09:58:38 -08001092 private void addDevice(DeviceEvent deviceEvent) {
Jonathan Harte37e4e22014-05-13 19:12:02 -07001093 log.debug("Adding a device to the topology with mac {}", deviceEvent.getMac());
1094 Device device = topology.getDeviceByMac(deviceEvent.getMac());
Pavlin Radoslavov3c9cc552014-02-20 09:58:38 -08001095
Ray Milkey269ffb92014-04-03 14:43:30 -07001096 if (device == null) {
Jonathan Harte37e4e22014-05-13 19:12:02 -07001097 log.debug("Existing device was not found in the Topology: Adding new device: mac {}", deviceEvent.getMac());
1098 device = new DeviceImpl(topology, deviceEvent.getMac());
Ray Milkey269ffb92014-04-03 14:43:30 -07001099 }
Pavlin Radoslavov3c9cc552014-02-20 09:58:38 -08001100
Ray Milkey269ffb92014-04-03 14:43:30 -07001101 DeviceImpl deviceImpl = getDeviceImpl(device);
Pavlin Radoslavov3c9cc552014-02-20 09:58:38 -08001102
Ray Milkey269ffb92014-04-03 14:43:30 -07001103 // Process each attachment point
1104 boolean attachmentFound = false;
1105 for (SwitchPort swp : deviceEvent.getAttachmentPoints()) {
1106 // Attached Ports must exist
Yuta HIGUCHIb1e2ab72014-06-30 11:01:31 -07001107 Port port = topology.getPort(swp.getDpid(), swp.getPortNumber());
Ray Milkey269ffb92014-04-03 14:43:30 -07001108 if (port == null) {
1109 // Reordered event: delay the event in local cache
1110 ByteBuffer id = deviceEvent.getIDasByteBuffer();
1111 reorderedAddedDeviceEvents.put(id, deviceEvent);
1112 continue;
1113 }
1114 // Attached Ports must not have Link
1115 if (port.getOutgoingLink() != null ||
1116 port.getIncomingLink() != null) {
1117 log.warn("Link (Out:{},In:{}) exist on the attachment point, skipping mutation.",
1118 port.getOutgoingLink(),
1119 port.getIncomingLink());
1120 continue;
1121 }
1122
1123 // Add Device <-> Port attachment
1124 PortImpl portImpl = getPortImpl(port);
Ray Milkey269ffb92014-04-03 14:43:30 -07001125 deviceImpl.addAttachmentPoint(port);
1126 attachmentFound = true;
1127 }
1128
TeruU5d2c9392014-06-09 20:02:02 -07001129 deviceImpl.setLastSeenTime(deviceEvent.getLastSeenTime());
1130
Jonathan Harte37e4e22014-05-13 19:12:02 -07001131 // Update the device in the topology
Ray Milkey269ffb92014-04-03 14:43:30 -07001132 if (attachmentFound) {
Jonathan Harte37e4e22014-05-13 19:12:02 -07001133 log.debug("Storing the device info into the Topology: mac {}", deviceEvent.getMac());
1134 topology.putDevice(device);
Ray Milkey269ffb92014-04-03 14:43:30 -07001135 apiAddedDeviceEvents.add(deviceEvent);
1136 }
Pavlin Radoslavov3c9cc552014-02-20 09:58:38 -08001137 }
1138
Pavlin Radoslavov734ff5a2014-02-26 10:20:43 -08001139 /**
Jonathan Harte37e4e22014-05-13 19:12:02 -07001140 * Remove a device from the topology.
Ray Milkey269ffb92014-04-03 14:43:30 -07001141 * <p/>
Pavlin Radoslavov734ff5a2014-02-26 10:20:43 -08001142 * TODO: Device-related work is incomplete.
1143 *
1144 * @param deviceEvent the Device Event with the device to remove.
1145 */
Yuta HIGUCHIbc67a052014-06-30 10:37:09 -07001146 @GuardedBy("topology.writeLock")
Pavlin Radoslavov3c9cc552014-02-20 09:58:38 -08001147 private void removeDevice(DeviceEvent deviceEvent) {
Yuta HIGUCHIfa742842014-07-03 22:35:13 -07001148 log.debug("Removing a device from the topology: mac {}", deviceEvent.getMac());
Jonathan Harte37e4e22014-05-13 19:12:02 -07001149 Device device = topology.getDeviceByMac(deviceEvent.getMac());
Ray Milkey269ffb92014-04-03 14:43:30 -07001150 if (device == null) {
1151 log.warn("Device {} already removed, ignoring", deviceEvent);
1152 return;
1153 }
Pavlin Radoslavov3c9cc552014-02-20 09:58:38 -08001154
Jonathan Harte37e4e22014-05-13 19:12:02 -07001155 topology.removeDevice(device);
Ray Milkey269ffb92014-04-03 14:43:30 -07001156 apiRemovedDeviceEvents.add(deviceEvent);
Pavlin Radoslavov3c9cc552014-02-20 09:58:38 -08001157 }
Jonathan Hart22eb9882014-02-11 15:52:59 -08001158
Pavlin Radoslavovc1cfde52014-02-19 11:35:29 -08001159 /**
Pavlin Radoslavov734ff5a2014-02-26 10:20:43 -08001160 * Get the SwitchImpl-casted switch implementation.
Pavlin Radoslavovc1cfde52014-02-19 11:35:29 -08001161 *
Pavlin Radoslavov734ff5a2014-02-26 10:20:43 -08001162 * @param sw the Switch to cast.
1163 * @return the SwitchImpl-casted switch implementation.
Pavlin Radoslavovc1cfde52014-02-19 11:35:29 -08001164 */
Pavlin Radoslavovc1cfde52014-02-19 11:35:29 -08001165 private SwitchImpl getSwitchImpl(Switch sw) {
Ray Milkey269ffb92014-04-03 14:43:30 -07001166 if (sw instanceof SwitchImpl) {
1167 return (SwitchImpl) sw;
1168 }
1169 throw new ClassCastException("SwitchImpl expected, but found: " + sw);
Pavlin Radoslavovc1cfde52014-02-19 11:35:29 -08001170 }
1171
Pavlin Radoslavov734ff5a2014-02-26 10:20:43 -08001172 /**
1173 * Get the PortImpl-casted port implementation.
1174 *
1175 * @param port the Port to cast.
1176 * @return the PortImpl-casted port implementation.
1177 */
1178 private PortImpl getPortImpl(Port port) {
Ray Milkey269ffb92014-04-03 14:43:30 -07001179 if (port instanceof PortImpl) {
1180 return (PortImpl) port;
1181 }
1182 throw new ClassCastException("PortImpl expected, but found: " + port);
Pavlin Radoslavovc1cfde52014-02-19 11:35:29 -08001183 }
1184
Pavlin Radoslavov734ff5a2014-02-26 10:20:43 -08001185 /**
1186 * Get the LinkImpl-casted link implementation.
1187 *
1188 * @param link the Link to cast.
1189 * @return the LinkImpl-casted link implementation.
1190 */
1191 private LinkImpl getLinkImpl(Link link) {
Ray Milkey269ffb92014-04-03 14:43:30 -07001192 if (link instanceof LinkImpl) {
1193 return (LinkImpl) link;
1194 }
1195 throw new ClassCastException("LinkImpl expected, but found: " + link);
Pavlin Radoslavovc1cfde52014-02-19 11:35:29 -08001196 }
1197
Pavlin Radoslavov734ff5a2014-02-26 10:20:43 -08001198 /**
1199 * Get the DeviceImpl-casted device implementation.
1200 *
1201 * @param device the Device to cast.
1202 * @return the DeviceImpl-casted device implementation.
1203 */
1204 private DeviceImpl getDeviceImpl(Device device) {
Ray Milkey269ffb92014-04-03 14:43:30 -07001205 if (device instanceof DeviceImpl) {
1206 return (DeviceImpl) device;
1207 }
1208 throw new ClassCastException("DeviceImpl expected, but found: " + device);
Pavlin Radoslavovc1cfde52014-02-19 11:35:29 -08001209 }
1210
Pavlin Radoslavov734ff5a2014-02-26 10:20:43 -08001211 /**
1212 * Read the whole topology from the database.
1213 *
1214 * @return a collection of EventEntry-encapsulated Topology Events for
1215 * the whole topology.
1216 */
Pavlin Radoslavov018d5332014-02-19 23:08:35 -08001217 private Collection<EventEntry<TopologyEvent>> readWholeTopologyFromDB() {
Ray Milkey269ffb92014-04-03 14:43:30 -07001218 Collection<EventEntry<TopologyEvent>> collection =
1219 new LinkedList<EventEntry<TopologyEvent>>();
Pavlin Radoslavov018d5332014-02-19 23:08:35 -08001220
Ray Milkey269ffb92014-04-03 14:43:30 -07001221 // XXX May need to clear whole topology first, depending on
1222 // how we initially subscribe to replication events
Pavlin Radoslavovc1cfde52014-02-19 11:35:29 -08001223
Ray Milkey269ffb92014-04-03 14:43:30 -07001224 // Add all active switches
1225 for (KVSwitch sw : KVSwitch.getAllSwitches()) {
1226 if (sw.getStatus() != KVSwitch.STATUS.ACTIVE) {
1227 continue;
1228 }
Pavlin Radoslavov018d5332014-02-19 23:08:35 -08001229
Ray Milkey269ffb92014-04-03 14:43:30 -07001230 SwitchEvent switchEvent = new SwitchEvent(sw.getDpid());
1231 TopologyEvent topologyEvent = new TopologyEvent(switchEvent);
1232 EventEntry<TopologyEvent> eventEntry =
1233 new EventEntry<TopologyEvent>(EventEntry.Type.ENTRY_ADD,
1234 topologyEvent);
1235 collection.add(eventEntry);
1236 }
Yuta HIGUCHIa536e762014-02-17 21:47:28 -08001237
Ray Milkey269ffb92014-04-03 14:43:30 -07001238 // Add all active ports
1239 for (KVPort p : KVPort.getAllPorts()) {
1240 if (p.getStatus() != KVPort.STATUS.ACTIVE) {
1241 continue;
1242 }
Pavlin Radoslavov018d5332014-02-19 23:08:35 -08001243
Ray Milkey269ffb92014-04-03 14:43:30 -07001244 PortEvent portEvent = new PortEvent(p.getDpid(), p.getNumber());
1245 TopologyEvent topologyEvent = new TopologyEvent(portEvent);
1246 EventEntry<TopologyEvent> eventEntry =
1247 new EventEntry<TopologyEvent>(EventEntry.Type.ENTRY_ADD,
1248 topologyEvent);
1249 collection.add(eventEntry);
1250 }
Yuta HIGUCHIa536e762014-02-17 21:47:28 -08001251
TeruU28adcc32014-04-15 17:57:35 -07001252 for (KVDevice d : KVDevice.getAllDevices()) {
1253 DeviceEvent devEvent = new DeviceEvent(MACAddress.valueOf(d.getMac()));
1254 for (byte[] portId : d.getAllPortIds()) {
Jonathan Hartc00f5c22014-06-10 15:14:40 -07001255 devEvent.addAttachmentPoint(
1256 new SwitchPort(KVPort.getDpidFromKey(portId),
1257 KVPort.getNumberFromKey(portId)));
TeruU28adcc32014-04-15 17:57:35 -07001258 }
1259 }
Pavlin Radoslavovc1cfde52014-02-19 11:35:29 -08001260
Ray Milkey269ffb92014-04-03 14:43:30 -07001261 for (KVLink l : KVLink.getAllLinks()) {
1262 LinkEvent linkEvent = new LinkEvent(l.getSrc().dpid,
1263 l.getSrc().number,
1264 l.getDst().dpid,
1265 l.getDst().number);
1266 TopologyEvent topologyEvent = new TopologyEvent(linkEvent);
1267 EventEntry<TopologyEvent> eventEntry =
1268 new EventEntry<TopologyEvent>(EventEntry.Type.ENTRY_ADD,
1269 topologyEvent);
1270 collection.add(eventEntry);
1271 }
Pavlin Radoslavov018d5332014-02-19 23:08:35 -08001272
Ray Milkey269ffb92014-04-03 14:43:30 -07001273 return collection;
Pavlin Radoslavovc1cfde52014-02-19 11:35:29 -08001274 }
Jonathan Hart062a2e82014-02-03 09:41:57 -08001275}