blob: 2e95c6cf4bb4c6b131584d48d54cc16a30df92fc [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 HIGUCHIe2a4e172014-07-03 10:50:39 -070029import net.onrc.onos.core.util.PortNumber;
Yuta HIGUCHI5c8cbeb2014-06-27 11:13:48 -070030import net.onrc.onos.core.util.SwitchPort;
Pavlin Radoslavov4eaab992014-07-03 18:39:42 -070031import net.onrc.onos.core.util.serializers.KryoFactory;
Yuta HIGUCHI5c8cbeb2014-06-27 11:13:48 -070032
Jonathan Hart062a2e82014-02-03 09:41:57 -080033import org.slf4j.Logger;
34import org.slf4j.LoggerFactory;
35
Pavlin Radoslavov4eaab992014-07-03 18:39:42 -070036import com.esotericsoftware.kryo.Kryo;
37
Yuta HIGUCHI181d34d2014-02-05 15:05:46 -080038/**
Jonathan Harte37e4e22014-05-13 19:12:02 -070039 * The TopologyManager receives topology updates from the southbound discovery
40 * modules and from other ONOS instances. These updates are processed and
41 * applied to the in-memory topology instance.
Ray Milkey269ffb92014-04-03 14:43:30 -070042 * <p/>
Yuta HIGUCHI4bfdd532014-02-07 13:47:36 -080043 * - Maintain Invariant/Relationships between Topology Objects.
Ray Milkey269ffb92014-04-03 14:43:30 -070044 * <p/>
Yuta HIGUCHI765cd0d2014-02-06 12:46:41 -080045 * TODO To be synchronized based on TopologyEvent Notification.
Ray Milkey269ffb92014-04-03 14:43:30 -070046 * <p/>
Yuta HIGUCHIcb951982014-02-11 13:31:44 -080047 * TODO TBD: Caller is expected to maintain parent/child calling order. Parent
Yuta HIGUCHI1c700102014-02-12 16:30:52 -080048 * Object must exist before adding sub component(Add Switch -> Port).
Ray Milkey269ffb92014-04-03 14:43:30 -070049 * <p/>
Yuta HIGUCHI4bfdd532014-02-07 13:47:36 -080050 * TODO TBD: This class may delay the requested change to handle event
51 * re-ordering. e.g.) Link Add came in, but Switch was not there.
Yuta HIGUCHI181d34d2014-02-05 15:05:46 -080052 */
Jonathan Harte37e4e22014-05-13 19:12:02 -070053public class TopologyManager implements TopologyDiscoveryInterface {
Jonathan Hart062a2e82014-02-03 09:41:57 -080054
Yuta HIGUCHI80829d12014-02-05 20:16:56 -080055 private static final Logger log = LoggerFactory
Ray Milkey269ffb92014-04-03 14:43:30 -070056 .getLogger(TopologyManager.class);
Yuta HIGUCHIcd922f42014-02-11 18:59:11 -080057
Pavlin Radoslavov721a2e02014-02-14 23:40:14 -080058 private IEventChannel<byte[], TopologyEvent> eventChannel;
Jonathan Hart10a7e2b2014-02-21 18:30:08 -080059 public static final String EVENT_CHANNEL_NAME = "onos.topology";
Pavlin Radoslavov721a2e02014-02-14 23:40:14 -080060 private EventHandler eventHandler = new EventHandler();
61
Jonathan Harte37e4e22014-05-13 19:12:02 -070062 private final TopologyDatastore datastore;
63 private final TopologyImpl topology = new TopologyImpl();
Yuta HIGUCHI170229f2014-02-17 15:47:54 -080064 private final IControllerRegistryService registryService;
Jonathan Harte37e4e22014-05-13 19:12:02 -070065 private CopyOnWriteArrayList<ITopologyListener> topologyListeners;
Pavlin Radoslavov4eaab992014-07-03 18:39:42 -070066 private Kryo kryo = KryoFactory.newKryoObject();
Yuta HIGUCHI181d34d2014-02-05 15:05:46 -080067
Pavlin Radoslavov706add22014-02-20 12:15:59 -080068 //
69 // Local state for keeping track of reordered events.
70 // NOTE: Switch Events are not affected by the event reordering.
71 //
72 private Map<ByteBuffer, PortEvent> reorderedAddedPortEvents =
Ray Milkey269ffb92014-04-03 14:43:30 -070073 new HashMap<ByteBuffer, PortEvent>();
Pavlin Radoslavov706add22014-02-20 12:15:59 -080074 private Map<ByteBuffer, LinkEvent> reorderedAddedLinkEvents =
Ray Milkey269ffb92014-04-03 14:43:30 -070075 new HashMap<ByteBuffer, LinkEvent>();
Pavlin Radoslavov706add22014-02-20 12:15:59 -080076 private Map<ByteBuffer, DeviceEvent> reorderedAddedDeviceEvents =
Ray Milkey269ffb92014-04-03 14:43:30 -070077 new HashMap<ByteBuffer, DeviceEvent>();
Pavlin Radoslavov018d5332014-02-19 23:08:35 -080078
Pavlin Radoslavov74986ce2014-02-20 13:17:20 -080079 //
Pavlin Radoslavov26d83402014-02-20 15:24:30 -080080 // Local state for keeping track of locally discovered events so we can
81 // cleanup properly when a Switch or Port is removed.
82 //
Yuta HIGUCHIbc67a052014-06-30 10:37:09 -070083 // We keep all Port, (incoming) Link and Device events per Switch DPID:
Pavlin Radoslavov26d83402014-02-20 15:24:30 -080084 // - If a switch goes down, we remove all corresponding Port, Link and
85 // Device events.
86 // - If a port on a switch goes down, we remove all corresponding Link
Yuta HIGUCHIbc67a052014-06-30 10:37:09 -070087 // and Device events discovered by this instance.
88 //
89 // How to handle side-effect of remote events.
90 // - Remote Port Down event -> Link Down
91 // Not handled. (XXX Shouldn't it be removed from discovered.. Map)
92 // - Remote Device Added -> lose ownership of Device)
93 // Not handled. (XXX Shouldn't it be removed from discovered.. Map)
94 //
95 // XXX Domain knowledge based invariant maintenance should be moved to
96 // driver module, since the invariant may be different on optical, etc.
97 //
98 // What happens on leadership change?
99 // - Probably should: remove from discovered.. Maps, but not send DELETE events
100 // XXX Switch/Port can be rediscovered by new leader, but Link, Device?
101 // - Current: There is no way to recognize leadership change?
102 // ZookeeperRegistry.requestControl(long, ControlChangeCallback)
103 // is the only way to register listener, and it allows only 1 listener,
104 // which is already used by Controller class.
105 //
106 // FIXME Replace with concurrent variant.
107 // #removeSwitchDiscoveryEvent(SwitchEvent) runs in different thread.
Pavlin Radoslavov26d83402014-02-20 15:24:30 -0800108 //
Yuta HIGUCHI8f3dfa32014-06-25 00:14:25 -0700109 private Map<Dpid, Map<ByteBuffer, PortEvent>> discoveredAddedPortEvents =
Ray Milkey269ffb92014-04-03 14:43:30 -0700110 new HashMap<>();
Yuta HIGUCHI8f3dfa32014-06-25 00:14:25 -0700111 private Map<Dpid, Map<ByteBuffer, LinkEvent>> discoveredAddedLinkEvents =
Ray Milkey269ffb92014-04-03 14:43:30 -0700112 new HashMap<>();
Yuta HIGUCHI8f3dfa32014-06-25 00:14:25 -0700113 private Map<Dpid, Map<ByteBuffer, DeviceEvent>> discoveredAddedDeviceEvents =
Ray Milkey269ffb92014-04-03 14:43:30 -0700114 new HashMap<>();
Pavlin Radoslavov26d83402014-02-20 15:24:30 -0800115
116 //
Pavlin Radoslavov74986ce2014-02-20 13:17:20 -0800117 // Local state for keeping track of the application event notifications
118 //
Yuta HIGUCHIbc67a052014-06-30 10:37:09 -0700119 // - Queue of events, which will be dispatched to local listeners
120 // on next notification.
Yuta HIGUCHI703696c2014-06-25 20:36:45 -0700121
122 private List<SwitchEvent> apiAddedSwitchEvents = new LinkedList<>();
123 private List<SwitchEvent> apiRemovedSwitchEvents = new LinkedList<>();
124 private List<PortEvent> apiAddedPortEvents = new LinkedList<>();
125 private List<PortEvent> apiRemovedPortEvents = new LinkedList<>();
126 private List<LinkEvent> apiAddedLinkEvents = new LinkedList<>();
127 private List<LinkEvent> apiRemovedLinkEvents = new LinkedList<>();
128 private List<DeviceEvent> apiAddedDeviceEvents = new LinkedList<>();
129 private List<DeviceEvent> apiRemovedDeviceEvents = new LinkedList<>();
Pavlin Radoslavov74986ce2014-02-20 13:17:20 -0800130
Pavlin Radoslavovc1cfde52014-02-19 11:35:29 -0800131 /**
132 * Constructor.
133 *
Jonathan Harte37e4e22014-05-13 19:12:02 -0700134 * @param registryService the Registry Service to use.
135 * @param topologyListeners the collection of topology listeners to use.
Pavlin Radoslavovc1cfde52014-02-19 11:35:29 -0800136 */
137 public TopologyManager(IControllerRegistryService registryService,
Jonathan Harte37e4e22014-05-13 19:12:02 -0700138 CopyOnWriteArrayList<ITopologyListener> topologyListeners) {
139 datastore = new TopologyDatastore();
Ray Milkey269ffb92014-04-03 14:43:30 -0700140 this.registryService = registryService;
Jonathan Harte37e4e22014-05-13 19:12:02 -0700141 this.topologyListeners = topologyListeners;
Yuta HIGUCHI80829d12014-02-05 20:16:56 -0800142 }
Yuta HIGUCHI181d34d2014-02-05 15:05:46 -0800143
Pavlin Radoslavovc1cfde52014-02-19 11:35:29 -0800144 /**
Jonathan Harte37e4e22014-05-13 19:12:02 -0700145 * Get the Topology.
Pavlin Radoslavovc1cfde52014-02-19 11:35:29 -0800146 *
Jonathan Harte37e4e22014-05-13 19:12:02 -0700147 * @return the Topology.
Pavlin Radoslavovc1cfde52014-02-19 11:35:29 -0800148 */
Jonathan Harte37e4e22014-05-13 19:12:02 -0700149 Topology getTopology() {
150 return topology;
Pavlin Radoslavov6d224ee2014-02-18 16:43:15 -0800151 }
152
Yuta HIGUCHI4bfdd532014-02-07 13:47:36 -0800153 /**
Pavlin Radoslavov721a2e02014-02-14 23:40:14 -0800154 * Event handler class.
155 */
156 private class EventHandler extends Thread implements
Ray Milkey269ffb92014-04-03 14:43:30 -0700157 IEventChannelListener<byte[], TopologyEvent> {
158 private BlockingQueue<EventEntry<TopologyEvent>> topologyEvents =
159 new LinkedBlockingQueue<EventEntry<TopologyEvent>>();
Pavlin Radoslavov721a2e02014-02-14 23:40:14 -0800160
Ray Milkey269ffb92014-04-03 14:43:30 -0700161 /**
162 * Startup processing.
163 */
164 private void startup() {
165 //
166 // TODO: Read all state from the database:
167 //
168 // Collection<EventEntry<TopologyEvent>> collection =
169 // readWholeTopologyFromDB();
170 //
171 // For now, as a shortcut we read it from the datagrid
172 //
Ray Milkey5df613b2014-04-15 10:50:56 -0700173 Collection<TopologyEvent> allTopologyEvents =
Ray Milkey269ffb92014-04-03 14:43:30 -0700174 eventChannel.getAllEntries();
175 Collection<EventEntry<TopologyEvent>> collection =
176 new LinkedList<EventEntry<TopologyEvent>>();
Pavlin Radoslavov721a2e02014-02-14 23:40:14 -0800177
Ray Milkey5df613b2014-04-15 10:50:56 -0700178 for (TopologyEvent topologyEvent : allTopologyEvents) {
Ray Milkey269ffb92014-04-03 14:43:30 -0700179 EventEntry<TopologyEvent> eventEntry =
180 new EventEntry<TopologyEvent>(EventEntry.Type.ENTRY_ADD,
181 topologyEvent);
182 collection.add(eventEntry);
183 }
184 processEvents(collection);
185 }
Pavlin Radoslavov721a2e02014-02-14 23:40:14 -0800186
Ray Milkey269ffb92014-04-03 14:43:30 -0700187 /**
188 * Run the thread.
189 */
190 @Override
191 public void run() {
192 Collection<EventEntry<TopologyEvent>> collection =
193 new LinkedList<EventEntry<TopologyEvent>>();
Pavlin Radoslavov721a2e02014-02-14 23:40:14 -0800194
Ray Milkey269ffb92014-04-03 14:43:30 -0700195 this.setName("TopologyManager.EventHandler " + this.getId());
196 startup();
Pavlin Radoslavov721a2e02014-02-14 23:40:14 -0800197
Ray Milkey269ffb92014-04-03 14:43:30 -0700198 //
199 // The main loop
200 //
Pavlin Radoslavov8e881a42014-06-24 16:58:07 -0700201 while (true) {
202 try {
203 EventEntry<TopologyEvent> eventEntry =
204 topologyEvents.take();
Ray Milkey269ffb92014-04-03 14:43:30 -0700205 collection.add(eventEntry);
206 topologyEvents.drainTo(collection);
Pavlin Radoslavov721a2e02014-02-14 23:40:14 -0800207
Ray Milkey269ffb92014-04-03 14:43:30 -0700208 processEvents(collection);
209 collection.clear();
Pavlin Radoslavov8e881a42014-06-24 16:58:07 -0700210 } catch (Exception exception) {
211 log.debug("Exception processing Topology Events: ",
212 exception);
Ray Milkey269ffb92014-04-03 14:43:30 -0700213 }
Ray Milkey269ffb92014-04-03 14:43:30 -0700214 }
215 }
Pavlin Radoslavov721a2e02014-02-14 23:40:14 -0800216
Ray Milkey269ffb92014-04-03 14:43:30 -0700217 /**
218 * Process all topology events.
219 *
220 * @param events the events to process.
221 */
222 private void processEvents(Collection<EventEntry<TopologyEvent>> events) {
223 // Local state for computing the final set of events
224 Map<ByteBuffer, SwitchEvent> addedSwitchEvents = new HashMap<>();
225 Map<ByteBuffer, SwitchEvent> removedSwitchEvents = new HashMap<>();
226 Map<ByteBuffer, PortEvent> addedPortEvents = new HashMap<>();
227 Map<ByteBuffer, PortEvent> removedPortEvents = new HashMap<>();
228 Map<ByteBuffer, LinkEvent> addedLinkEvents = new HashMap<>();
229 Map<ByteBuffer, LinkEvent> removedLinkEvents = new HashMap<>();
230 Map<ByteBuffer, DeviceEvent> addedDeviceEvents = new HashMap<>();
231 Map<ByteBuffer, DeviceEvent> removedDeviceEvents = new HashMap<>();
Pavlin Radoslavov3c9cc552014-02-20 09:58:38 -0800232
Ray Milkey269ffb92014-04-03 14:43:30 -0700233 //
234 // Classify and suppress matching events
235 //
236 for (EventEntry<TopologyEvent> event : events) {
237 TopologyEvent topologyEvent = event.eventData();
238 SwitchEvent switchEvent = topologyEvent.switchEvent;
239 PortEvent portEvent = topologyEvent.portEvent;
240 LinkEvent linkEvent = topologyEvent.linkEvent;
241 DeviceEvent deviceEvent = topologyEvent.deviceEvent;
Pavlin Radoslavov018d5332014-02-19 23:08:35 -0800242
Ray Milkey269ffb92014-04-03 14:43:30 -0700243 //
244 // Extract the events
245 //
246 switch (event.eventType()) {
247 case ENTRY_ADD:
248 log.debug("Topology event ENTRY_ADD: {}", topologyEvent);
249 if (switchEvent != null) {
250 ByteBuffer id = switchEvent.getIDasByteBuffer();
251 addedSwitchEvents.put(id, switchEvent);
252 removedSwitchEvents.remove(id);
253 // Switch Events are not affected by event reordering
254 }
255 if (portEvent != null) {
256 ByteBuffer id = portEvent.getIDasByteBuffer();
257 addedPortEvents.put(id, portEvent);
258 removedPortEvents.remove(id);
259 reorderedAddedPortEvents.remove(id);
260 }
261 if (linkEvent != null) {
262 ByteBuffer id = linkEvent.getIDasByteBuffer();
263 addedLinkEvents.put(id, linkEvent);
264 removedLinkEvents.remove(id);
265 reorderedAddedLinkEvents.remove(id);
266 }
267 if (deviceEvent != null) {
268 ByteBuffer id = deviceEvent.getIDasByteBuffer();
269 addedDeviceEvents.put(id, deviceEvent);
270 removedDeviceEvents.remove(id);
271 reorderedAddedDeviceEvents.remove(id);
272 }
273 break;
274 case ENTRY_REMOVE:
275 log.debug("Topology event ENTRY_REMOVE: {}", topologyEvent);
276 if (switchEvent != null) {
277 ByteBuffer id = switchEvent.getIDasByteBuffer();
278 addedSwitchEvents.remove(id);
279 removedSwitchEvents.put(id, switchEvent);
280 // Switch Events are not affected by event reordering
281 }
282 if (portEvent != null) {
283 ByteBuffer id = portEvent.getIDasByteBuffer();
284 addedPortEvents.remove(id);
285 removedPortEvents.put(id, portEvent);
286 reorderedAddedPortEvents.remove(id);
287 }
288 if (linkEvent != null) {
289 ByteBuffer id = linkEvent.getIDasByteBuffer();
290 addedLinkEvents.remove(id);
291 removedLinkEvents.put(id, linkEvent);
292 reorderedAddedLinkEvents.remove(id);
293 }
294 if (deviceEvent != null) {
295 ByteBuffer id = deviceEvent.getIDasByteBuffer();
296 addedDeviceEvents.remove(id);
297 removedDeviceEvents.put(id, deviceEvent);
298 reorderedAddedDeviceEvents.remove(id);
299 }
300 break;
Ray Milkey0b122ed2014-04-14 10:06:03 -0700301 default:
302 log.error("Unknown topology event {}",
303 event.eventType());
Ray Milkey269ffb92014-04-03 14:43:30 -0700304 }
305 }
Pavlin Radoslavov3c9cc552014-02-20 09:58:38 -0800306
Ray Milkey269ffb92014-04-03 14:43:30 -0700307 //
Jonathan Harte37e4e22014-05-13 19:12:02 -0700308 // Lock the topology while it is modified
Ray Milkey269ffb92014-04-03 14:43:30 -0700309 //
Jonathan Harte37e4e22014-05-13 19:12:02 -0700310 topology.acquireWriteLock();
Pavlin Radoslavov8ffb8bf2014-02-20 15:34:26 -0800311
Ray Milkey269ffb92014-04-03 14:43:30 -0700312 try {
313 //
314 // Apply the classified events.
315 //
316 // Apply the "add" events in the proper order:
317 // switch, port, link, device
318 //
Ray Milkeyb29e6262014-04-09 16:02:14 -0700319 for (SwitchEvent switchEvent : addedSwitchEvents.values()) {
Ray Milkey269ffb92014-04-03 14:43:30 -0700320 addSwitch(switchEvent);
Ray Milkeyb29e6262014-04-09 16:02:14 -0700321 }
322 for (PortEvent portEvent : addedPortEvents.values()) {
Ray Milkey269ffb92014-04-03 14:43:30 -0700323 addPort(portEvent);
Ray Milkeyb29e6262014-04-09 16:02:14 -0700324 }
325 for (LinkEvent linkEvent : addedLinkEvents.values()) {
Ray Milkey269ffb92014-04-03 14:43:30 -0700326 addLink(linkEvent);
Ray Milkeyb29e6262014-04-09 16:02:14 -0700327 }
328 for (DeviceEvent deviceEvent : addedDeviceEvents.values()) {
Ray Milkey269ffb92014-04-03 14:43:30 -0700329 addDevice(deviceEvent);
Ray Milkeyb29e6262014-04-09 16:02:14 -0700330 }
Ray Milkey269ffb92014-04-03 14:43:30 -0700331 //
332 // Apply the "remove" events in the reverse order:
333 // device, link, port, switch
334 //
Ray Milkeyb29e6262014-04-09 16:02:14 -0700335 for (DeviceEvent deviceEvent : removedDeviceEvents.values()) {
Ray Milkey269ffb92014-04-03 14:43:30 -0700336 removeDevice(deviceEvent);
Ray Milkeyb29e6262014-04-09 16:02:14 -0700337 }
338 for (LinkEvent linkEvent : removedLinkEvents.values()) {
Ray Milkey269ffb92014-04-03 14:43:30 -0700339 removeLink(linkEvent);
Ray Milkeyb29e6262014-04-09 16:02:14 -0700340 }
341 for (PortEvent portEvent : removedPortEvents.values()) {
Ray Milkey269ffb92014-04-03 14:43:30 -0700342 removePort(portEvent);
Ray Milkeyb29e6262014-04-09 16:02:14 -0700343 }
344 for (SwitchEvent switchEvent : removedSwitchEvents.values()) {
Ray Milkey269ffb92014-04-03 14:43:30 -0700345 removeSwitch(switchEvent);
Ray Milkeyb29e6262014-04-09 16:02:14 -0700346 }
Yuta HIGUCHI3aca81a2014-02-23 12:41:19 -0800347
Ray Milkey269ffb92014-04-03 14:43:30 -0700348 //
349 // Apply reordered events
350 //
351 applyReorderedEvents(!addedSwitchEvents.isEmpty(),
352 !addedPortEvents.isEmpty());
Yuta HIGUCHI3aca81a2014-02-23 12:41:19 -0800353
Ray Milkey269ffb92014-04-03 14:43:30 -0700354 } finally {
355 //
Jonathan Harte37e4e22014-05-13 19:12:02 -0700356 // Topology modifications completed: Release the lock
Ray Milkey269ffb92014-04-03 14:43:30 -0700357 //
Jonathan Harte37e4e22014-05-13 19:12:02 -0700358 topology.releaseWriteLock();
Ray Milkey269ffb92014-04-03 14:43:30 -0700359 }
Yuta HIGUCHI3aca81a2014-02-23 12:41:19 -0800360
Ray Milkey269ffb92014-04-03 14:43:30 -0700361 //
362 // Dispatch the Topology Notification Events to the applications
363 //
Jonathan Harte37e4e22014-05-13 19:12:02 -0700364 dispatchTopologyEvents();
Ray Milkey269ffb92014-04-03 14:43:30 -0700365 }
Pavlin Radoslavov721a2e02014-02-14 23:40:14 -0800366
Ray Milkey269ffb92014-04-03 14:43:30 -0700367 /**
368 * Receive a notification that an entry is added.
369 *
370 * @param value the value for the entry.
371 */
372 @Override
373 public void entryAdded(TopologyEvent value) {
374 EventEntry<TopologyEvent> eventEntry =
375 new EventEntry<TopologyEvent>(EventEntry.Type.ENTRY_ADD,
376 value);
377 topologyEvents.add(eventEntry);
378 }
Pavlin Radoslavov721a2e02014-02-14 23:40:14 -0800379
Ray Milkey269ffb92014-04-03 14:43:30 -0700380 /**
381 * Receive a notification that an entry is removed.
382 *
383 * @param value the value for the entry.
384 */
385 @Override
386 public void entryRemoved(TopologyEvent value) {
387 EventEntry<TopologyEvent> eventEntry =
388 new EventEntry<TopologyEvent>(EventEntry.Type.ENTRY_REMOVE,
389 value);
390 topologyEvents.add(eventEntry);
391 }
Pavlin Radoslavov721a2e02014-02-14 23:40:14 -0800392
Ray Milkey269ffb92014-04-03 14:43:30 -0700393 /**
394 * Receive a notification that an entry is updated.
395 *
396 * @param value the value for the entry.
397 */
398 @Override
399 public void entryUpdated(TopologyEvent value) {
400 // NOTE: The ADD and UPDATE events are processed in same way
401 entryAdded(value);
402 }
Pavlin Radoslavov721a2e02014-02-14 23:40:14 -0800403 }
404
405 /**
406 * Startup processing.
407 *
408 * @param datagridService the datagrid service to use.
409 */
410 void startup(IDatagridService datagridService) {
Ray Milkey269ffb92014-04-03 14:43:30 -0700411 eventChannel = datagridService.addListener(EVENT_CHANNEL_NAME,
412 eventHandler,
413 byte[].class,
414 TopologyEvent.class);
415 eventHandler.start();
Pavlin Radoslavov721a2e02014-02-14 23:40:14 -0800416 }
417
Pavlin Radoslavov74986ce2014-02-20 13:17:20 -0800418 /**
Jonathan Harte37e4e22014-05-13 19:12:02 -0700419 * Dispatch Topology Events to the listeners.
Pavlin Radoslavov74986ce2014-02-20 13:17:20 -0800420 */
Jonathan Harte37e4e22014-05-13 19:12:02 -0700421 private void dispatchTopologyEvents() {
Ray Milkey269ffb92014-04-03 14:43:30 -0700422 if (apiAddedSwitchEvents.isEmpty() &&
423 apiRemovedSwitchEvents.isEmpty() &&
424 apiAddedPortEvents.isEmpty() &&
425 apiRemovedPortEvents.isEmpty() &&
426 apiAddedLinkEvents.isEmpty() &&
427 apiRemovedLinkEvents.isEmpty() &&
428 apiAddedDeviceEvents.isEmpty() &&
429 apiRemovedDeviceEvents.isEmpty()) {
430 return; // No events to dispatch
431 }
Pavlin Radoslavov74986ce2014-02-20 13:17:20 -0800432
Ray Milkey269ffb92014-04-03 14:43:30 -0700433 if (log.isDebugEnabled()) {
434 //
435 // Debug statements
436 // TODO: Those statements should be removed in the future
437 //
Ray Milkeyb29e6262014-04-09 16:02:14 -0700438 for (SwitchEvent switchEvent : apiAddedSwitchEvents) {
Jonathan Harte37e4e22014-05-13 19:12:02 -0700439 log.debug("Dispatch Topology Event: ADDED {}", switchEvent);
Ray Milkeyb29e6262014-04-09 16:02:14 -0700440 }
441 for (SwitchEvent switchEvent : apiRemovedSwitchEvents) {
Jonathan Harte37e4e22014-05-13 19:12:02 -0700442 log.debug("Dispatch Topology Event: REMOVED {}", switchEvent);
Ray Milkeyb29e6262014-04-09 16:02:14 -0700443 }
444 for (PortEvent portEvent : apiAddedPortEvents) {
Jonathan Harte37e4e22014-05-13 19:12:02 -0700445 log.debug("Dispatch Topology Event: ADDED {}", portEvent);
Ray Milkeyb29e6262014-04-09 16:02:14 -0700446 }
447 for (PortEvent portEvent : apiRemovedPortEvents) {
Jonathan Harte37e4e22014-05-13 19:12:02 -0700448 log.debug("Dispatch Topology Event: REMOVED {}", portEvent);
Ray Milkeyb29e6262014-04-09 16:02:14 -0700449 }
450 for (LinkEvent linkEvent : apiAddedLinkEvents) {
Jonathan Harte37e4e22014-05-13 19:12:02 -0700451 log.debug("Dispatch Topology Event: ADDED {}", linkEvent);
Ray Milkeyb29e6262014-04-09 16:02:14 -0700452 }
453 for (LinkEvent linkEvent : apiRemovedLinkEvents) {
Jonathan Harte37e4e22014-05-13 19:12:02 -0700454 log.debug("Dispatch Topology Event: REMOVED {}", linkEvent);
Ray Milkeyb29e6262014-04-09 16:02:14 -0700455 }
456 for (DeviceEvent deviceEvent : apiAddedDeviceEvents) {
Jonathan Harte37e4e22014-05-13 19:12:02 -0700457 log.debug("Dispatch Topology Event: ADDED {}", deviceEvent);
Ray Milkeyb29e6262014-04-09 16:02:14 -0700458 }
459 for (DeviceEvent deviceEvent : apiRemovedDeviceEvents) {
Jonathan Harte37e4e22014-05-13 19:12:02 -0700460 log.debug("Dispatch Topology Event: REMOVED {}", deviceEvent);
Ray Milkeyb29e6262014-04-09 16:02:14 -0700461 }
Ray Milkey269ffb92014-04-03 14:43:30 -0700462 }
adminbc181552014-02-21 18:36:42 -0800463
Ray Milkey269ffb92014-04-03 14:43:30 -0700464 // Deliver the events
Pavlin Radoslavov4eaab992014-07-03 18:39:42 -0700465 long timestamp = System.nanoTime();
Jonathan Harte37e4e22014-05-13 19:12:02 -0700466 for (ITopologyListener listener : this.topologyListeners) {
Pavlin Radoslavov4eaab992014-07-03 18:39:42 -0700467 TopologyEvents events =
468 new TopologyEvents(timestamp,
469 kryo.copy(apiAddedSwitchEvents),
470 kryo.copy(apiRemovedSwitchEvents),
471 kryo.copy(apiAddedPortEvents),
472 kryo.copy(apiRemovedPortEvents),
473 kryo.copy(apiAddedLinkEvents),
474 kryo.copy(apiRemovedLinkEvents),
475 kryo.copy(apiAddedDeviceEvents),
476 kryo.copy(apiRemovedDeviceEvents));
477 listener.topologyEvents(events);
Ray Milkey269ffb92014-04-03 14:43:30 -0700478 }
Pavlin Radoslavov74986ce2014-02-20 13:17:20 -0800479
Ray Milkey269ffb92014-04-03 14:43:30 -0700480 //
481 // Cleanup
482 //
483 apiAddedSwitchEvents.clear();
484 apiRemovedSwitchEvents.clear();
485 apiAddedPortEvents.clear();
486 apiRemovedPortEvents.clear();
487 apiAddedLinkEvents.clear();
488 apiRemovedLinkEvents.clear();
489 apiAddedDeviceEvents.clear();
490 apiRemovedDeviceEvents.clear();
Pavlin Radoslavov74986ce2014-02-20 13:17:20 -0800491 }
492
493 /**
494 * Apply reordered events.
495 *
496 * @param hasAddedSwitchEvents true if there were Added Switch Events.
Ray Milkey269ffb92014-04-03 14:43:30 -0700497 * @param hasAddedPortEvents true if there were Added Port Events.
Pavlin Radoslavov74986ce2014-02-20 13:17:20 -0800498 */
Yuta HIGUCHIbc67a052014-06-30 10:37:09 -0700499 @GuardedBy("topology.writeLock")
Pavlin Radoslavov74986ce2014-02-20 13:17:20 -0800500 private void applyReorderedEvents(boolean hasAddedSwitchEvents,
Ray Milkey269ffb92014-04-03 14:43:30 -0700501 boolean hasAddedPortEvents) {
Ray Milkeyb29e6262014-04-09 16:02:14 -0700502 if (!(hasAddedSwitchEvents || hasAddedPortEvents)) {
Ray Milkey269ffb92014-04-03 14:43:30 -0700503 return; // Nothing to do
Ray Milkeyb29e6262014-04-09 16:02:14 -0700504 }
Pavlin Radoslavov74986ce2014-02-20 13:17:20 -0800505
Ray Milkey269ffb92014-04-03 14:43:30 -0700506 //
507 // Try to apply the reordered events.
508 //
509 // NOTE: For simplicity we try to apply all events of a particular
510 // type if any "parent" type event was processed:
511 // - Apply reordered Port Events if Switches were added
512 // - Apply reordered Link and Device Events if Switches or Ports
513 // were added
514 //
adminbc181552014-02-21 18:36:42 -0800515
Ray Milkey269ffb92014-04-03 14:43:30 -0700516 //
517 // Apply reordered Port Events if Switches were added
518 //
519 if (hasAddedSwitchEvents) {
520 Map<ByteBuffer, PortEvent> portEvents = reorderedAddedPortEvents;
521 reorderedAddedPortEvents = new HashMap<>();
Ray Milkeyb29e6262014-04-09 16:02:14 -0700522 for (PortEvent portEvent : portEvents.values()) {
Ray Milkey269ffb92014-04-03 14:43:30 -0700523 addPort(portEvent);
Ray Milkeyb29e6262014-04-09 16:02:14 -0700524 }
Ray Milkey269ffb92014-04-03 14:43:30 -0700525 }
526 //
527 // Apply reordered Link and Device Events if Switches or Ports
528 // were added.
529 //
530 Map<ByteBuffer, LinkEvent> linkEvents = reorderedAddedLinkEvents;
531 reorderedAddedLinkEvents = new HashMap<>();
Ray Milkeyb29e6262014-04-09 16:02:14 -0700532 for (LinkEvent linkEvent : linkEvents.values()) {
Ray Milkey269ffb92014-04-03 14:43:30 -0700533 addLink(linkEvent);
Ray Milkeyb29e6262014-04-09 16:02:14 -0700534 }
Ray Milkey269ffb92014-04-03 14:43:30 -0700535 //
536 Map<ByteBuffer, DeviceEvent> deviceEvents = reorderedAddedDeviceEvents;
537 reorderedAddedDeviceEvents = new HashMap<>();
Ray Milkeyb29e6262014-04-09 16:02:14 -0700538 for (DeviceEvent deviceEvent : deviceEvents.values()) {
Ray Milkey269ffb92014-04-03 14:43:30 -0700539 addDevice(deviceEvent);
Ray Milkeyb29e6262014-04-09 16:02:14 -0700540 }
Pavlin Radoslavov74986ce2014-02-20 13:17:20 -0800541 }
542
Pavlin Radoslavov734ff5a2014-02-26 10:20:43 -0800543 /**
544 * Switch discovered event.
545 *
546 * @param switchEvent the switch event.
Ray Milkey269ffb92014-04-03 14:43:30 -0700547 * @param portEvents the corresponding port events for the switch.
Pavlin Radoslavov734ff5a2014-02-26 10:20:43 -0800548 */
Pavlin Radoslavovc1cfde52014-02-19 11:35:29 -0800549 @Override
Pavlin Radoslavov018d5332014-02-19 23:08:35 -0800550 public void putSwitchDiscoveryEvent(SwitchEvent switchEvent,
Ray Milkey269ffb92014-04-03 14:43:30 -0700551 Collection<PortEvent> portEvents) {
552 if (datastore.addSwitch(switchEvent, portEvents)) {
Jonathan Hart92c819f2014-05-30 10:53:30 -0700553 log.debug("Sending add switch: {}", switchEvent);
Ray Milkey269ffb92014-04-03 14:43:30 -0700554 // Send out notification
555 TopologyEvent topologyEvent = new TopologyEvent(switchEvent);
556 eventChannel.addEntry(topologyEvent.getID(), topologyEvent);
Pavlin Radoslavov26d83402014-02-20 15:24:30 -0800557
Ray Milkey269ffb92014-04-03 14:43:30 -0700558 // Send out notification for each port
559 for (PortEvent portEvent : portEvents) {
Jonathan Hart92c819f2014-05-30 10:53:30 -0700560 log.debug("Sending add port: {}", portEvent);
Ray Milkey269ffb92014-04-03 14:43:30 -0700561 topologyEvent = new TopologyEvent(portEvent);
562 eventChannel.addEntry(topologyEvent.getID(), topologyEvent);
563 }
Pavlin Radoslavov26d83402014-02-20 15:24:30 -0800564
Ray Milkey269ffb92014-04-03 14:43:30 -0700565 //
566 // Keep track of the added ports
567 //
568 // Get the old Port Events
569 Map<ByteBuffer, PortEvent> oldPortEvents =
570 discoveredAddedPortEvents.get(switchEvent.getDpid());
Ray Milkeyb29e6262014-04-09 16:02:14 -0700571 if (oldPortEvents == null) {
Ray Milkey269ffb92014-04-03 14:43:30 -0700572 oldPortEvents = new HashMap<>();
Ray Milkeyb29e6262014-04-09 16:02:14 -0700573 }
Pavlin Radoslavov26d83402014-02-20 15:24:30 -0800574
Ray Milkey269ffb92014-04-03 14:43:30 -0700575 // Store the new Port Events in the local cache
576 Map<ByteBuffer, PortEvent> newPortEvents = new HashMap<>();
577 for (PortEvent portEvent : portEvents) {
578 ByteBuffer id = portEvent.getIDasByteBuffer();
579 newPortEvents.put(id, portEvent);
580 }
581 discoveredAddedPortEvents.put(switchEvent.getDpid(),
582 newPortEvents);
Pavlin Radoslavov26d83402014-02-20 15:24:30 -0800583
Ray Milkey269ffb92014-04-03 14:43:30 -0700584 //
585 // Extract the removed ports
586 //
587 List<PortEvent> removedPortEvents = new LinkedList<>();
588 for (Map.Entry<ByteBuffer, PortEvent> entry : oldPortEvents.entrySet()) {
589 ByteBuffer key = entry.getKey();
590 PortEvent portEvent = entry.getValue();
Ray Milkeyb29e6262014-04-09 16:02:14 -0700591 if (!newPortEvents.containsKey(key)) {
Ray Milkey269ffb92014-04-03 14:43:30 -0700592 removedPortEvents.add(portEvent);
Ray Milkeyb29e6262014-04-09 16:02:14 -0700593 }
Ray Milkey269ffb92014-04-03 14:43:30 -0700594 }
595
596 // Cleanup old removed ports
Ray Milkeyb29e6262014-04-09 16:02:14 -0700597 for (PortEvent portEvent : removedPortEvents) {
Ray Milkey269ffb92014-04-03 14:43:30 -0700598 removePortDiscoveryEvent(portEvent);
Ray Milkeyb29e6262014-04-09 16:02:14 -0700599 }
Ray Milkey269ffb92014-04-03 14:43:30 -0700600 }
Pavlin Radoslavovc1cfde52014-02-19 11:35:29 -0800601 }
602
Pavlin Radoslavov734ff5a2014-02-26 10:20:43 -0800603 /**
Yuta HIGUCHIbc67a052014-06-30 10:37:09 -0700604 * {@inheritDoc}
605 * <p/>
606 * Called by {@link TopologyPublisher.SwitchCleanup} thread.
Pavlin Radoslavov734ff5a2014-02-26 10:20:43 -0800607 */
Pavlin Radoslavovc1cfde52014-02-19 11:35:29 -0800608 @Override
Pavlin Radoslavov6ea84a42014-02-19 15:50:01 -0800609 public void removeSwitchDiscoveryEvent(SwitchEvent switchEvent) {
Ray Milkey269ffb92014-04-03 14:43:30 -0700610 // Get the old Port Events
611 Map<ByteBuffer, PortEvent> oldPortEvents =
612 discoveredAddedPortEvents.get(switchEvent.getDpid());
Ray Milkeyb29e6262014-04-09 16:02:14 -0700613 if (oldPortEvents == null) {
Ray Milkey269ffb92014-04-03 14:43:30 -0700614 oldPortEvents = new HashMap<>();
Ray Milkeyb29e6262014-04-09 16:02:14 -0700615 }
Pavlin Radoslavov018d5332014-02-19 23:08:35 -0800616
Ray Milkey269ffb92014-04-03 14:43:30 -0700617 if (datastore.deactivateSwitch(switchEvent, oldPortEvents.values())) {
Jonathan Hart92c819f2014-05-30 10:53:30 -0700618 log.debug("Sending remove switch: {}", switchEvent);
Ray Milkey269ffb92014-04-03 14:43:30 -0700619 // Send out notification
620 eventChannel.removeEntry(switchEvent.getID());
Pavlin Radoslavov018d5332014-02-19 23:08:35 -0800621
Ray Milkey269ffb92014-04-03 14:43:30 -0700622 //
623 // Send out notification for each port.
624 //
625 // NOTE: We don't use removePortDiscoveryEvent() for the cleanup,
626 // because it will attempt to remove the port from the database,
627 // and the deactiveSwitch() call above already removed all ports.
628 //
Ray Milkeyb29e6262014-04-09 16:02:14 -0700629 for (PortEvent portEvent : oldPortEvents.values()) {
Jonathan Hart92c819f2014-05-30 10:53:30 -0700630 log.debug("Sending remove port:", portEvent);
Ray Milkey269ffb92014-04-03 14:43:30 -0700631 eventChannel.removeEntry(portEvent.getID());
Ray Milkeyb29e6262014-04-09 16:02:14 -0700632 }
Ray Milkey269ffb92014-04-03 14:43:30 -0700633 discoveredAddedPortEvents.remove(switchEvent.getDpid());
Pavlin Radoslavov26d83402014-02-20 15:24:30 -0800634
Ray Milkey269ffb92014-04-03 14:43:30 -0700635 // Cleanup for each link
636 Map<ByteBuffer, LinkEvent> oldLinkEvents =
637 discoveredAddedLinkEvents.get(switchEvent.getDpid());
638 if (oldLinkEvents != null) {
639 for (LinkEvent linkEvent : new ArrayList<>(oldLinkEvents.values())) {
640 removeLinkDiscoveryEvent(linkEvent);
641 }
642 discoveredAddedLinkEvents.remove(switchEvent.getDpid());
643 }
Pavlin Radoslavov26d83402014-02-20 15:24:30 -0800644
Ray Milkey269ffb92014-04-03 14:43:30 -0700645 // Cleanup for each device
646 Map<ByteBuffer, DeviceEvent> oldDeviceEvents =
647 discoveredAddedDeviceEvents.get(switchEvent.getDpid());
648 if (oldDeviceEvents != null) {
649 for (DeviceEvent deviceEvent : new ArrayList<>(oldDeviceEvents.values())) {
650 removeDeviceDiscoveryEvent(deviceEvent);
651 }
652 discoveredAddedDeviceEvents.remove(switchEvent.getDpid());
653 }
654 }
Pavlin Radoslavovc1cfde52014-02-19 11:35:29 -0800655 }
656
Pavlin Radoslavov734ff5a2014-02-26 10:20:43 -0800657 /**
658 * Port discovered event.
659 *
660 * @param portEvent the port event.
661 */
Pavlin Radoslavovc1cfde52014-02-19 11:35:29 -0800662 @Override
Pavlin Radoslavov6ea84a42014-02-19 15:50:01 -0800663 public void putPortDiscoveryEvent(PortEvent portEvent) {
Ray Milkey269ffb92014-04-03 14:43:30 -0700664 if (datastore.addPort(portEvent)) {
Jonathan Hart92c819f2014-05-30 10:53:30 -0700665 log.debug("Sending add port: {}", portEvent);
Ray Milkey269ffb92014-04-03 14:43:30 -0700666 // Send out notification
667 TopologyEvent topologyEvent = new TopologyEvent(portEvent);
668 eventChannel.addEntry(topologyEvent.getID(), topologyEvent);
Pavlin Radoslavov26d83402014-02-20 15:24:30 -0800669
Ray Milkey269ffb92014-04-03 14:43:30 -0700670 // Store the new Port Event in the local cache
671 Map<ByteBuffer, PortEvent> oldPortEvents =
672 discoveredAddedPortEvents.get(portEvent.getDpid());
673 if (oldPortEvents == null) {
674 oldPortEvents = new HashMap<>();
675 discoveredAddedPortEvents.put(portEvent.getDpid(),
676 oldPortEvents);
677 }
678 ByteBuffer id = portEvent.getIDasByteBuffer();
679 oldPortEvents.put(id, portEvent);
680 }
Pavlin Radoslavovc1cfde52014-02-19 11:35:29 -0800681 }
682
Pavlin Radoslavov734ff5a2014-02-26 10:20:43 -0800683 /**
684 * Port removed event.
685 *
686 * @param portEvent the port event.
687 */
Pavlin Radoslavovc1cfde52014-02-19 11:35:29 -0800688 @Override
Pavlin Radoslavov6ea84a42014-02-19 15:50:01 -0800689 public void removePortDiscoveryEvent(PortEvent portEvent) {
Ray Milkey269ffb92014-04-03 14:43:30 -0700690 if (datastore.deactivatePort(portEvent)) {
Jonathan Hart92c819f2014-05-30 10:53:30 -0700691 log.debug("Sending remove port: {}", portEvent);
Ray Milkey269ffb92014-04-03 14:43:30 -0700692 // Send out notification
693 eventChannel.removeEntry(portEvent.getID());
Pavlin Radoslavov26d83402014-02-20 15:24:30 -0800694
Ray Milkey269ffb92014-04-03 14:43:30 -0700695 // Cleanup the Port Event from the local cache
696 Map<ByteBuffer, PortEvent> oldPortEvents =
697 discoveredAddedPortEvents.get(portEvent.getDpid());
698 if (oldPortEvents != null) {
699 ByteBuffer id = portEvent.getIDasByteBuffer();
700 oldPortEvents.remove(id);
701 }
Pavlin Radoslavov26d83402014-02-20 15:24:30 -0800702
Ray Milkey269ffb92014-04-03 14:43:30 -0700703 // Cleanup for the incoming link
704 Map<ByteBuffer, LinkEvent> oldLinkEvents =
705 discoveredAddedLinkEvents.get(portEvent.getDpid());
706 if (oldLinkEvents != null) {
707 for (LinkEvent linkEvent : new ArrayList<>(oldLinkEvents.values())) {
Yuta HIGUCHIbf0a8712014-06-30 18:59:46 -0700708 if (linkEvent.getDst().equals(portEvent.getSwitchPort())) {
Ray Milkey269ffb92014-04-03 14:43:30 -0700709 removeLinkDiscoveryEvent(linkEvent);
710 // XXX If we change our model to allow multiple Link on
711 // a Port, this loop must be fixed to allow continuing.
712 break;
713 }
714 }
715 }
Pavlin Radoslavov26d83402014-02-20 15:24:30 -0800716
Ray Milkey269ffb92014-04-03 14:43:30 -0700717 // Cleanup for the connected devices
718 // TODO: The implementation below is probably wrong
719 List<DeviceEvent> removedDeviceEvents = new LinkedList<>();
720 Map<ByteBuffer, DeviceEvent> oldDeviceEvents =
721 discoveredAddedDeviceEvents.get(portEvent.getDpid());
722 if (oldDeviceEvents != null) {
723 for (DeviceEvent deviceEvent : new ArrayList<>(oldDeviceEvents.values())) {
724 for (SwitchPort swp : deviceEvent.getAttachmentPoints()) {
Yuta HIGUCHIbf0a8712014-06-30 18:59:46 -0700725 if (swp.equals(portEvent.getSwitchPort())) {
Ray Milkey269ffb92014-04-03 14:43:30 -0700726 removedDeviceEvents.add(deviceEvent);
727 }
728 }
729 }
Ray Milkeyb29e6262014-04-09 16:02:14 -0700730 for (DeviceEvent deviceEvent : removedDeviceEvents) {
Ray Milkey269ffb92014-04-03 14:43:30 -0700731 removeDeviceDiscoveryEvent(deviceEvent);
Ray Milkeyb29e6262014-04-09 16:02:14 -0700732 }
Ray Milkey269ffb92014-04-03 14:43:30 -0700733 }
734 }
Pavlin Radoslavovc1cfde52014-02-19 11:35:29 -0800735 }
736
Pavlin Radoslavov734ff5a2014-02-26 10:20:43 -0800737 /**
738 * Link discovered event.
739 *
740 * @param linkEvent the link event.
741 */
Pavlin Radoslavovc1cfde52014-02-19 11:35:29 -0800742 @Override
Pavlin Radoslavov6ea84a42014-02-19 15:50:01 -0800743 public void putLinkDiscoveryEvent(LinkEvent linkEvent) {
Ray Milkey269ffb92014-04-03 14:43:30 -0700744 if (datastore.addLink(linkEvent)) {
Jonathan Hart92c819f2014-05-30 10:53:30 -0700745 log.debug("Sending add link: {}", linkEvent);
Ray Milkey269ffb92014-04-03 14:43:30 -0700746 // Send out notification
747 TopologyEvent topologyEvent = new TopologyEvent(linkEvent);
748 eventChannel.addEntry(topologyEvent.getID(), topologyEvent);
Pavlin Radoslavov26d83402014-02-20 15:24:30 -0800749
Ray Milkey269ffb92014-04-03 14:43:30 -0700750 // Store the new Link Event in the local cache
751 Map<ByteBuffer, LinkEvent> oldLinkEvents =
752 discoveredAddedLinkEvents.get(linkEvent.getDst().getDpid());
753 if (oldLinkEvents == null) {
754 oldLinkEvents = new HashMap<>();
755 discoveredAddedLinkEvents.put(linkEvent.getDst().getDpid(),
756 oldLinkEvents);
757 }
758 ByteBuffer id = linkEvent.getIDasByteBuffer();
759 oldLinkEvents.put(id, linkEvent);
760 }
Pavlin Radoslavovc1cfde52014-02-19 11:35:29 -0800761 }
762
Pavlin Radoslavov734ff5a2014-02-26 10:20:43 -0800763 /**
764 * Link removed event.
765 *
766 * @param linkEvent the link event.
767 */
Pavlin Radoslavovc1cfde52014-02-19 11:35:29 -0800768 @Override
Pavlin Radoslavov6ea84a42014-02-19 15:50:01 -0800769 public void removeLinkDiscoveryEvent(LinkEvent linkEvent) {
Ray Milkey269ffb92014-04-03 14:43:30 -0700770 if (datastore.removeLink(linkEvent)) {
Jonathan Hart92c819f2014-05-30 10:53:30 -0700771 log.debug("Sending remove link: {}", linkEvent);
Ray Milkey269ffb92014-04-03 14:43:30 -0700772 // Send out notification
773 eventChannel.removeEntry(linkEvent.getID());
Pavlin Radoslavov26d83402014-02-20 15:24:30 -0800774
Ray Milkey269ffb92014-04-03 14:43:30 -0700775 // Cleanup the Link Event from the local cache
776 Map<ByteBuffer, LinkEvent> oldLinkEvents =
777 discoveredAddedLinkEvents.get(linkEvent.getDst().getDpid());
778 if (oldLinkEvents != null) {
779 ByteBuffer id = linkEvent.getIDasByteBuffer();
780 oldLinkEvents.remove(id);
781 }
782 }
Pavlin Radoslavovc1cfde52014-02-19 11:35:29 -0800783 }
Jonathan Hart22eb9882014-02-11 15:52:59 -0800784
Pavlin Radoslavov734ff5a2014-02-26 10:20:43 -0800785 /**
786 * Device discovered event.
787 *
788 * @param deviceEvent the device event.
789 */
Pavlin Radoslavovc1cfde52014-02-19 11:35:29 -0800790 @Override
Pavlin Radoslavov6ea84a42014-02-19 15:50:01 -0800791 public void putDeviceDiscoveryEvent(DeviceEvent deviceEvent) {
Ray Milkey269ffb92014-04-03 14:43:30 -0700792 if (datastore.addDevice(deviceEvent)) {
793 // Send out notification
794 TopologyEvent topologyEvent = new TopologyEvent(deviceEvent);
795 eventChannel.addEntry(topologyEvent.getID(), topologyEvent);
Jonathan Harte37e4e22014-05-13 19:12:02 -0700796 log.debug("Put the device info into the cache of the topology. mac {}", deviceEvent.getMac());
Ray Milkey269ffb92014-04-03 14:43:30 -0700797
798 // Store the new Device Event in the local cache
799 // TODO: The implementation below is probably wrong
800 for (SwitchPort swp : deviceEvent.getAttachmentPoints()) {
801 Map<ByteBuffer, DeviceEvent> oldDeviceEvents =
802 discoveredAddedDeviceEvents.get(swp.getDpid());
803 if (oldDeviceEvents == null) {
804 oldDeviceEvents = new HashMap<>();
805 discoveredAddedDeviceEvents.put(swp.getDpid(),
806 oldDeviceEvents);
807 }
808 ByteBuffer id = deviceEvent.getIDasByteBuffer();
809 oldDeviceEvents.put(id, deviceEvent);
810 }
811 }
Pavlin Radoslavovc1cfde52014-02-19 11:35:29 -0800812 }
Jonathan Hart22eb9882014-02-11 15:52:59 -0800813
Pavlin Radoslavov734ff5a2014-02-26 10:20:43 -0800814 /**
815 * Device removed event.
816 *
817 * @param deviceEvent the device event.
818 */
Pavlin Radoslavovc1cfde52014-02-19 11:35:29 -0800819 @Override
Pavlin Radoslavov6ea84a42014-02-19 15:50:01 -0800820 public void removeDeviceDiscoveryEvent(DeviceEvent deviceEvent) {
Ray Milkey269ffb92014-04-03 14:43:30 -0700821 if (datastore.removeDevice(deviceEvent)) {
822 // Send out notification
823 eventChannel.removeEntry(deviceEvent.getID());
Jonathan Harte37e4e22014-05-13 19:12:02 -0700824 log.debug("Remove the device info into the cache of the topology. mac {}", deviceEvent.getMac());
Pavlin Radoslavov26d83402014-02-20 15:24:30 -0800825
Ray Milkey269ffb92014-04-03 14:43:30 -0700826 // Cleanup the Device Event from the local cache
827 // TODO: The implementation below is probably wrong
828 ByteBuffer id = ByteBuffer.wrap(deviceEvent.getID());
829 for (SwitchPort swp : deviceEvent.getAttachmentPoints()) {
830 Map<ByteBuffer, DeviceEvent> oldDeviceEvents =
831 discoveredAddedDeviceEvents.get(swp.getDpid());
832 if (oldDeviceEvents != null) {
833 oldDeviceEvents.remove(id);
834 }
835 }
836 }
Pavlin Radoslavovc1cfde52014-02-19 11:35:29 -0800837 }
Jonathan Hart22eb9882014-02-11 15:52:59 -0800838
Pavlin Radoslavov734ff5a2014-02-26 10:20:43 -0800839 /**
Yuta HIGUCHI7926ba32014-07-09 11:39:32 -0700840 * Adds a switch to the topology replica.
Pavlin Radoslavov734ff5a2014-02-26 10:20:43 -0800841 *
Yuta HIGUCHIbf0a8712014-06-30 18:59:46 -0700842 * @param switchEvent the SwitchEvent with the switch to add.
Pavlin Radoslavov734ff5a2014-02-26 10:20:43 -0800843 */
Yuta HIGUCHIbc67a052014-06-30 10:37:09 -0700844 @GuardedBy("topology.writeLock")
Pavlin Radoslavov74986ce2014-02-20 13:17:20 -0800845 private void addSwitch(SwitchEvent switchEvent) {
Jonathan Harte37e4e22014-05-13 19:12:02 -0700846 Switch sw = topology.getSwitch(switchEvent.getDpid());
Ray Milkey269ffb92014-04-03 14:43:30 -0700847 if (sw == null) {
Yuta HIGUCHIbf0a8712014-06-30 18:59:46 -0700848 sw = new SwitchImpl(topology, switchEvent);
Jonathan Harte37e4e22014-05-13 19:12:02 -0700849 topology.putSwitch(sw);
Ray Milkey269ffb92014-04-03 14:43:30 -0700850 } else {
851 // TODO: Update the switch attributes
Ray Milkey1aa71f82014-04-08 16:23:24 -0700852 log.debug("Update switch attributes");
Yuta HIGUCHIbf0a8712014-06-30 18:59:46 -0700853 SwitchImpl impl = (SwitchImpl) sw;
854 impl.replaceStringAttributes(switchEvent);
Ray Milkey269ffb92014-04-03 14:43:30 -0700855 }
856 apiAddedSwitchEvents.add(switchEvent);
Pavlin Radoslavov3c9cc552014-02-20 09:58:38 -0800857 }
858
Pavlin Radoslavov734ff5a2014-02-26 10:20:43 -0800859 /**
Yuta HIGUCHI7926ba32014-07-09 11:39:32 -0700860 * Removes a switch from the topology replica.
Yuta HIGUCHIbf0a8712014-06-30 18:59:46 -0700861 * <p/>
862 * It will call {@link #removePort(PortEvent)} for each ports on this switch.
Pavlin Radoslavov734ff5a2014-02-26 10:20:43 -0800863 *
Yuta HIGUCHIbf0a8712014-06-30 18:59:46 -0700864 * @param switchEvent the SwitchEvent with the switch to remove.
Pavlin Radoslavov734ff5a2014-02-26 10:20:43 -0800865 */
Yuta HIGUCHIbc67a052014-06-30 10:37:09 -0700866 @GuardedBy("topology.writeLock")
Pavlin Radoslavov74986ce2014-02-20 13:17:20 -0800867 private void removeSwitch(SwitchEvent switchEvent) {
Jonathan Harte37e4e22014-05-13 19:12:02 -0700868 Switch sw = topology.getSwitch(switchEvent.getDpid());
Ray Milkey269ffb92014-04-03 14:43:30 -0700869 if (sw == null) {
870 log.warn("Switch {} already removed, ignoring", switchEvent);
871 return;
872 }
Pavlin Radoslavov3c9cc552014-02-20 09:58:38 -0800873
Ray Milkey269ffb92014-04-03 14:43:30 -0700874 //
875 // Remove all Ports on the Switch
876 //
877 ArrayList<PortEvent> portsToRemove = new ArrayList<>();
878 for (Port port : sw.getPorts()) {
879 log.warn("Port {} on Switch {} should be removed prior to removing Switch. Removing Port now.",
880 port, switchEvent);
881 PortEvent portEvent = new PortEvent(port.getDpid(),
882 port.getNumber());
883 portsToRemove.add(portEvent);
884 }
Ray Milkeyb29e6262014-04-09 16:02:14 -0700885 for (PortEvent portEvent : portsToRemove) {
Ray Milkey269ffb92014-04-03 14:43:30 -0700886 removePort(portEvent);
Ray Milkeyb29e6262014-04-09 16:02:14 -0700887 }
Pavlin Radoslavov3c9cc552014-02-20 09:58:38 -0800888
Jonathan Harte37e4e22014-05-13 19:12:02 -0700889 topology.removeSwitch(switchEvent.getDpid());
Ray Milkey269ffb92014-04-03 14:43:30 -0700890 apiRemovedSwitchEvents.add(switchEvent);
Pavlin Radoslavov3c9cc552014-02-20 09:58:38 -0800891 }
892
Pavlin Radoslavov734ff5a2014-02-26 10:20:43 -0800893 /**
Yuta HIGUCHI7926ba32014-07-09 11:39:32 -0700894 * Adds a port to the topology replica.
Pavlin Radoslavov734ff5a2014-02-26 10:20:43 -0800895 *
Yuta HIGUCHIbf0a8712014-06-30 18:59:46 -0700896 * @param portEvent the PortEvent with the port to add.
Pavlin Radoslavov734ff5a2014-02-26 10:20:43 -0800897 */
Yuta HIGUCHIbc67a052014-06-30 10:37:09 -0700898 @GuardedBy("topology.writeLock")
Pavlin Radoslavov3c9cc552014-02-20 09:58:38 -0800899 private void addPort(PortEvent portEvent) {
Jonathan Harte37e4e22014-05-13 19:12:02 -0700900 Switch sw = topology.getSwitch(portEvent.getDpid());
Ray Milkey269ffb92014-04-03 14:43:30 -0700901 if (sw == null) {
Jonathan Hartf1675202014-05-23 14:59:07 -0700902 log.debug("{} reordered because switch is null", portEvent);
Ray Milkey269ffb92014-04-03 14:43:30 -0700903 // Reordered event: delay the event in local cache
904 ByteBuffer id = portEvent.getIDasByteBuffer();
905 reorderedAddedPortEvents.put(id, portEvent);
906 return;
907 }
Pavlin Radoslavov3c9cc552014-02-20 09:58:38 -0800908
Yuta HIGUCHIbf0a8712014-06-30 18:59:46 -0700909
Yuta HIGUCHIb1e2ab72014-06-30 11:01:31 -0700910 Port port = sw.getPort(portEvent.getPortNumber());
Ray Milkey269ffb92014-04-03 14:43:30 -0700911 if (port == null) {
Yuta HIGUCHIbf0a8712014-06-30 18:59:46 -0700912 port = new PortImpl(topology, portEvent);
Yuta HIGUCHIfa742842014-07-03 22:35:13 -0700913 topology.putPort(port);
Ray Milkey269ffb92014-04-03 14:43:30 -0700914 } else {
915 // TODO: Update the port attributes
Ray Milkey1aa71f82014-04-08 16:23:24 -0700916 log.debug("Update port attributes");
Yuta HIGUCHIbf0a8712014-06-30 18:59:46 -0700917 PortImpl impl = (PortImpl) port;
918 impl.replaceStringAttributes(portEvent);
Ray Milkey269ffb92014-04-03 14:43:30 -0700919 }
920 apiAddedPortEvents.add(portEvent);
Pavlin Radoslavov3c9cc552014-02-20 09:58:38 -0800921 }
922
Pavlin Radoslavov734ff5a2014-02-26 10:20:43 -0800923 /**
Yuta HIGUCHI7926ba32014-07-09 11:39:32 -0700924 * Removes a port from the topology replica.
Yuta HIGUCHIbf0a8712014-06-30 18:59:46 -0700925 * <p/>
926 * It will call {@link #removeDevice(DeviceEvent)} for each hosts on this port
927 * and call {@link #removeLink(LinkEvent)} for each links on this port.
Pavlin Radoslavov734ff5a2014-02-26 10:20:43 -0800928 *
Yuta HIGUCHIbf0a8712014-06-30 18:59:46 -0700929 * @param portEvent the PortEvent with the port to remove.
Pavlin Radoslavov734ff5a2014-02-26 10:20:43 -0800930 */
Yuta HIGUCHIbc67a052014-06-30 10:37:09 -0700931 @GuardedBy("topology.writeLock")
Pavlin Radoslavov3c9cc552014-02-20 09:58:38 -0800932 private void removePort(PortEvent portEvent) {
Jonathan Harte37e4e22014-05-13 19:12:02 -0700933 Switch sw = topology.getSwitch(portEvent.getDpid());
Ray Milkey269ffb92014-04-03 14:43:30 -0700934 if (sw == null) {
935 log.warn("Parent Switch for Port {} already removed, ignoring",
936 portEvent);
937 return;
938 }
Pavlin Radoslavov3c9cc552014-02-20 09:58:38 -0800939
Yuta HIGUCHIb1e2ab72014-06-30 11:01:31 -0700940 Port port = sw.getPort(portEvent.getPortNumber());
Ray Milkey269ffb92014-04-03 14:43:30 -0700941 if (port == null) {
942 log.warn("Port {} already removed, ignoring", portEvent);
943 return;
944 }
Pavlin Radoslavov3c9cc552014-02-20 09:58:38 -0800945
Ray Milkey269ffb92014-04-03 14:43:30 -0700946 //
947 // Remove all Devices attached to the Port
948 //
949 ArrayList<DeviceEvent> devicesToRemove = new ArrayList<>();
950 for (Device device : port.getDevices()) {
951 log.debug("Removing Device {} on Port {}", device, portEvent);
952 DeviceEvent deviceEvent = new DeviceEvent(device.getMacAddress());
953 SwitchPort switchPort = new SwitchPort(port.getSwitch().getDpid(),
954 port.getNumber());
955 deviceEvent.addAttachmentPoint(switchPort);
956 devicesToRemove.add(deviceEvent);
957 }
Ray Milkeyb29e6262014-04-09 16:02:14 -0700958 for (DeviceEvent deviceEvent : devicesToRemove) {
Ray Milkey269ffb92014-04-03 14:43:30 -0700959 removeDevice(deviceEvent);
Ray Milkeyb29e6262014-04-09 16:02:14 -0700960 }
Pavlin Radoslavov3c9cc552014-02-20 09:58:38 -0800961
Ray Milkey269ffb92014-04-03 14:43:30 -0700962 //
963 // Remove all Links connected to the Port
964 //
965 Set<Link> links = new HashSet<>();
966 links.add(port.getOutgoingLink());
967 links.add(port.getIncomingLink());
968 ArrayList<LinkEvent> linksToRemove = new ArrayList<>();
969 for (Link link : links) {
Ray Milkeyb29e6262014-04-09 16:02:14 -0700970 if (link == null) {
Ray Milkey269ffb92014-04-03 14:43:30 -0700971 continue;
Ray Milkeyb29e6262014-04-09 16:02:14 -0700972 }
Ray Milkey269ffb92014-04-03 14:43:30 -0700973 log.debug("Removing Link {} on Port {}", link, portEvent);
974 LinkEvent linkEvent = new LinkEvent(link.getSrcSwitch().getDpid(),
975 link.getSrcPort().getNumber(),
976 link.getDstSwitch().getDpid(),
977 link.getDstPort().getNumber());
978 linksToRemove.add(linkEvent);
979 }
Ray Milkeyb29e6262014-04-09 16:02:14 -0700980 for (LinkEvent linkEvent : linksToRemove) {
Ray Milkey269ffb92014-04-03 14:43:30 -0700981 removeLink(linkEvent);
Ray Milkeyb29e6262014-04-09 16:02:14 -0700982 }
Pavlin Radoslavov3c9cc552014-02-20 09:58:38 -0800983
Ray Milkey269ffb92014-04-03 14:43:30 -0700984 // Remove the Port from the Switch
Yuta HIGUCHIfa742842014-07-03 22:35:13 -0700985 topology.removePort(port);
Pavlin Radoslavov74986ce2014-02-20 13:17:20 -0800986
Ray Milkey269ffb92014-04-03 14:43:30 -0700987 apiRemovedPortEvents.add(portEvent);
Pavlin Radoslavov3c9cc552014-02-20 09:58:38 -0800988 }
989
Pavlin Radoslavov734ff5a2014-02-26 10:20:43 -0800990 /**
Yuta HIGUCHI7926ba32014-07-09 11:39:32 -0700991 * Adds a link to the topology replica.
Yuta HIGUCHIbf0a8712014-06-30 18:59:46 -0700992 * <p/>
993 * It will call {@link #removeDevice(DeviceEvent)} for each hosts on both ports.
Pavlin Radoslavov734ff5a2014-02-26 10:20:43 -0800994 *
Yuta HIGUCHIbf0a8712014-06-30 18:59:46 -0700995 * @param linkEvent the LinkEvent with the link to add.
Pavlin Radoslavov734ff5a2014-02-26 10:20:43 -0800996 */
Yuta HIGUCHIbc67a052014-06-30 10:37:09 -0700997 @GuardedBy("topology.writeLock")
Pavlin Radoslavov3c9cc552014-02-20 09:58:38 -0800998 private void addLink(LinkEvent linkEvent) {
Yuta HIGUCHI8f3dfa32014-06-25 00:14:25 -0700999 Port srcPort = topology.getPort(linkEvent.getSrc().getDpid(),
Yuta HIGUCHIb1e2ab72014-06-30 11:01:31 -07001000 linkEvent.getSrc().getPortNumber());
Yuta HIGUCHI8f3dfa32014-06-25 00:14:25 -07001001 Port dstPort = topology.getPort(linkEvent.getDst().getDpid(),
Yuta HIGUCHIb1e2ab72014-06-30 11:01:31 -07001002 linkEvent.getDst().getPortNumber());
Ray Milkey269ffb92014-04-03 14:43:30 -07001003 if ((srcPort == null) || (dstPort == null)) {
Jonathan Hartf1675202014-05-23 14:59:07 -07001004 log.debug("{} reordered because {} port is null", linkEvent,
1005 (srcPort == null) ? "src" : "dst");
1006
Yuta HIGUCHIbf0a8712014-06-30 18:59:46 -07001007 // XXX domain knowledge: port must be present before link.
Ray Milkey269ffb92014-04-03 14:43:30 -07001008 // Reordered event: delay the event in local cache
1009 ByteBuffer id = linkEvent.getIDasByteBuffer();
1010 reorderedAddedLinkEvents.put(id, linkEvent);
1011 return;
1012 }
Pavlin Radoslavov3c9cc552014-02-20 09:58:38 -08001013
Ray Milkey269ffb92014-04-03 14:43:30 -07001014 // Get the Link instance from the Destination Port Incoming Link
Yuta HIGUCHIbf0a8712014-06-30 18:59:46 -07001015 // XXX domain knowledge: Link is discovered by LLDP,
1016 // thus incoming link is likely to be more up-to-date
1017 // FIXME potentially local replica may not be up-to-date yet due to HZ delay.
1018 // may need to manage local truth and use them instead.
Ray Milkey269ffb92014-04-03 14:43:30 -07001019 Link link = dstPort.getIncomingLink();
1020 assert (link == srcPort.getOutgoingLink());
1021 if (link == null) {
Yuta HIGUCHIbf0a8712014-06-30 18:59:46 -07001022 link = new LinkImpl(topology, linkEvent);
Jonathan Harte37e4e22014-05-13 19:12:02 -07001023 topology.putLink(link);
Pavlin Radoslavov3c9cc552014-02-20 09:58:38 -08001024
Ray Milkey269ffb92014-04-03 14:43:30 -07001025 // Remove all Devices attached to the Ports
1026 ArrayList<DeviceEvent> devicesToRemove = new ArrayList<>();
1027 ArrayList<Port> ports = new ArrayList<>();
1028 ports.add(srcPort);
1029 ports.add(dstPort);
1030 for (Port port : ports) {
1031 for (Device device : port.getDevices()) {
1032 log.error("Device {} on Port {} should have been removed prior to adding Link {}",
1033 device, port, linkEvent);
Yuta HIGUCHIbf0a8712014-06-30 18:59:46 -07001034 // FIXME must get Device info from topology, when we add attrs.
Ray Milkey269ffb92014-04-03 14:43:30 -07001035 DeviceEvent deviceEvent =
1036 new DeviceEvent(device.getMacAddress());
1037 SwitchPort switchPort =
1038 new SwitchPort(port.getSwitch().getDpid(),
1039 port.getNumber());
Yuta HIGUCHIbf0a8712014-06-30 18:59:46 -07001040 // adding attachment port which needs to be removed
Ray Milkey269ffb92014-04-03 14:43:30 -07001041 deviceEvent.addAttachmentPoint(switchPort);
1042 devicesToRemove.add(deviceEvent);
1043 }
1044 }
Ray Milkeyb29e6262014-04-09 16:02:14 -07001045 for (DeviceEvent deviceEvent : devicesToRemove) {
Ray Milkey269ffb92014-04-03 14:43:30 -07001046 removeDevice(deviceEvent);
Ray Milkeyb29e6262014-04-09 16:02:14 -07001047 }
Ray Milkey269ffb92014-04-03 14:43:30 -07001048 } else {
1049 // TODO: Update the link attributes
Ray Milkey1aa71f82014-04-08 16:23:24 -07001050 log.debug("Update link attributes");
Yuta HIGUCHIbf0a8712014-06-30 18:59:46 -07001051 LinkImpl impl = (LinkImpl) link;
1052 impl.replaceStringAttributes(linkEvent);
Ray Milkey269ffb92014-04-03 14:43:30 -07001053 }
Pavlin Radoslavov74986ce2014-02-20 13:17:20 -08001054
Ray Milkey269ffb92014-04-03 14:43:30 -07001055 apiAddedLinkEvents.add(linkEvent);
Pavlin Radoslavov3c9cc552014-02-20 09:58:38 -08001056 }
1057
Pavlin Radoslavov734ff5a2014-02-26 10:20:43 -08001058 /**
Yuta HIGUCHI7926ba32014-07-09 11:39:32 -07001059 * Removes a link from the topology replica.
Pavlin Radoslavov734ff5a2014-02-26 10:20:43 -08001060 *
Yuta HIGUCHIbf0a8712014-06-30 18:59:46 -07001061 * @param linkEvent the LinkEvent with the link to remove.
Pavlin Radoslavov734ff5a2014-02-26 10:20:43 -08001062 */
Yuta HIGUCHIbc67a052014-06-30 10:37:09 -07001063 @GuardedBy("topology.writeLock")
Pavlin Radoslavov3c9cc552014-02-20 09:58:38 -08001064 private void removeLink(LinkEvent linkEvent) {
Yuta HIGUCHI8f3dfa32014-06-25 00:14:25 -07001065 Port srcPort = topology.getPort(linkEvent.getSrc().getDpid(),
Yuta HIGUCHIb1e2ab72014-06-30 11:01:31 -07001066 linkEvent.getSrc().getPortNumber());
Ray Milkey269ffb92014-04-03 14:43:30 -07001067 if (srcPort == null) {
1068 log.warn("Src Port for Link {} already removed, ignoring",
1069 linkEvent);
1070 return;
1071 }
Pavlin Radoslavov3c9cc552014-02-20 09:58:38 -08001072
Yuta HIGUCHI8f3dfa32014-06-25 00:14:25 -07001073 Port dstPort = topology.getPort(linkEvent.getDst().getDpid(),
Yuta HIGUCHIb1e2ab72014-06-30 11:01:31 -07001074 linkEvent.getDst().getPortNumber());
Ray Milkey269ffb92014-04-03 14:43:30 -07001075 if (dstPort == null) {
1076 log.warn("Dst Port for Link {} already removed, ignoring",
1077 linkEvent);
1078 return;
1079 }
Pavlin Radoslavov3c9cc552014-02-20 09:58:38 -08001080
Ray Milkey269ffb92014-04-03 14:43:30 -07001081 //
1082 // Remove the Link instance from the Destination Port Incoming Link
1083 // and the Source Port Outgoing Link.
1084 //
1085 Link link = dstPort.getIncomingLink();
1086 if (link == null) {
1087 log.warn("Link {} already removed on destination Port", linkEvent);
1088 }
1089 link = srcPort.getOutgoingLink();
1090 if (link == null) {
1091 log.warn("Link {} already removed on src Port", linkEvent);
1092 }
Jonathan Hart25bd53e2014-04-30 23:44:09 -07001093
1094 // TODO should we check that we get the same link from each port?
1095 if (link != null) {
Jonathan Harte37e4e22014-05-13 19:12:02 -07001096 topology.removeLink(link);
Jonathan Hart25bd53e2014-04-30 23:44:09 -07001097 }
Pavlin Radoslavov74986ce2014-02-20 13:17:20 -08001098
Ray Milkey269ffb92014-04-03 14:43:30 -07001099 apiRemovedLinkEvents.add(linkEvent);
Pavlin Radoslavov3c9cc552014-02-20 09:58:38 -08001100 }
1101
Pavlin Radoslavov734ff5a2014-02-26 10:20:43 -08001102 /**
Yuta HIGUCHI7926ba32014-07-09 11:39:32 -07001103 * Adds a device to the topology replica.
Ray Milkey269ffb92014-04-03 14:43:30 -07001104 * <p/>
Pavlin Radoslavov734ff5a2014-02-26 10:20:43 -08001105 * TODO: Device-related work is incomplete.
1106 * TODO: Eventually, we might need to consider reordering
1107 * or addLink() and addDevice() events on the same port.
1108 *
Yuta HIGUCHIbf0a8712014-06-30 18:59:46 -07001109 * @param deviceEvent the DeviceEvent with the device to add.
Pavlin Radoslavov734ff5a2014-02-26 10:20:43 -08001110 */
Yuta HIGUCHIbc67a052014-06-30 10:37:09 -07001111 @GuardedBy("topology.writeLock")
Pavlin Radoslavov3c9cc552014-02-20 09:58:38 -08001112 private void addDevice(DeviceEvent deviceEvent) {
Jonathan Harte37e4e22014-05-13 19:12:02 -07001113 log.debug("Adding a device to the topology with mac {}", deviceEvent.getMac());
1114 Device device = topology.getDeviceByMac(deviceEvent.getMac());
Pavlin Radoslavov3c9cc552014-02-20 09:58:38 -08001115
Ray Milkey269ffb92014-04-03 14:43:30 -07001116 if (device == null) {
Jonathan Harte37e4e22014-05-13 19:12:02 -07001117 log.debug("Existing device was not found in the Topology: Adding new device: mac {}", deviceEvent.getMac());
1118 device = new DeviceImpl(topology, deviceEvent.getMac());
Ray Milkey269ffb92014-04-03 14:43:30 -07001119 }
Pavlin Radoslavov3c9cc552014-02-20 09:58:38 -08001120
Yuta HIGUCHIbf0a8712014-06-30 18:59:46 -07001121 DeviceImpl deviceImpl = (DeviceImpl) device;
Pavlin Radoslavov3c9cc552014-02-20 09:58:38 -08001122
Ray Milkey269ffb92014-04-03 14:43:30 -07001123 // Process each attachment point
1124 boolean attachmentFound = false;
1125 for (SwitchPort swp : deviceEvent.getAttachmentPoints()) {
Yuta HIGUCHIbf0a8712014-06-30 18:59:46 -07001126 // XXX domain knowledge: Port must exist before Device
1127 // but this knowledge cannot be pushed down to driver.
1128
Ray Milkey269ffb92014-04-03 14:43:30 -07001129 // Attached Ports must exist
Yuta HIGUCHIb1e2ab72014-06-30 11:01:31 -07001130 Port port = topology.getPort(swp.getDpid(), swp.getPortNumber());
Ray Milkey269ffb92014-04-03 14:43:30 -07001131 if (port == null) {
1132 // Reordered event: delay the event in local cache
1133 ByteBuffer id = deviceEvent.getIDasByteBuffer();
1134 reorderedAddedDeviceEvents.put(id, deviceEvent);
1135 continue;
1136 }
1137 // Attached Ports must not have Link
1138 if (port.getOutgoingLink() != null ||
1139 port.getIncomingLink() != null) {
1140 log.warn("Link (Out:{},In:{}) exist on the attachment point, skipping mutation.",
1141 port.getOutgoingLink(),
1142 port.getIncomingLink());
1143 continue;
1144 }
1145
1146 // Add Device <-> Port attachment
Ray Milkey269ffb92014-04-03 14:43:30 -07001147 deviceImpl.addAttachmentPoint(port);
1148 attachmentFound = true;
1149 }
1150
Jonathan Harte37e4e22014-05-13 19:12:02 -07001151 // Update the device in the topology
Ray Milkey269ffb92014-04-03 14:43:30 -07001152 if (attachmentFound) {
Jonathan Harte37e4e22014-05-13 19:12:02 -07001153 log.debug("Storing the device info into the Topology: mac {}", deviceEvent.getMac());
1154 topology.putDevice(device);
Ray Milkey269ffb92014-04-03 14:43:30 -07001155 apiAddedDeviceEvents.add(deviceEvent);
1156 }
Pavlin Radoslavov3c9cc552014-02-20 09:58:38 -08001157 }
1158
Pavlin Radoslavov734ff5a2014-02-26 10:20:43 -08001159 /**
Yuta HIGUCHI7926ba32014-07-09 11:39:32 -07001160 * Removes a device from the topology replica.
Ray Milkey269ffb92014-04-03 14:43:30 -07001161 * <p/>
Pavlin Radoslavov734ff5a2014-02-26 10:20:43 -08001162 * TODO: Device-related work is incomplete.
1163 *
1164 * @param deviceEvent the Device Event with the device to remove.
1165 */
Yuta HIGUCHIbc67a052014-06-30 10:37:09 -07001166 @GuardedBy("topology.writeLock")
Pavlin Radoslavov3c9cc552014-02-20 09:58:38 -08001167 private void removeDevice(DeviceEvent deviceEvent) {
Yuta HIGUCHIfa742842014-07-03 22:35:13 -07001168 log.debug("Removing a device from the topology: mac {}", deviceEvent.getMac());
Jonathan Harte37e4e22014-05-13 19:12:02 -07001169 Device device = topology.getDeviceByMac(deviceEvent.getMac());
Ray Milkey269ffb92014-04-03 14:43:30 -07001170 if (device == null) {
1171 log.warn("Device {} already removed, ignoring", deviceEvent);
1172 return;
1173 }
Pavlin Radoslavov3c9cc552014-02-20 09:58:38 -08001174
Jonathan Harte37e4e22014-05-13 19:12:02 -07001175 topology.removeDevice(device);
Ray Milkey269ffb92014-04-03 14:43:30 -07001176 apiRemovedDeviceEvents.add(deviceEvent);
Pavlin Radoslavov3c9cc552014-02-20 09:58:38 -08001177 }
Jonathan Hart22eb9882014-02-11 15:52:59 -08001178
Pavlin Radoslavovc1cfde52014-02-19 11:35:29 -08001179 /**
Pavlin Radoslavov734ff5a2014-02-26 10:20:43 -08001180 * Read the whole topology from the database.
1181 *
1182 * @return a collection of EventEntry-encapsulated Topology Events for
1183 * the whole topology.
1184 */
Pavlin Radoslavov018d5332014-02-19 23:08:35 -08001185 private Collection<EventEntry<TopologyEvent>> readWholeTopologyFromDB() {
Ray Milkey269ffb92014-04-03 14:43:30 -07001186 Collection<EventEntry<TopologyEvent>> collection =
1187 new LinkedList<EventEntry<TopologyEvent>>();
Pavlin Radoslavov018d5332014-02-19 23:08:35 -08001188
Ray Milkey269ffb92014-04-03 14:43:30 -07001189 // XXX May need to clear whole topology first, depending on
1190 // how we initially subscribe to replication events
Pavlin Radoslavovc1cfde52014-02-19 11:35:29 -08001191
Ray Milkey269ffb92014-04-03 14:43:30 -07001192 // Add all active switches
1193 for (KVSwitch sw : KVSwitch.getAllSwitches()) {
1194 if (sw.getStatus() != KVSwitch.STATUS.ACTIVE) {
1195 continue;
1196 }
Pavlin Radoslavov018d5332014-02-19 23:08:35 -08001197
Yuta HIGUCHIe2a4e172014-07-03 10:50:39 -07001198 SwitchEvent switchEvent = new SwitchEvent(new Dpid(sw.getDpid()));
Ray Milkey269ffb92014-04-03 14:43:30 -07001199 TopologyEvent topologyEvent = new TopologyEvent(switchEvent);
1200 EventEntry<TopologyEvent> eventEntry =
1201 new EventEntry<TopologyEvent>(EventEntry.Type.ENTRY_ADD,
1202 topologyEvent);
1203 collection.add(eventEntry);
1204 }
Yuta HIGUCHIa536e762014-02-17 21:47:28 -08001205
Ray Milkey269ffb92014-04-03 14:43:30 -07001206 // Add all active ports
1207 for (KVPort p : KVPort.getAllPorts()) {
1208 if (p.getStatus() != KVPort.STATUS.ACTIVE) {
1209 continue;
1210 }
Pavlin Radoslavov018d5332014-02-19 23:08:35 -08001211
Yuta HIGUCHIe2a4e172014-07-03 10:50:39 -07001212 PortEvent portEvent = new PortEvent(
1213 new Dpid(p.getDpid()),
1214 new PortNumber(p.getNumber().shortValue()));
Ray Milkey269ffb92014-04-03 14:43:30 -07001215 TopologyEvent topologyEvent = new TopologyEvent(portEvent);
1216 EventEntry<TopologyEvent> eventEntry =
1217 new EventEntry<TopologyEvent>(EventEntry.Type.ENTRY_ADD,
1218 topologyEvent);
1219 collection.add(eventEntry);
1220 }
Yuta HIGUCHIa536e762014-02-17 21:47:28 -08001221
TeruU28adcc32014-04-15 17:57:35 -07001222 for (KVDevice d : KVDevice.getAllDevices()) {
1223 DeviceEvent devEvent = new DeviceEvent(MACAddress.valueOf(d.getMac()));
1224 for (byte[] portId : d.getAllPortIds()) {
Jonathan Hartc00f5c22014-06-10 15:14:40 -07001225 devEvent.addAttachmentPoint(
1226 new SwitchPort(KVPort.getDpidFromKey(portId),
1227 KVPort.getNumberFromKey(portId)));
TeruU28adcc32014-04-15 17:57:35 -07001228 }
1229 }
Pavlin Radoslavovc1cfde52014-02-19 11:35:29 -08001230
Ray Milkey269ffb92014-04-03 14:43:30 -07001231 for (KVLink l : KVLink.getAllLinks()) {
Yuta HIGUCHIe2a4e172014-07-03 10:50:39 -07001232 LinkEvent linkEvent = new LinkEvent(
1233 new SwitchPort(l.getSrc().dpid, l.getSrc().number),
1234 new SwitchPort(l.getDst().dpid, l.getDst().number));
Ray Milkey269ffb92014-04-03 14:43:30 -07001235 TopologyEvent topologyEvent = new TopologyEvent(linkEvent);
1236 EventEntry<TopologyEvent> eventEntry =
1237 new EventEntry<TopologyEvent>(EventEntry.Type.ENTRY_ADD,
1238 topologyEvent);
1239 collection.add(eventEntry);
1240 }
Pavlin Radoslavov018d5332014-02-19 23:08:35 -08001241
Ray Milkey269ffb92014-04-03 14:43:30 -07001242 return collection;
Pavlin Radoslavovc1cfde52014-02-19 11:35:29 -08001243 }
Jonathan Hart062a2e82014-02-03 09:41:57 -08001244}