blob: bdc6d67bcb25bdbdfcc73723b17b9898d74da78d [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
weibitf7c31a42014-06-23 16:51:01 -070062 private TopologyDatastore datastore;
Jonathan Harte37e4e22014-05-13 19:12:02 -070063 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>();
Yuta HIGUCHIbfc77f02014-07-14 22:50:25 -070076 private Map<ByteBuffer, HostEvent> reorderedAddedHostEvents =
77 new HashMap<ByteBuffer, HostEvent>();
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 HIGUCHIbfc77f02014-07-14 22:50:25 -070083 // We keep all Port, (incoming) Link and Host events per Switch DPID:
Pavlin Radoslavov26d83402014-02-20 15:24:30 -080084 // - If a switch goes down, we remove all corresponding Port, Link and
Yuta HIGUCHIbfc77f02014-07-14 22:50:25 -070085 // Host events.
Pavlin Radoslavov26d83402014-02-20 15:24:30 -080086 // - If a port on a switch goes down, we remove all corresponding Link
Yuta HIGUCHIbfc77f02014-07-14 22:50:25 -070087 // and Host events discovered by this instance.
Yuta HIGUCHIbc67a052014-06-30 10:37:09 -070088 //
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)
Yuta HIGUCHIbfc77f02014-07-14 22:50:25 -070092 // - Remote Host Added -> lose ownership of Host)
Yuta HIGUCHIbc67a052014-06-30 10:37:09 -070093 // 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
Yuta HIGUCHIbfc77f02014-07-14 22:50:25 -0700100 // XXX Switch/Port can be rediscovered by new leader, but Link, Host?
Yuta HIGUCHIbc67a052014-06-30 10:37:09 -0700101 // - 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 HIGUCHIbfc77f02014-07-14 22:50:25 -0700113 private Map<Dpid, Map<ByteBuffer, HostEvent>> discoveredAddedHostEvents =
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<>();
Yuta HIGUCHIbfc77f02014-07-14 22:50:25 -0700128 private List<HostEvent> apiAddedHostEvents = new LinkedList<>();
129 private List<HostEvent> apiRemovedHostEvents = 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<>();
Yuta HIGUCHIbfc77f02014-07-14 22:50:25 -0700230 Map<ByteBuffer, HostEvent> addedHostEvents = new HashMap<>();
231 Map<ByteBuffer, HostEvent> removedHostEvents = 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;
Yuta HIGUCHIbfc77f02014-07-14 22:50:25 -0700241 HostEvent hostEvent = topologyEvent.hostEvent;
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 }
Yuta HIGUCHIbfc77f02014-07-14 22:50:25 -0700267 if (hostEvent != null) {
268 ByteBuffer id = hostEvent.getIDasByteBuffer();
269 addedHostEvents.put(id, hostEvent);
270 removedHostEvents.remove(id);
271 reorderedAddedHostEvents.remove(id);
Ray Milkey269ffb92014-04-03 14:43:30 -0700272 }
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 }
Yuta HIGUCHIbfc77f02014-07-14 22:50:25 -0700294 if (hostEvent != null) {
295 ByteBuffer id = hostEvent.getIDasByteBuffer();
296 addedHostEvents.remove(id);
297 removedHostEvents.put(id, hostEvent);
298 reorderedAddedHostEvents.remove(id);
Ray Milkey269ffb92014-04-03 14:43:30 -0700299 }
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:
Yuta HIGUCHIbfc77f02014-07-14 22:50:25 -0700317 // switch, port, link, host
Ray Milkey269ffb92014-04-03 14:43:30 -0700318 //
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 }
Yuta HIGUCHIbfc77f02014-07-14 22:50:25 -0700328 for (HostEvent hostEvent : addedHostEvents.values()) {
329 addHost(hostEvent);
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:
Yuta HIGUCHIbfc77f02014-07-14 22:50:25 -0700333 // host, link, port, switch
Ray Milkey269ffb92014-04-03 14:43:30 -0700334 //
Yuta HIGUCHIbfc77f02014-07-14 22:50:25 -0700335 for (HostEvent hostEvent : removedHostEvents.values()) {
336 removeHost(hostEvent);
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() &&
Yuta HIGUCHIbfc77f02014-07-14 22:50:25 -0700428 apiAddedHostEvents.isEmpty() &&
429 apiRemovedHostEvents.isEmpty()) {
Ray Milkey269ffb92014-04-03 14:43:30 -0700430 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 }
Yuta HIGUCHIbfc77f02014-07-14 22:50:25 -0700456 for (HostEvent hostEvent : apiAddedHostEvents) {
457 log.debug("Dispatch Topology Event: ADDED {}", hostEvent);
Ray Milkeyb29e6262014-04-09 16:02:14 -0700458 }
Yuta HIGUCHIbfc77f02014-07-14 22:50:25 -0700459 for (HostEvent hostEvent : apiRemovedHostEvents) {
460 log.debug("Dispatch Topology Event: REMOVED {}", hostEvent);
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),
Yuta HIGUCHIbfc77f02014-07-14 22:50:25 -0700475 kryo.copy(apiAddedHostEvents),
476 kryo.copy(apiRemovedHostEvents));
Pavlin Radoslavov4eaab992014-07-03 18:39:42 -0700477 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();
Yuta HIGUCHIbfc77f02014-07-14 22:50:25 -0700489 apiAddedHostEvents.clear();
490 apiRemovedHostEvents.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
Yuta HIGUCHIbfc77f02014-07-14 22:50:25 -0700512 // - Apply reordered Link and Host Events if Switches or Ports
Ray Milkey269ffb92014-04-03 14:43:30 -0700513 // 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 //
Yuta HIGUCHIbfc77f02014-07-14 22:50:25 -0700527 // Apply reordered Link and Host Events if Switches or Ports
Ray Milkey269ffb92014-04-03 14:43:30 -0700528 // 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 //
Yuta HIGUCHIbfc77f02014-07-14 22:50:25 -0700536 Map<ByteBuffer, HostEvent> hostEvents = reorderedAddedHostEvents;
537 reorderedAddedHostEvents = new HashMap<>();
538 for (HostEvent hostEvent : hostEvents.values()) {
539 addHost(hostEvent);
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
Yuta HIGUCHIbfc77f02014-07-14 22:50:25 -0700645 // Cleanup for each host
646 Map<ByteBuffer, HostEvent> oldHostEvents =
647 discoveredAddedHostEvents.get(switchEvent.getDpid());
648 if (oldHostEvents != null) {
649 for (HostEvent hostEvent : new ArrayList<>(oldHostEvents.values())) {
650 removeHostDiscoveryEvent(hostEvent);
Ray Milkey269ffb92014-04-03 14:43:30 -0700651 }
Yuta HIGUCHIbfc77f02014-07-14 22:50:25 -0700652 discoveredAddedHostEvents.remove(switchEvent.getDpid());
Ray Milkey269ffb92014-04-03 14:43:30 -0700653 }
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
Yuta HIGUCHIbfc77f02014-07-14 22:50:25 -0700717 // Cleanup for the connected hosts
Ray Milkey269ffb92014-04-03 14:43:30 -0700718 // TODO: The implementation below is probably wrong
Yuta HIGUCHIbfc77f02014-07-14 22:50:25 -0700719 List<HostEvent> removedHostEvents = new LinkedList<>();
720 Map<ByteBuffer, HostEvent> oldHostEvents =
721 discoveredAddedHostEvents.get(portEvent.getDpid());
722 if (oldHostEvents != null) {
723 for (HostEvent hostEvent : new ArrayList<>(oldHostEvents.values())) {
724 for (SwitchPort swp : hostEvent.getAttachmentPoints()) {
Yuta HIGUCHIbf0a8712014-06-30 18:59:46 -0700725 if (swp.equals(portEvent.getSwitchPort())) {
Yuta HIGUCHIbfc77f02014-07-14 22:50:25 -0700726 removedHostEvents.add(hostEvent);
Ray Milkey269ffb92014-04-03 14:43:30 -0700727 }
728 }
729 }
Yuta HIGUCHIbfc77f02014-07-14 22:50:25 -0700730 for (HostEvent hostEvent : removedHostEvents) {
731 removeHostDiscoveryEvent(hostEvent);
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 /**
Yuta HIGUCHIbfc77f02014-07-14 22:50:25 -0700786 * Host discovered event.
Pavlin Radoslavov734ff5a2014-02-26 10:20:43 -0800787 *
Yuta HIGUCHIbfc77f02014-07-14 22:50:25 -0700788 * @param hostEvent the host event.
Pavlin Radoslavov734ff5a2014-02-26 10:20:43 -0800789 */
Pavlin Radoslavovc1cfde52014-02-19 11:35:29 -0800790 @Override
Yuta HIGUCHIbfc77f02014-07-14 22:50:25 -0700791 public void putHostDiscoveryEvent(HostEvent hostEvent) {
792 if (datastore.addHost(hostEvent)) {
Ray Milkey269ffb92014-04-03 14:43:30 -0700793 // Send out notification
Yuta HIGUCHIbfc77f02014-07-14 22:50:25 -0700794 TopologyEvent topologyEvent = new TopologyEvent(hostEvent);
Ray Milkey269ffb92014-04-03 14:43:30 -0700795 eventChannel.addEntry(topologyEvent.getID(), topologyEvent);
Yuta HIGUCHIbfc77f02014-07-14 22:50:25 -0700796 log.debug("Put the host info into the cache of the topology. mac {}", hostEvent.getMac());
Ray Milkey269ffb92014-04-03 14:43:30 -0700797
Yuta HIGUCHIbfc77f02014-07-14 22:50:25 -0700798 // Store the new Host Event in the local cache
Ray Milkey269ffb92014-04-03 14:43:30 -0700799 // TODO: The implementation below is probably wrong
Yuta HIGUCHIbfc77f02014-07-14 22:50:25 -0700800 for (SwitchPort swp : hostEvent.getAttachmentPoints()) {
801 Map<ByteBuffer, HostEvent> oldHostEvents =
802 discoveredAddedHostEvents.get(swp.getDpid());
803 if (oldHostEvents == null) {
804 oldHostEvents = new HashMap<>();
805 discoveredAddedHostEvents.put(swp.getDpid(),
806 oldHostEvents);
Ray Milkey269ffb92014-04-03 14:43:30 -0700807 }
Yuta HIGUCHIbfc77f02014-07-14 22:50:25 -0700808 ByteBuffer id = hostEvent.getIDasByteBuffer();
809 oldHostEvents.put(id, hostEvent);
Ray Milkey269ffb92014-04-03 14:43:30 -0700810 }
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 /**
Yuta HIGUCHIbfc77f02014-07-14 22:50:25 -0700815 * Host removed event.
Pavlin Radoslavov734ff5a2014-02-26 10:20:43 -0800816 *
Yuta HIGUCHIbfc77f02014-07-14 22:50:25 -0700817 * @param hostEvent the host event.
Pavlin Radoslavov734ff5a2014-02-26 10:20:43 -0800818 */
Pavlin Radoslavovc1cfde52014-02-19 11:35:29 -0800819 @Override
Yuta HIGUCHIbfc77f02014-07-14 22:50:25 -0700820 public void removeHostDiscoveryEvent(HostEvent hostEvent) {
821 if (datastore.removeHost(hostEvent)) {
Ray Milkey269ffb92014-04-03 14:43:30 -0700822 // Send out notification
Yuta HIGUCHIbfc77f02014-07-14 22:50:25 -0700823 eventChannel.removeEntry(hostEvent.getID());
824 log.debug("Remove the host info into the cache of the topology. mac {}", hostEvent.getMac());
Pavlin Radoslavov26d83402014-02-20 15:24:30 -0800825
Yuta HIGUCHIbfc77f02014-07-14 22:50:25 -0700826 // Cleanup the Host Event from the local cache
Ray Milkey269ffb92014-04-03 14:43:30 -0700827 // TODO: The implementation below is probably wrong
Yuta HIGUCHIbfc77f02014-07-14 22:50:25 -0700828 ByteBuffer id = ByteBuffer.wrap(hostEvent.getID());
829 for (SwitchPort swp : hostEvent.getAttachmentPoints()) {
830 Map<ByteBuffer, HostEvent> oldHostEvents =
831 discoveredAddedHostEvents.get(swp.getDpid());
832 if (oldHostEvents != null) {
833 oldHostEvents.remove(id);
Ray Milkey269ffb92014-04-03 14:43:30 -0700834 }
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/>
Yuta HIGUCHIbfc77f02014-07-14 22:50:25 -0700926 * It will call {@link #removeHost(HostEvent)} for each hosts on this port
Yuta HIGUCHIbf0a8712014-06-30 18:59:46 -0700927 * 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 //
Yuta HIGUCHIbfc77f02014-07-14 22:50:25 -0700947 // Remove all Hosts attached to the Port
Ray Milkey269ffb92014-04-03 14:43:30 -0700948 //
Yuta HIGUCHIbfc77f02014-07-14 22:50:25 -0700949 ArrayList<HostEvent> hostsToRemove = new ArrayList<>();
950 for (Host host : port.getHosts()) {
951 log.debug("Removing Host {} on Port {}", host, portEvent);
952 HostEvent hostEvent = new HostEvent(host.getMacAddress());
Ray Milkey269ffb92014-04-03 14:43:30 -0700953 SwitchPort switchPort = new SwitchPort(port.getSwitch().getDpid(),
954 port.getNumber());
Yuta HIGUCHIbfc77f02014-07-14 22:50:25 -0700955 hostEvent.addAttachmentPoint(switchPort);
956 hostsToRemove.add(hostEvent);
Ray Milkey269ffb92014-04-03 14:43:30 -0700957 }
Yuta HIGUCHIbfc77f02014-07-14 22:50:25 -0700958 for (HostEvent hostEvent : hostsToRemove) {
959 removeHost(hostEvent);
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/>
Yuta HIGUCHIbfc77f02014-07-14 22:50:25 -0700993 * It will call {@link #removeHost(HostEvent)} 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
Yuta HIGUCHIbfc77f02014-07-14 22:50:25 -07001025 // Remove all Hosts attached to the Ports
1026 ArrayList<HostEvent> hostsToRemove = new ArrayList<>();
Ray Milkey269ffb92014-04-03 14:43:30 -07001027 ArrayList<Port> ports = new ArrayList<>();
1028 ports.add(srcPort);
1029 ports.add(dstPort);
1030 for (Port port : ports) {
Yuta HIGUCHIbfc77f02014-07-14 22:50:25 -07001031 for (Host host : port.getHosts()) {
1032 log.error("Host {} on Port {} should have been removed prior to adding Link {}",
1033 host, port, linkEvent);
1034 // FIXME must get Host info from topology, when we add attrs.
1035 HostEvent hostEvent =
1036 new HostEvent(host.getMacAddress());
Ray Milkey269ffb92014-04-03 14:43:30 -07001037 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
Yuta HIGUCHIbfc77f02014-07-14 22:50:25 -07001041 hostEvent.addAttachmentPoint(switchPort);
1042 hostsToRemove.add(hostEvent);
Ray Milkey269ffb92014-04-03 14:43:30 -07001043 }
1044 }
Yuta HIGUCHIbfc77f02014-07-14 22:50:25 -07001045 for (HostEvent hostEvent : hostsToRemove) {
1046 removeHost(hostEvent);
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 HIGUCHIbfc77f02014-07-14 22:50:25 -07001103 * Adds a host to the topology replica.
Ray Milkey269ffb92014-04-03 14:43:30 -07001104 * <p/>
Yuta HIGUCHIbfc77f02014-07-14 22:50:25 -07001105 * TODO: Host-related work is incomplete.
Pavlin Radoslavov734ff5a2014-02-26 10:20:43 -08001106 * TODO: Eventually, we might need to consider reordering
1107 * or addLink() and addDevice() events on the same port.
1108 *
Yuta HIGUCHIbfc77f02014-07-14 22:50:25 -07001109 * @param hostEvent the HostEvent with the host to add.
Pavlin Radoslavov734ff5a2014-02-26 10:20:43 -08001110 */
Yuta HIGUCHIbc67a052014-06-30 10:37:09 -07001111 @GuardedBy("topology.writeLock")
Yuta HIGUCHIbfc77f02014-07-14 22:50:25 -07001112 private void addHost(HostEvent hostEvent) {
1113 log.debug("Adding a host to the topology with mac {}", hostEvent.getMac());
1114 Host host = topology.getHostByMac(hostEvent.getMac());
Pavlin Radoslavov3c9cc552014-02-20 09:58:38 -08001115
Yuta HIGUCHIbfc77f02014-07-14 22:50:25 -07001116 if (host == null) {
1117 log.debug("Existing host was not found in the Topology: Adding new host: mac {}", hostEvent.getMac());
1118 host = new HostImpl(topology, hostEvent.getMac());
Ray Milkey269ffb92014-04-03 14:43:30 -07001119 }
Pavlin Radoslavov3c9cc552014-02-20 09:58:38 -08001120
Yuta HIGUCHIbfc77f02014-07-14 22:50:25 -07001121 HostImpl hostImpl = (HostImpl) host;
Pavlin Radoslavov3c9cc552014-02-20 09:58:38 -08001122
Ray Milkey269ffb92014-04-03 14:43:30 -07001123 // Process each attachment point
1124 boolean attachmentFound = false;
Yuta HIGUCHIbfc77f02014-07-14 22:50:25 -07001125 for (SwitchPort swp : hostEvent.getAttachmentPoints()) {
1126 // XXX domain knowledge: Port must exist before Host
Yuta HIGUCHIbf0a8712014-06-30 18:59:46 -07001127 // 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
Yuta HIGUCHIbfc77f02014-07-14 22:50:25 -07001133 ByteBuffer id = hostEvent.getIDasByteBuffer();
1134 reorderedAddedHostEvents.put(id, hostEvent);
Ray Milkey269ffb92014-04-03 14:43:30 -07001135 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
Yuta HIGUCHIbfc77f02014-07-14 22:50:25 -07001146 // Add Host <-> Port attachment
1147 hostImpl.addAttachmentPoint(port);
Ray Milkey269ffb92014-04-03 14:43:30 -07001148 attachmentFound = true;
1149 }
1150
Yuta HIGUCHIbfc77f02014-07-14 22:50:25 -07001151 hostImpl.setLastSeenTime(hostEvent.getLastSeenTime());
TeruU896019b2014-07-10 16:10:09 -07001152
Yuta HIGUCHIbfc77f02014-07-14 22:50:25 -07001153 // Update the host in the topology
Ray Milkey269ffb92014-04-03 14:43:30 -07001154 if (attachmentFound) {
Yuta HIGUCHIbfc77f02014-07-14 22:50:25 -07001155 log.debug("Storing the host info into the Topology: mac {}", hostEvent.getMac());
1156 topology.putHost(host);
1157 apiAddedHostEvents.add(hostEvent);
Ray Milkey269ffb92014-04-03 14:43:30 -07001158 }
Pavlin Radoslavov3c9cc552014-02-20 09:58:38 -08001159 }
1160
Pavlin Radoslavov734ff5a2014-02-26 10:20:43 -08001161 /**
Yuta HIGUCHIbfc77f02014-07-14 22:50:25 -07001162 * Removes a host from the topology replica.
Ray Milkey269ffb92014-04-03 14:43:30 -07001163 * <p/>
Yuta HIGUCHIbfc77f02014-07-14 22:50:25 -07001164 * TODO: Host-related work is incomplete.
Pavlin Radoslavov734ff5a2014-02-26 10:20:43 -08001165 *
Yuta HIGUCHIbfc77f02014-07-14 22:50:25 -07001166 * @param hostEvent the Host Event with the host to remove.
Pavlin Radoslavov734ff5a2014-02-26 10:20:43 -08001167 */
Yuta HIGUCHIbc67a052014-06-30 10:37:09 -07001168 @GuardedBy("topology.writeLock")
Yuta HIGUCHIbfc77f02014-07-14 22:50:25 -07001169 private void removeHost(HostEvent hostEvent) {
1170 log.debug("Removing a host from the topology: mac {}", hostEvent.getMac());
1171 Host host = topology.getHostByMac(hostEvent.getMac());
1172 if (host == null) {
1173 log.warn("Host {} already removed, ignoring", hostEvent);
Ray Milkey269ffb92014-04-03 14:43:30 -07001174 return;
1175 }
Pavlin Radoslavov3c9cc552014-02-20 09:58:38 -08001176
Yuta HIGUCHIbfc77f02014-07-14 22:50:25 -07001177 topology.removeHost(host);
1178 apiRemovedHostEvents.add(hostEvent);
Pavlin Radoslavov3c9cc552014-02-20 09:58:38 -08001179 }
Jonathan Hart22eb9882014-02-11 15:52:59 -08001180
Pavlin Radoslavovc1cfde52014-02-19 11:35:29 -08001181 /**
Pavlin Radoslavov734ff5a2014-02-26 10:20:43 -08001182 * Read the whole topology from the database.
1183 *
1184 * @return a collection of EventEntry-encapsulated Topology Events for
1185 * the whole topology.
1186 */
Pavlin Radoslavov018d5332014-02-19 23:08:35 -08001187 private Collection<EventEntry<TopologyEvent>> readWholeTopologyFromDB() {
Ray Milkey269ffb92014-04-03 14:43:30 -07001188 Collection<EventEntry<TopologyEvent>> collection =
1189 new LinkedList<EventEntry<TopologyEvent>>();
Pavlin Radoslavov018d5332014-02-19 23:08:35 -08001190
Ray Milkey269ffb92014-04-03 14:43:30 -07001191 // XXX May need to clear whole topology first, depending on
1192 // how we initially subscribe to replication events
Pavlin Radoslavovc1cfde52014-02-19 11:35:29 -08001193
Ray Milkey269ffb92014-04-03 14:43:30 -07001194 // Add all active switches
1195 for (KVSwitch sw : KVSwitch.getAllSwitches()) {
1196 if (sw.getStatus() != KVSwitch.STATUS.ACTIVE) {
1197 continue;
1198 }
Pavlin Radoslavov018d5332014-02-19 23:08:35 -08001199
Yuta HIGUCHIe2a4e172014-07-03 10:50:39 -07001200 SwitchEvent switchEvent = new SwitchEvent(new Dpid(sw.getDpid()));
Ray Milkey269ffb92014-04-03 14:43:30 -07001201 TopologyEvent topologyEvent = new TopologyEvent(switchEvent);
1202 EventEntry<TopologyEvent> eventEntry =
1203 new EventEntry<TopologyEvent>(EventEntry.Type.ENTRY_ADD,
1204 topologyEvent);
1205 collection.add(eventEntry);
1206 }
Yuta HIGUCHIa536e762014-02-17 21:47:28 -08001207
Ray Milkey269ffb92014-04-03 14:43:30 -07001208 // Add all active ports
1209 for (KVPort p : KVPort.getAllPorts()) {
1210 if (p.getStatus() != KVPort.STATUS.ACTIVE) {
1211 continue;
1212 }
Pavlin Radoslavov018d5332014-02-19 23:08:35 -08001213
Yuta HIGUCHIe2a4e172014-07-03 10:50:39 -07001214 PortEvent portEvent = new PortEvent(
1215 new Dpid(p.getDpid()),
1216 new PortNumber(p.getNumber().shortValue()));
Ray Milkey269ffb92014-04-03 14:43:30 -07001217 TopologyEvent topologyEvent = new TopologyEvent(portEvent);
1218 EventEntry<TopologyEvent> eventEntry =
1219 new EventEntry<TopologyEvent>(EventEntry.Type.ENTRY_ADD,
1220 topologyEvent);
1221 collection.add(eventEntry);
1222 }
Yuta HIGUCHIa536e762014-02-17 21:47:28 -08001223
TeruU28adcc32014-04-15 17:57:35 -07001224 for (KVDevice d : KVDevice.getAllDevices()) {
Yuta HIGUCHIbfc77f02014-07-14 22:50:25 -07001225 HostEvent devEvent = new HostEvent(MACAddress.valueOf(d.getMac()));
TeruU28adcc32014-04-15 17:57:35 -07001226 for (byte[] portId : d.getAllPortIds()) {
Jonathan Hartc00f5c22014-06-10 15:14:40 -07001227 devEvent.addAttachmentPoint(
1228 new SwitchPort(KVPort.getDpidFromKey(portId),
1229 KVPort.getNumberFromKey(portId)));
TeruU28adcc32014-04-15 17:57:35 -07001230 }
1231 }
Pavlin Radoslavovc1cfde52014-02-19 11:35:29 -08001232
Ray Milkey269ffb92014-04-03 14:43:30 -07001233 for (KVLink l : KVLink.getAllLinks()) {
Yuta HIGUCHIe2a4e172014-07-03 10:50:39 -07001234 LinkEvent linkEvent = new LinkEvent(
1235 new SwitchPort(l.getSrc().dpid, l.getSrc().number),
1236 new SwitchPort(l.getDst().dpid, l.getDst().number));
Ray Milkey269ffb92014-04-03 14:43:30 -07001237 TopologyEvent topologyEvent = new TopologyEvent(linkEvent);
1238 EventEntry<TopologyEvent> eventEntry =
1239 new EventEntry<TopologyEvent>(EventEntry.Type.ENTRY_ADD,
1240 topologyEvent);
1241 collection.add(eventEntry);
1242 }
Pavlin Radoslavov018d5332014-02-19 23:08:35 -08001243
Ray Milkey269ffb92014-04-03 14:43:30 -07001244 return collection;
Pavlin Radoslavovc1cfde52014-02-19 11:35:29 -08001245 }
weibitf7c31a42014-06-23 16:51:01 -07001246 /**
1247 * Replaces the internal datastore instance.
1248 *
1249 * @param dataStore instance
1250 *
1251 * @exclude Backdoor for unit testing purpose only, do not use.
1252 */
1253 void debugReplaceDataStore(final TopologyDatastore dataStoreService) {
1254 this.datastore = dataStoreService;
1255 }
Jonathan Hart062a2e82014-02-03 09:41:57 -08001256}