blob: 7e7f2b83b7b49920144d4c7f6aab5e2b89afea8d [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;
Yuta HIGUCHI8b389a72014-07-18 13:50:00 -07005import java.util.Arrays;
Pavlin Radoslavov721a2e02014-02-14 23:40:14 -08006import java.util.Collection;
Yuta HIGUCHI8b389a72014-07-18 13:50:00 -07007import java.util.Comparator;
Pavlin Radoslavov018d5332014-02-19 23:08:35 -08008import java.util.HashMap;
Yuta HIGUCHI8d762e92014-02-12 14:10:25 -08009import java.util.HashSet;
Pavlin Radoslavov721a2e02014-02-14 23:40:14 -080010import java.util.LinkedList;
Yuta HIGUCHI8d762e92014-02-12 14:10:25 -080011import java.util.List;
Pavlin Radoslavov018d5332014-02-19 23:08:35 -080012import java.util.Map;
Yuta HIGUCHI8d762e92014-02-12 14:10:25 -080013import java.util.Set;
Yuta HIGUCHI8b389a72014-07-18 13:50:00 -070014import java.util.TreeSet;
Pavlin Radoslavov721a2e02014-02-14 23:40:14 -080015import java.util.concurrent.BlockingQueue;
Yuta HIGUCHIa536e762014-02-17 21:47:28 -080016import java.util.concurrent.CopyOnWriteArrayList;
Pavlin Radoslavov721a2e02014-02-14 23:40:14 -080017import java.util.concurrent.LinkedBlockingQueue;
Yuta HIGUCHI8d762e92014-02-12 14:10:25 -080018
Yuta HIGUCHIbc67a052014-06-30 10:37:09 -070019import javax.annotation.concurrent.GuardedBy;
20
TeruU28adcc32014-04-15 17:57:35 -070021import net.floodlightcontroller.util.MACAddress;
Jonathan Hart6df90172014-04-03 10:13:11 -070022import net.onrc.onos.core.datagrid.IDatagridService;
23import net.onrc.onos.core.datagrid.IEventChannel;
24import net.onrc.onos.core.datagrid.IEventChannelListener;
TeruU28adcc32014-04-15 17:57:35 -070025import net.onrc.onos.core.datastore.topology.KVDevice;
Jonathan Hart6df90172014-04-03 10:13:11 -070026import net.onrc.onos.core.datastore.topology.KVLink;
27import net.onrc.onos.core.datastore.topology.KVPort;
28import net.onrc.onos.core.datastore.topology.KVSwitch;
Jonathan Hartdeda0ba2014-04-03 11:14:12 -070029import net.onrc.onos.core.registry.IControllerRegistryService;
Yuta HIGUCHI8f3dfa32014-06-25 00:14:25 -070030import net.onrc.onos.core.util.Dpid;
Jonathan Hart23701d12014-04-03 10:45:48 -070031import net.onrc.onos.core.util.EventEntry;
Yuta HIGUCHIe2a4e172014-07-03 10:50:39 -070032import net.onrc.onos.core.util.PortNumber;
Yuta HIGUCHI5c8cbeb2014-06-27 11:13:48 -070033import net.onrc.onos.core.util.SwitchPort;
Pavlin Radoslavov4eaab992014-07-03 18:39:42 -070034import net.onrc.onos.core.util.serializers.KryoFactory;
Yuta HIGUCHI5c8cbeb2014-06-27 11:13:48 -070035
Jonathan Hart062a2e82014-02-03 09:41:57 -080036import org.slf4j.Logger;
37import org.slf4j.LoggerFactory;
38
Pavlin Radoslavov4eaab992014-07-03 18:39:42 -070039import com.esotericsoftware.kryo.Kryo;
40
Yuta HIGUCHI181d34d2014-02-05 15:05:46 -080041/**
Jonathan Harte37e4e22014-05-13 19:12:02 -070042 * The TopologyManager receives topology updates from the southbound discovery
43 * modules and from other ONOS instances. These updates are processed and
44 * applied to the in-memory topology instance.
Ray Milkey269ffb92014-04-03 14:43:30 -070045 * <p/>
Yuta HIGUCHI4bfdd532014-02-07 13:47:36 -080046 * - Maintain Invariant/Relationships between Topology Objects.
Ray Milkey269ffb92014-04-03 14:43:30 -070047 * <p/>
Yuta HIGUCHI765cd0d2014-02-06 12:46:41 -080048 * TODO To be synchronized based on TopologyEvent Notification.
Ray Milkey269ffb92014-04-03 14:43:30 -070049 * <p/>
Yuta HIGUCHIcb951982014-02-11 13:31:44 -080050 * TODO TBD: Caller is expected to maintain parent/child calling order. Parent
Yuta HIGUCHI1c700102014-02-12 16:30:52 -080051 * Object must exist before adding sub component(Add Switch -> Port).
Ray Milkey269ffb92014-04-03 14:43:30 -070052 * <p/>
Yuta HIGUCHI4bfdd532014-02-07 13:47:36 -080053 * TODO TBD: This class may delay the requested change to handle event
54 * re-ordering. e.g.) Link Add came in, but Switch was not there.
Yuta HIGUCHI181d34d2014-02-05 15:05:46 -080055 */
Jonathan Harte37e4e22014-05-13 19:12:02 -070056public class TopologyManager implements TopologyDiscoveryInterface {
Jonathan Hart062a2e82014-02-03 09:41:57 -080057
Yuta HIGUCHI80829d12014-02-05 20:16:56 -080058 private static final Logger log = LoggerFactory
Ray Milkey269ffb92014-04-03 14:43:30 -070059 .getLogger(TopologyManager.class);
Yuta HIGUCHIcd922f42014-02-11 18:59:11 -080060
Pavlin Radoslavov721a2e02014-02-14 23:40:14 -080061 private IEventChannel<byte[], TopologyEvent> eventChannel;
Jonathan Hart10a7e2b2014-02-21 18:30:08 -080062 public static final String EVENT_CHANNEL_NAME = "onos.topology";
Pavlin Radoslavov721a2e02014-02-14 23:40:14 -080063 private EventHandler eventHandler = new EventHandler();
64
weibitf7c31a42014-06-23 16:51:01 -070065 private TopologyDatastore datastore;
Jonathan Harte37e4e22014-05-13 19:12:02 -070066 private final TopologyImpl topology = new TopologyImpl();
Yuta HIGUCHI170229f2014-02-17 15:47:54 -080067 private final IControllerRegistryService registryService;
Jonathan Harte37e4e22014-05-13 19:12:02 -070068 private CopyOnWriteArrayList<ITopologyListener> topologyListeners;
Pavlin Radoslavov4eaab992014-07-03 18:39:42 -070069 private Kryo kryo = KryoFactory.newKryoObject();
Yuta HIGUCHI181d34d2014-02-05 15:05:46 -080070
Pavlin Radoslavov706add22014-02-20 12:15:59 -080071 //
72 // Local state for keeping track of reordered events.
73 // NOTE: Switch Events are not affected by the event reordering.
74 //
75 private Map<ByteBuffer, PortEvent> reorderedAddedPortEvents =
Ray Milkey269ffb92014-04-03 14:43:30 -070076 new HashMap<ByteBuffer, PortEvent>();
Pavlin Radoslavov706add22014-02-20 12:15:59 -080077 private Map<ByteBuffer, LinkEvent> reorderedAddedLinkEvents =
Ray Milkey269ffb92014-04-03 14:43:30 -070078 new HashMap<ByteBuffer, LinkEvent>();
Yuta HIGUCHIbfc77f02014-07-14 22:50:25 -070079 private Map<ByteBuffer, HostEvent> reorderedAddedHostEvents =
80 new HashMap<ByteBuffer, HostEvent>();
Pavlin Radoslavov018d5332014-02-19 23:08:35 -080081
Pavlin Radoslavov74986ce2014-02-20 13:17:20 -080082 //
Pavlin Radoslavov26d83402014-02-20 15:24:30 -080083 // Local state for keeping track of locally discovered events so we can
84 // cleanup properly when a Switch or Port is removed.
85 //
Yuta HIGUCHIbfc77f02014-07-14 22:50:25 -070086 // We keep all Port, (incoming) Link and Host events per Switch DPID:
Pavlin Radoslavov26d83402014-02-20 15:24:30 -080087 // - If a switch goes down, we remove all corresponding Port, Link and
Yuta HIGUCHIbfc77f02014-07-14 22:50:25 -070088 // Host events.
Pavlin Radoslavov26d83402014-02-20 15:24:30 -080089 // - If a port on a switch goes down, we remove all corresponding Link
Yuta HIGUCHIbfc77f02014-07-14 22:50:25 -070090 // and Host events discovered by this instance.
Yuta HIGUCHIbc67a052014-06-30 10:37:09 -070091 //
92 // How to handle side-effect of remote events.
93 // - Remote Port Down event -> Link Down
94 // Not handled. (XXX Shouldn't it be removed from discovered.. Map)
Yuta HIGUCHIbfc77f02014-07-14 22:50:25 -070095 // - Remote Host Added -> lose ownership of Host)
Yuta HIGUCHIbc67a052014-06-30 10:37:09 -070096 // Not handled. (XXX Shouldn't it be removed from discovered.. Map)
97 //
98 // XXX Domain knowledge based invariant maintenance should be moved to
99 // driver module, since the invariant may be different on optical, etc.
100 //
101 // What happens on leadership change?
102 // - Probably should: remove from discovered.. Maps, but not send DELETE events
Yuta HIGUCHIbfc77f02014-07-14 22:50:25 -0700103 // XXX Switch/Port can be rediscovered by new leader, but Link, Host?
Yuta HIGUCHIbc67a052014-06-30 10:37:09 -0700104 // - Current: There is no way to recognize leadership change?
105 // ZookeeperRegistry.requestControl(long, ControlChangeCallback)
106 // is the only way to register listener, and it allows only 1 listener,
107 // which is already used by Controller class.
108 //
109 // FIXME Replace with concurrent variant.
110 // #removeSwitchDiscoveryEvent(SwitchEvent) runs in different thread.
Pavlin Radoslavov26d83402014-02-20 15:24:30 -0800111 //
Yuta HIGUCHI8f3dfa32014-06-25 00:14:25 -0700112 private Map<Dpid, Map<ByteBuffer, PortEvent>> discoveredAddedPortEvents =
Ray Milkey269ffb92014-04-03 14:43:30 -0700113 new HashMap<>();
Yuta HIGUCHI8f3dfa32014-06-25 00:14:25 -0700114 private Map<Dpid, Map<ByteBuffer, LinkEvent>> discoveredAddedLinkEvents =
Ray Milkey269ffb92014-04-03 14:43:30 -0700115 new HashMap<>();
Yuta HIGUCHIbfc77f02014-07-14 22:50:25 -0700116 private Map<Dpid, Map<ByteBuffer, HostEvent>> discoveredAddedHostEvents =
Ray Milkey269ffb92014-04-03 14:43:30 -0700117 new HashMap<>();
Pavlin Radoslavov26d83402014-02-20 15:24:30 -0800118
119 //
Pavlin Radoslavov74986ce2014-02-20 13:17:20 -0800120 // Local state for keeping track of the application event notifications
121 //
Yuta HIGUCHIbc67a052014-06-30 10:37:09 -0700122 // - Queue of events, which will be dispatched to local listeners
123 // on next notification.
Yuta HIGUCHI703696c2014-06-25 20:36:45 -0700124
125 private List<SwitchEvent> apiAddedSwitchEvents = new LinkedList<>();
126 private List<SwitchEvent> apiRemovedSwitchEvents = new LinkedList<>();
127 private List<PortEvent> apiAddedPortEvents = new LinkedList<>();
128 private List<PortEvent> apiRemovedPortEvents = new LinkedList<>();
129 private List<LinkEvent> apiAddedLinkEvents = new LinkedList<>();
130 private List<LinkEvent> apiRemovedLinkEvents = new LinkedList<>();
Yuta HIGUCHIbfc77f02014-07-14 22:50:25 -0700131 private List<HostEvent> apiAddedHostEvents = new LinkedList<>();
132 private List<HostEvent> apiRemovedHostEvents = new LinkedList<>();
Pavlin Radoslavov74986ce2014-02-20 13:17:20 -0800133
Pavlin Radoslavovc1cfde52014-02-19 11:35:29 -0800134 /**
135 * Constructor.
136 *
Jonathan Harte37e4e22014-05-13 19:12:02 -0700137 * @param registryService the Registry Service to use.
138 * @param topologyListeners the collection of topology listeners to use.
Pavlin Radoslavovc1cfde52014-02-19 11:35:29 -0800139 */
140 public TopologyManager(IControllerRegistryService registryService,
Jonathan Harte37e4e22014-05-13 19:12:02 -0700141 CopyOnWriteArrayList<ITopologyListener> topologyListeners) {
142 datastore = new TopologyDatastore();
Ray Milkey269ffb92014-04-03 14:43:30 -0700143 this.registryService = registryService;
Jonathan Harte37e4e22014-05-13 19:12:02 -0700144 this.topologyListeners = topologyListeners;
Yuta HIGUCHI80829d12014-02-05 20:16:56 -0800145 }
Yuta HIGUCHI181d34d2014-02-05 15:05:46 -0800146
Pavlin Radoslavovc1cfde52014-02-19 11:35:29 -0800147 /**
Jonathan Harte37e4e22014-05-13 19:12:02 -0700148 * Get the Topology.
Pavlin Radoslavovc1cfde52014-02-19 11:35:29 -0800149 *
Jonathan Harte37e4e22014-05-13 19:12:02 -0700150 * @return the Topology.
Pavlin Radoslavovc1cfde52014-02-19 11:35:29 -0800151 */
Jonathan Harte37e4e22014-05-13 19:12:02 -0700152 Topology getTopology() {
153 return topology;
Pavlin Radoslavov6d224ee2014-02-18 16:43:15 -0800154 }
155
Yuta HIGUCHI4bfdd532014-02-07 13:47:36 -0800156 /**
Pavlin Radoslavov721a2e02014-02-14 23:40:14 -0800157 * Event handler class.
158 */
Yuta HIGUCHI8b389a72014-07-18 13:50:00 -0700159 class EventHandler extends Thread implements
Ray Milkey269ffb92014-04-03 14:43:30 -0700160 IEventChannelListener<byte[], TopologyEvent> {
161 private BlockingQueue<EventEntry<TopologyEvent>> topologyEvents =
162 new LinkedBlockingQueue<EventEntry<TopologyEvent>>();
Pavlin Radoslavov721a2e02014-02-14 23:40:14 -0800163
Ray Milkey269ffb92014-04-03 14:43:30 -0700164 /**
165 * Startup processing.
166 */
167 private void startup() {
168 //
169 // TODO: Read all state from the database:
170 //
171 // Collection<EventEntry<TopologyEvent>> collection =
172 // readWholeTopologyFromDB();
173 //
174 // For now, as a shortcut we read it from the datagrid
175 //
Ray Milkey5df613b2014-04-15 10:50:56 -0700176 Collection<TopologyEvent> allTopologyEvents =
Ray Milkey269ffb92014-04-03 14:43:30 -0700177 eventChannel.getAllEntries();
178 Collection<EventEntry<TopologyEvent>> collection =
179 new LinkedList<EventEntry<TopologyEvent>>();
Pavlin Radoslavov721a2e02014-02-14 23:40:14 -0800180
Ray Milkey5df613b2014-04-15 10:50:56 -0700181 for (TopologyEvent topologyEvent : allTopologyEvents) {
Ray Milkey269ffb92014-04-03 14:43:30 -0700182 EventEntry<TopologyEvent> eventEntry =
183 new EventEntry<TopologyEvent>(EventEntry.Type.ENTRY_ADD,
184 topologyEvent);
185 collection.add(eventEntry);
186 }
187 processEvents(collection);
188 }
Pavlin Radoslavov721a2e02014-02-14 23:40:14 -0800189
Ray Milkey269ffb92014-04-03 14:43:30 -0700190 /**
191 * Run the thread.
192 */
193 @Override
194 public void run() {
195 Collection<EventEntry<TopologyEvent>> collection =
196 new LinkedList<EventEntry<TopologyEvent>>();
Pavlin Radoslavov721a2e02014-02-14 23:40:14 -0800197
Ray Milkey269ffb92014-04-03 14:43:30 -0700198 this.setName("TopologyManager.EventHandler " + this.getId());
199 startup();
Pavlin Radoslavov721a2e02014-02-14 23:40:14 -0800200
Ray Milkey269ffb92014-04-03 14:43:30 -0700201 //
202 // The main loop
203 //
Pavlin Radoslavov8e881a42014-06-24 16:58:07 -0700204 while (true) {
205 try {
206 EventEntry<TopologyEvent> eventEntry =
207 topologyEvents.take();
Ray Milkey269ffb92014-04-03 14:43:30 -0700208 collection.add(eventEntry);
209 topologyEvents.drainTo(collection);
Pavlin Radoslavov721a2e02014-02-14 23:40:14 -0800210
Ray Milkey269ffb92014-04-03 14:43:30 -0700211 processEvents(collection);
212 collection.clear();
Pavlin Radoslavov8e881a42014-06-24 16:58:07 -0700213 } catch (Exception exception) {
214 log.debug("Exception processing Topology Events: ",
215 exception);
Ray Milkey269ffb92014-04-03 14:43:30 -0700216 }
Ray Milkey269ffb92014-04-03 14:43:30 -0700217 }
218 }
Pavlin Radoslavov721a2e02014-02-14 23:40:14 -0800219
Ray Milkey269ffb92014-04-03 14:43:30 -0700220 /**
221 * Process all topology events.
222 *
223 * @param events the events to process.
224 */
225 private void processEvents(Collection<EventEntry<TopologyEvent>> events) {
226 // Local state for computing the final set of events
227 Map<ByteBuffer, SwitchEvent> addedSwitchEvents = new HashMap<>();
228 Map<ByteBuffer, SwitchEvent> removedSwitchEvents = new HashMap<>();
229 Map<ByteBuffer, PortEvent> addedPortEvents = new HashMap<>();
230 Map<ByteBuffer, PortEvent> removedPortEvents = new HashMap<>();
231 Map<ByteBuffer, LinkEvent> addedLinkEvents = new HashMap<>();
232 Map<ByteBuffer, LinkEvent> removedLinkEvents = new HashMap<>();
Yuta HIGUCHIbfc77f02014-07-14 22:50:25 -0700233 Map<ByteBuffer, HostEvent> addedHostEvents = new HashMap<>();
234 Map<ByteBuffer, HostEvent> removedHostEvents = new HashMap<>();
Pavlin Radoslavov3c9cc552014-02-20 09:58:38 -0800235
Ray Milkey269ffb92014-04-03 14:43:30 -0700236 //
237 // Classify and suppress matching events
238 //
239 for (EventEntry<TopologyEvent> event : events) {
240 TopologyEvent topologyEvent = event.eventData();
241 SwitchEvent switchEvent = topologyEvent.switchEvent;
242 PortEvent portEvent = topologyEvent.portEvent;
243 LinkEvent linkEvent = topologyEvent.linkEvent;
Yuta HIGUCHIbfc77f02014-07-14 22:50:25 -0700244 HostEvent hostEvent = topologyEvent.hostEvent;
Pavlin Radoslavov018d5332014-02-19 23:08:35 -0800245
Ray Milkey269ffb92014-04-03 14:43:30 -0700246 //
247 // Extract the events
248 //
Yuta HIGUCHI8b389a72014-07-18 13:50:00 -0700249 // FIXME Following event squashing logic based only on ID
250 // potentially lose attribute change.
Ray Milkey269ffb92014-04-03 14:43:30 -0700251 switch (event.eventType()) {
252 case ENTRY_ADD:
253 log.debug("Topology event ENTRY_ADD: {}", topologyEvent);
254 if (switchEvent != null) {
255 ByteBuffer id = switchEvent.getIDasByteBuffer();
256 addedSwitchEvents.put(id, switchEvent);
257 removedSwitchEvents.remove(id);
258 // Switch Events are not affected by event reordering
259 }
260 if (portEvent != null) {
261 ByteBuffer id = portEvent.getIDasByteBuffer();
262 addedPortEvents.put(id, portEvent);
263 removedPortEvents.remove(id);
264 reorderedAddedPortEvents.remove(id);
265 }
266 if (linkEvent != null) {
267 ByteBuffer id = linkEvent.getIDasByteBuffer();
268 addedLinkEvents.put(id, linkEvent);
269 removedLinkEvents.remove(id);
270 reorderedAddedLinkEvents.remove(id);
271 }
Yuta HIGUCHIbfc77f02014-07-14 22:50:25 -0700272 if (hostEvent != null) {
273 ByteBuffer id = hostEvent.getIDasByteBuffer();
274 addedHostEvents.put(id, hostEvent);
275 removedHostEvents.remove(id);
276 reorderedAddedHostEvents.remove(id);
Ray Milkey269ffb92014-04-03 14:43:30 -0700277 }
278 break;
279 case ENTRY_REMOVE:
280 log.debug("Topology event ENTRY_REMOVE: {}", topologyEvent);
281 if (switchEvent != null) {
282 ByteBuffer id = switchEvent.getIDasByteBuffer();
283 addedSwitchEvents.remove(id);
284 removedSwitchEvents.put(id, switchEvent);
285 // Switch Events are not affected by event reordering
286 }
287 if (portEvent != null) {
288 ByteBuffer id = portEvent.getIDasByteBuffer();
289 addedPortEvents.remove(id);
290 removedPortEvents.put(id, portEvent);
291 reorderedAddedPortEvents.remove(id);
292 }
293 if (linkEvent != null) {
294 ByteBuffer id = linkEvent.getIDasByteBuffer();
295 addedLinkEvents.remove(id);
296 removedLinkEvents.put(id, linkEvent);
297 reorderedAddedLinkEvents.remove(id);
298 }
Yuta HIGUCHIbfc77f02014-07-14 22:50:25 -0700299 if (hostEvent != null) {
300 ByteBuffer id = hostEvent.getIDasByteBuffer();
301 addedHostEvents.remove(id);
302 removedHostEvents.put(id, hostEvent);
303 reorderedAddedHostEvents.remove(id);
Ray Milkey269ffb92014-04-03 14:43:30 -0700304 }
305 break;
Ray Milkey0b122ed2014-04-14 10:06:03 -0700306 default:
307 log.error("Unknown topology event {}",
308 event.eventType());
Ray Milkey269ffb92014-04-03 14:43:30 -0700309 }
310 }
Pavlin Radoslavov3c9cc552014-02-20 09:58:38 -0800311
Ray Milkey269ffb92014-04-03 14:43:30 -0700312 //
Jonathan Harte37e4e22014-05-13 19:12:02 -0700313 // Lock the topology while it is modified
Ray Milkey269ffb92014-04-03 14:43:30 -0700314 //
Jonathan Harte37e4e22014-05-13 19:12:02 -0700315 topology.acquireWriteLock();
Pavlin Radoslavov8ffb8bf2014-02-20 15:34:26 -0800316
Ray Milkey269ffb92014-04-03 14:43:30 -0700317 try {
318 //
319 // Apply the classified events.
320 //
321 // Apply the "add" events in the proper order:
Yuta HIGUCHIbfc77f02014-07-14 22:50:25 -0700322 // switch, port, link, host
Ray Milkey269ffb92014-04-03 14:43:30 -0700323 //
Ray Milkeyb29e6262014-04-09 16:02:14 -0700324 for (SwitchEvent switchEvent : addedSwitchEvents.values()) {
Ray Milkey269ffb92014-04-03 14:43:30 -0700325 addSwitch(switchEvent);
Ray Milkeyb29e6262014-04-09 16:02:14 -0700326 }
327 for (PortEvent portEvent : addedPortEvents.values()) {
Ray Milkey269ffb92014-04-03 14:43:30 -0700328 addPort(portEvent);
Ray Milkeyb29e6262014-04-09 16:02:14 -0700329 }
330 for (LinkEvent linkEvent : addedLinkEvents.values()) {
Ray Milkey269ffb92014-04-03 14:43:30 -0700331 addLink(linkEvent);
Ray Milkeyb29e6262014-04-09 16:02:14 -0700332 }
Yuta HIGUCHIbfc77f02014-07-14 22:50:25 -0700333 for (HostEvent hostEvent : addedHostEvents.values()) {
334 addHost(hostEvent);
Ray Milkeyb29e6262014-04-09 16:02:14 -0700335 }
Ray Milkey269ffb92014-04-03 14:43:30 -0700336 //
337 // Apply the "remove" events in the reverse order:
Yuta HIGUCHIbfc77f02014-07-14 22:50:25 -0700338 // host, link, port, switch
Ray Milkey269ffb92014-04-03 14:43:30 -0700339 //
Yuta HIGUCHIbfc77f02014-07-14 22:50:25 -0700340 for (HostEvent hostEvent : removedHostEvents.values()) {
341 removeHost(hostEvent);
Ray Milkeyb29e6262014-04-09 16:02:14 -0700342 }
343 for (LinkEvent linkEvent : removedLinkEvents.values()) {
Ray Milkey269ffb92014-04-03 14:43:30 -0700344 removeLink(linkEvent);
Ray Milkeyb29e6262014-04-09 16:02:14 -0700345 }
346 for (PortEvent portEvent : removedPortEvents.values()) {
Ray Milkey269ffb92014-04-03 14:43:30 -0700347 removePort(portEvent);
Ray Milkeyb29e6262014-04-09 16:02:14 -0700348 }
349 for (SwitchEvent switchEvent : removedSwitchEvents.values()) {
Ray Milkey269ffb92014-04-03 14:43:30 -0700350 removeSwitch(switchEvent);
Ray Milkeyb29e6262014-04-09 16:02:14 -0700351 }
Yuta HIGUCHI3aca81a2014-02-23 12:41:19 -0800352
Ray Milkey269ffb92014-04-03 14:43:30 -0700353 //
354 // Apply reordered events
355 //
356 applyReorderedEvents(!addedSwitchEvents.isEmpty(),
357 !addedPortEvents.isEmpty());
Yuta HIGUCHI3aca81a2014-02-23 12:41:19 -0800358
Ray Milkey269ffb92014-04-03 14:43:30 -0700359 } finally {
360 //
Jonathan Harte37e4e22014-05-13 19:12:02 -0700361 // Topology modifications completed: Release the lock
Ray Milkey269ffb92014-04-03 14:43:30 -0700362 //
Jonathan Harte37e4e22014-05-13 19:12:02 -0700363 topology.releaseWriteLock();
Ray Milkey269ffb92014-04-03 14:43:30 -0700364 }
Yuta HIGUCHI3aca81a2014-02-23 12:41:19 -0800365
Ray Milkey269ffb92014-04-03 14:43:30 -0700366 //
367 // Dispatch the Topology Notification Events to the applications
368 //
Jonathan Harte37e4e22014-05-13 19:12:02 -0700369 dispatchTopologyEvents();
Ray Milkey269ffb92014-04-03 14:43:30 -0700370 }
Pavlin Radoslavov721a2e02014-02-14 23:40:14 -0800371
Ray Milkey269ffb92014-04-03 14:43:30 -0700372 /**
373 * Receive a notification that an entry is added.
374 *
375 * @param value the value for the entry.
376 */
377 @Override
378 public void entryAdded(TopologyEvent value) {
379 EventEntry<TopologyEvent> eventEntry =
380 new EventEntry<TopologyEvent>(EventEntry.Type.ENTRY_ADD,
381 value);
382 topologyEvents.add(eventEntry);
383 }
Pavlin Radoslavov721a2e02014-02-14 23:40:14 -0800384
Ray Milkey269ffb92014-04-03 14:43:30 -0700385 /**
386 * Receive a notification that an entry is removed.
387 *
388 * @param value the value for the entry.
389 */
390 @Override
391 public void entryRemoved(TopologyEvent value) {
392 EventEntry<TopologyEvent> eventEntry =
393 new EventEntry<TopologyEvent>(EventEntry.Type.ENTRY_REMOVE,
394 value);
395 topologyEvents.add(eventEntry);
396 }
Pavlin Radoslavov721a2e02014-02-14 23:40:14 -0800397
Ray Milkey269ffb92014-04-03 14:43:30 -0700398 /**
399 * Receive a notification that an entry is updated.
400 *
401 * @param value the value for the entry.
402 */
403 @Override
404 public void entryUpdated(TopologyEvent value) {
405 // NOTE: The ADD and UPDATE events are processed in same way
406 entryAdded(value);
407 }
Pavlin Radoslavov721a2e02014-02-14 23:40:14 -0800408 }
409
410 /**
411 * Startup processing.
412 *
413 * @param datagridService the datagrid service to use.
414 */
415 void startup(IDatagridService datagridService) {
Ray Milkey269ffb92014-04-03 14:43:30 -0700416 eventChannel = datagridService.addListener(EVENT_CHANNEL_NAME,
417 eventHandler,
418 byte[].class,
419 TopologyEvent.class);
420 eventHandler.start();
Pavlin Radoslavov721a2e02014-02-14 23:40:14 -0800421 }
422
Pavlin Radoslavov74986ce2014-02-20 13:17:20 -0800423 /**
Jonathan Harte37e4e22014-05-13 19:12:02 -0700424 * Dispatch Topology Events to the listeners.
Pavlin Radoslavov74986ce2014-02-20 13:17:20 -0800425 */
Jonathan Harte37e4e22014-05-13 19:12:02 -0700426 private void dispatchTopologyEvents() {
Ray Milkey269ffb92014-04-03 14:43:30 -0700427 if (apiAddedSwitchEvents.isEmpty() &&
428 apiRemovedSwitchEvents.isEmpty() &&
429 apiAddedPortEvents.isEmpty() &&
430 apiRemovedPortEvents.isEmpty() &&
431 apiAddedLinkEvents.isEmpty() &&
432 apiRemovedLinkEvents.isEmpty() &&
Yuta HIGUCHIbfc77f02014-07-14 22:50:25 -0700433 apiAddedHostEvents.isEmpty() &&
434 apiRemovedHostEvents.isEmpty()) {
Ray Milkey269ffb92014-04-03 14:43:30 -0700435 return; // No events to dispatch
436 }
Pavlin Radoslavov74986ce2014-02-20 13:17:20 -0800437
Ray Milkey269ffb92014-04-03 14:43:30 -0700438 if (log.isDebugEnabled()) {
439 //
440 // Debug statements
441 // TODO: Those statements should be removed in the future
442 //
Ray Milkeyb29e6262014-04-09 16:02:14 -0700443 for (SwitchEvent switchEvent : apiAddedSwitchEvents) {
Jonathan Harte37e4e22014-05-13 19:12:02 -0700444 log.debug("Dispatch Topology Event: ADDED {}", switchEvent);
Ray Milkeyb29e6262014-04-09 16:02:14 -0700445 }
446 for (SwitchEvent switchEvent : apiRemovedSwitchEvents) {
Jonathan Harte37e4e22014-05-13 19:12:02 -0700447 log.debug("Dispatch Topology Event: REMOVED {}", switchEvent);
Ray Milkeyb29e6262014-04-09 16:02:14 -0700448 }
449 for (PortEvent portEvent : apiAddedPortEvents) {
Jonathan Harte37e4e22014-05-13 19:12:02 -0700450 log.debug("Dispatch Topology Event: ADDED {}", portEvent);
Ray Milkeyb29e6262014-04-09 16:02:14 -0700451 }
452 for (PortEvent portEvent : apiRemovedPortEvents) {
Jonathan Harte37e4e22014-05-13 19:12:02 -0700453 log.debug("Dispatch Topology Event: REMOVED {}", portEvent);
Ray Milkeyb29e6262014-04-09 16:02:14 -0700454 }
455 for (LinkEvent linkEvent : apiAddedLinkEvents) {
Jonathan Harte37e4e22014-05-13 19:12:02 -0700456 log.debug("Dispatch Topology Event: ADDED {}", linkEvent);
Ray Milkeyb29e6262014-04-09 16:02:14 -0700457 }
458 for (LinkEvent linkEvent : apiRemovedLinkEvents) {
Jonathan Harte37e4e22014-05-13 19:12:02 -0700459 log.debug("Dispatch Topology Event: REMOVED {}", linkEvent);
Ray Milkeyb29e6262014-04-09 16:02:14 -0700460 }
Yuta HIGUCHIbfc77f02014-07-14 22:50:25 -0700461 for (HostEvent hostEvent : apiAddedHostEvents) {
462 log.debug("Dispatch Topology Event: ADDED {}", hostEvent);
Ray Milkeyb29e6262014-04-09 16:02:14 -0700463 }
Yuta HIGUCHIbfc77f02014-07-14 22:50:25 -0700464 for (HostEvent hostEvent : apiRemovedHostEvents) {
465 log.debug("Dispatch Topology Event: REMOVED {}", hostEvent);
Ray Milkeyb29e6262014-04-09 16:02:14 -0700466 }
Ray Milkey269ffb92014-04-03 14:43:30 -0700467 }
adminbc181552014-02-21 18:36:42 -0800468
Ray Milkey269ffb92014-04-03 14:43:30 -0700469 // Deliver the events
Pavlin Radoslavov4eaab992014-07-03 18:39:42 -0700470 long timestamp = System.nanoTime();
Jonathan Harte37e4e22014-05-13 19:12:02 -0700471 for (ITopologyListener listener : this.topologyListeners) {
Pavlin Radoslavov4eaab992014-07-03 18:39:42 -0700472 TopologyEvents events =
473 new TopologyEvents(timestamp,
474 kryo.copy(apiAddedSwitchEvents),
475 kryo.copy(apiRemovedSwitchEvents),
476 kryo.copy(apiAddedPortEvents),
477 kryo.copy(apiRemovedPortEvents),
478 kryo.copy(apiAddedLinkEvents),
479 kryo.copy(apiRemovedLinkEvents),
Yuta HIGUCHIbfc77f02014-07-14 22:50:25 -0700480 kryo.copy(apiAddedHostEvents),
481 kryo.copy(apiRemovedHostEvents));
Pavlin Radoslavov4eaab992014-07-03 18:39:42 -0700482 listener.topologyEvents(events);
Ray Milkey269ffb92014-04-03 14:43:30 -0700483 }
Pavlin Radoslavov74986ce2014-02-20 13:17:20 -0800484
Ray Milkey269ffb92014-04-03 14:43:30 -0700485 //
486 // Cleanup
487 //
488 apiAddedSwitchEvents.clear();
489 apiRemovedSwitchEvents.clear();
490 apiAddedPortEvents.clear();
491 apiRemovedPortEvents.clear();
492 apiAddedLinkEvents.clear();
493 apiRemovedLinkEvents.clear();
Yuta HIGUCHIbfc77f02014-07-14 22:50:25 -0700494 apiAddedHostEvents.clear();
495 apiRemovedHostEvents.clear();
Pavlin Radoslavov74986ce2014-02-20 13:17:20 -0800496 }
497
498 /**
499 * Apply reordered events.
500 *
501 * @param hasAddedSwitchEvents true if there were Added Switch Events.
Ray Milkey269ffb92014-04-03 14:43:30 -0700502 * @param hasAddedPortEvents true if there were Added Port Events.
Pavlin Radoslavov74986ce2014-02-20 13:17:20 -0800503 */
Yuta HIGUCHIbc67a052014-06-30 10:37:09 -0700504 @GuardedBy("topology.writeLock")
Pavlin Radoslavov74986ce2014-02-20 13:17:20 -0800505 private void applyReorderedEvents(boolean hasAddedSwitchEvents,
Ray Milkey269ffb92014-04-03 14:43:30 -0700506 boolean hasAddedPortEvents) {
Ray Milkeyb29e6262014-04-09 16:02:14 -0700507 if (!(hasAddedSwitchEvents || hasAddedPortEvents)) {
Ray Milkey269ffb92014-04-03 14:43:30 -0700508 return; // Nothing to do
Ray Milkeyb29e6262014-04-09 16:02:14 -0700509 }
Pavlin Radoslavov74986ce2014-02-20 13:17:20 -0800510
Ray Milkey269ffb92014-04-03 14:43:30 -0700511 //
512 // Try to apply the reordered events.
513 //
514 // NOTE: For simplicity we try to apply all events of a particular
515 // type if any "parent" type event was processed:
516 // - Apply reordered Port Events if Switches were added
Yuta HIGUCHIbfc77f02014-07-14 22:50:25 -0700517 // - Apply reordered Link and Host Events if Switches or Ports
Ray Milkey269ffb92014-04-03 14:43:30 -0700518 // were added
519 //
adminbc181552014-02-21 18:36:42 -0800520
Ray Milkey269ffb92014-04-03 14:43:30 -0700521 //
522 // Apply reordered Port Events if Switches were added
523 //
524 if (hasAddedSwitchEvents) {
525 Map<ByteBuffer, PortEvent> portEvents = reorderedAddedPortEvents;
526 reorderedAddedPortEvents = new HashMap<>();
Ray Milkeyb29e6262014-04-09 16:02:14 -0700527 for (PortEvent portEvent : portEvents.values()) {
Ray Milkey269ffb92014-04-03 14:43:30 -0700528 addPort(portEvent);
Ray Milkeyb29e6262014-04-09 16:02:14 -0700529 }
Ray Milkey269ffb92014-04-03 14:43:30 -0700530 }
531 //
Yuta HIGUCHIbfc77f02014-07-14 22:50:25 -0700532 // Apply reordered Link and Host Events if Switches or Ports
Ray Milkey269ffb92014-04-03 14:43:30 -0700533 // were added.
534 //
535 Map<ByteBuffer, LinkEvent> linkEvents = reorderedAddedLinkEvents;
536 reorderedAddedLinkEvents = new HashMap<>();
Ray Milkeyb29e6262014-04-09 16:02:14 -0700537 for (LinkEvent linkEvent : linkEvents.values()) {
Ray Milkey269ffb92014-04-03 14:43:30 -0700538 addLink(linkEvent);
Ray Milkeyb29e6262014-04-09 16:02:14 -0700539 }
Ray Milkey269ffb92014-04-03 14:43:30 -0700540 //
Yuta HIGUCHIbfc77f02014-07-14 22:50:25 -0700541 Map<ByteBuffer, HostEvent> hostEvents = reorderedAddedHostEvents;
542 reorderedAddedHostEvents = new HashMap<>();
543 for (HostEvent hostEvent : hostEvents.values()) {
544 addHost(hostEvent);
Ray Milkeyb29e6262014-04-09 16:02:14 -0700545 }
Pavlin Radoslavov74986ce2014-02-20 13:17:20 -0800546 }
547
Pavlin Radoslavov734ff5a2014-02-26 10:20:43 -0800548 /**
549 * Switch discovered event.
550 *
551 * @param switchEvent the switch event.
Ray Milkey269ffb92014-04-03 14:43:30 -0700552 * @param portEvents the corresponding port events for the switch.
Pavlin Radoslavov734ff5a2014-02-26 10:20:43 -0800553 */
Pavlin Radoslavovc1cfde52014-02-19 11:35:29 -0800554 @Override
Pavlin Radoslavov018d5332014-02-19 23:08:35 -0800555 public void putSwitchDiscoveryEvent(SwitchEvent switchEvent,
Ray Milkey269ffb92014-04-03 14:43:30 -0700556 Collection<PortEvent> portEvents) {
557 if (datastore.addSwitch(switchEvent, portEvents)) {
Jonathan Hart92c819f2014-05-30 10:53:30 -0700558 log.debug("Sending add switch: {}", switchEvent);
Ray Milkey269ffb92014-04-03 14:43:30 -0700559 // Send out notification
560 TopologyEvent topologyEvent = new TopologyEvent(switchEvent);
561 eventChannel.addEntry(topologyEvent.getID(), topologyEvent);
Pavlin Radoslavov26d83402014-02-20 15:24:30 -0800562
Ray Milkey269ffb92014-04-03 14:43:30 -0700563 // Send out notification for each port
564 for (PortEvent portEvent : portEvents) {
Jonathan Hart92c819f2014-05-30 10:53:30 -0700565 log.debug("Sending add port: {}", portEvent);
Ray Milkey269ffb92014-04-03 14:43:30 -0700566 topologyEvent = new TopologyEvent(portEvent);
567 eventChannel.addEntry(topologyEvent.getID(), topologyEvent);
568 }
Pavlin Radoslavov26d83402014-02-20 15:24:30 -0800569
Ray Milkey269ffb92014-04-03 14:43:30 -0700570 //
571 // Keep track of the added ports
572 //
573 // Get the old Port Events
574 Map<ByteBuffer, PortEvent> oldPortEvents =
575 discoveredAddedPortEvents.get(switchEvent.getDpid());
Ray Milkeyb29e6262014-04-09 16:02:14 -0700576 if (oldPortEvents == null) {
Ray Milkey269ffb92014-04-03 14:43:30 -0700577 oldPortEvents = new HashMap<>();
Ray Milkeyb29e6262014-04-09 16:02:14 -0700578 }
Pavlin Radoslavov26d83402014-02-20 15:24:30 -0800579
Ray Milkey269ffb92014-04-03 14:43:30 -0700580 // Store the new Port Events in the local cache
581 Map<ByteBuffer, PortEvent> newPortEvents = new HashMap<>();
582 for (PortEvent portEvent : portEvents) {
583 ByteBuffer id = portEvent.getIDasByteBuffer();
584 newPortEvents.put(id, portEvent);
585 }
586 discoveredAddedPortEvents.put(switchEvent.getDpid(),
587 newPortEvents);
Pavlin Radoslavov26d83402014-02-20 15:24:30 -0800588
Ray Milkey269ffb92014-04-03 14:43:30 -0700589 //
590 // Extract the removed ports
591 //
592 List<PortEvent> removedPortEvents = new LinkedList<>();
593 for (Map.Entry<ByteBuffer, PortEvent> entry : oldPortEvents.entrySet()) {
594 ByteBuffer key = entry.getKey();
595 PortEvent portEvent = entry.getValue();
Ray Milkeyb29e6262014-04-09 16:02:14 -0700596 if (!newPortEvents.containsKey(key)) {
Ray Milkey269ffb92014-04-03 14:43:30 -0700597 removedPortEvents.add(portEvent);
Ray Milkeyb29e6262014-04-09 16:02:14 -0700598 }
Ray Milkey269ffb92014-04-03 14:43:30 -0700599 }
600
601 // Cleanup old removed ports
Ray Milkeyb29e6262014-04-09 16:02:14 -0700602 for (PortEvent portEvent : removedPortEvents) {
Ray Milkey269ffb92014-04-03 14:43:30 -0700603 removePortDiscoveryEvent(portEvent);
Ray Milkeyb29e6262014-04-09 16:02:14 -0700604 }
Ray Milkey269ffb92014-04-03 14:43:30 -0700605 }
Pavlin Radoslavovc1cfde52014-02-19 11:35:29 -0800606 }
607
Pavlin Radoslavov734ff5a2014-02-26 10:20:43 -0800608 /**
Yuta HIGUCHIbc67a052014-06-30 10:37:09 -0700609 * {@inheritDoc}
610 * <p/>
611 * Called by {@link TopologyPublisher.SwitchCleanup} thread.
Pavlin Radoslavov734ff5a2014-02-26 10:20:43 -0800612 */
Pavlin Radoslavovc1cfde52014-02-19 11:35:29 -0800613 @Override
Pavlin Radoslavov6ea84a42014-02-19 15:50:01 -0800614 public void removeSwitchDiscoveryEvent(SwitchEvent switchEvent) {
Ray Milkey269ffb92014-04-03 14:43:30 -0700615 // Get the old Port Events
616 Map<ByteBuffer, PortEvent> oldPortEvents =
617 discoveredAddedPortEvents.get(switchEvent.getDpid());
Ray Milkeyb29e6262014-04-09 16:02:14 -0700618 if (oldPortEvents == null) {
Ray Milkey269ffb92014-04-03 14:43:30 -0700619 oldPortEvents = new HashMap<>();
Ray Milkeyb29e6262014-04-09 16:02:14 -0700620 }
Pavlin Radoslavov018d5332014-02-19 23:08:35 -0800621
Ray Milkey269ffb92014-04-03 14:43:30 -0700622 if (datastore.deactivateSwitch(switchEvent, oldPortEvents.values())) {
Jonathan Hart92c819f2014-05-30 10:53:30 -0700623 log.debug("Sending remove switch: {}", switchEvent);
Ray Milkey269ffb92014-04-03 14:43:30 -0700624 // Send out notification
625 eventChannel.removeEntry(switchEvent.getID());
Pavlin Radoslavov018d5332014-02-19 23:08:35 -0800626
Ray Milkey269ffb92014-04-03 14:43:30 -0700627 //
628 // Send out notification for each port.
629 //
630 // NOTE: We don't use removePortDiscoveryEvent() for the cleanup,
631 // because it will attempt to remove the port from the database,
632 // and the deactiveSwitch() call above already removed all ports.
633 //
Ray Milkeyb29e6262014-04-09 16:02:14 -0700634 for (PortEvent portEvent : oldPortEvents.values()) {
Jonathan Hart92c819f2014-05-30 10:53:30 -0700635 log.debug("Sending remove port:", portEvent);
Ray Milkey269ffb92014-04-03 14:43:30 -0700636 eventChannel.removeEntry(portEvent.getID());
Ray Milkeyb29e6262014-04-09 16:02:14 -0700637 }
Ray Milkey269ffb92014-04-03 14:43:30 -0700638 discoveredAddedPortEvents.remove(switchEvent.getDpid());
Pavlin Radoslavov26d83402014-02-20 15:24:30 -0800639
Ray Milkey269ffb92014-04-03 14:43:30 -0700640 // Cleanup for each link
641 Map<ByteBuffer, LinkEvent> oldLinkEvents =
642 discoveredAddedLinkEvents.get(switchEvent.getDpid());
643 if (oldLinkEvents != null) {
644 for (LinkEvent linkEvent : new ArrayList<>(oldLinkEvents.values())) {
645 removeLinkDiscoveryEvent(linkEvent);
646 }
647 discoveredAddedLinkEvents.remove(switchEvent.getDpid());
648 }
Pavlin Radoslavov26d83402014-02-20 15:24:30 -0800649
Yuta HIGUCHIbfc77f02014-07-14 22:50:25 -0700650 // Cleanup for each host
651 Map<ByteBuffer, HostEvent> oldHostEvents =
652 discoveredAddedHostEvents.get(switchEvent.getDpid());
653 if (oldHostEvents != null) {
654 for (HostEvent hostEvent : new ArrayList<>(oldHostEvents.values())) {
655 removeHostDiscoveryEvent(hostEvent);
Ray Milkey269ffb92014-04-03 14:43:30 -0700656 }
Yuta HIGUCHIbfc77f02014-07-14 22:50:25 -0700657 discoveredAddedHostEvents.remove(switchEvent.getDpid());
Ray Milkey269ffb92014-04-03 14:43:30 -0700658 }
659 }
Pavlin Radoslavovc1cfde52014-02-19 11:35:29 -0800660 }
661
Pavlin Radoslavov734ff5a2014-02-26 10:20:43 -0800662 /**
663 * Port discovered event.
664 *
665 * @param portEvent the port event.
666 */
Pavlin Radoslavovc1cfde52014-02-19 11:35:29 -0800667 @Override
Pavlin Radoslavov6ea84a42014-02-19 15:50:01 -0800668 public void putPortDiscoveryEvent(PortEvent portEvent) {
Ray Milkey269ffb92014-04-03 14:43:30 -0700669 if (datastore.addPort(portEvent)) {
Jonathan Hart92c819f2014-05-30 10:53:30 -0700670 log.debug("Sending add port: {}", portEvent);
Ray Milkey269ffb92014-04-03 14:43:30 -0700671 // Send out notification
672 TopologyEvent topologyEvent = new TopologyEvent(portEvent);
673 eventChannel.addEntry(topologyEvent.getID(), topologyEvent);
Pavlin Radoslavov26d83402014-02-20 15:24:30 -0800674
Ray Milkey269ffb92014-04-03 14:43:30 -0700675 // Store the new Port Event in the local cache
676 Map<ByteBuffer, PortEvent> oldPortEvents =
677 discoveredAddedPortEvents.get(portEvent.getDpid());
678 if (oldPortEvents == null) {
679 oldPortEvents = new HashMap<>();
680 discoveredAddedPortEvents.put(portEvent.getDpid(),
681 oldPortEvents);
682 }
683 ByteBuffer id = portEvent.getIDasByteBuffer();
684 oldPortEvents.put(id, portEvent);
685 }
Pavlin Radoslavovc1cfde52014-02-19 11:35:29 -0800686 }
687
Pavlin Radoslavov734ff5a2014-02-26 10:20:43 -0800688 /**
689 * Port removed event.
690 *
691 * @param portEvent the port event.
692 */
Pavlin Radoslavovc1cfde52014-02-19 11:35:29 -0800693 @Override
Pavlin Radoslavov6ea84a42014-02-19 15:50:01 -0800694 public void removePortDiscoveryEvent(PortEvent portEvent) {
Ray Milkey269ffb92014-04-03 14:43:30 -0700695 if (datastore.deactivatePort(portEvent)) {
Jonathan Hart92c819f2014-05-30 10:53:30 -0700696 log.debug("Sending remove port: {}", portEvent);
Ray Milkey269ffb92014-04-03 14:43:30 -0700697 // Send out notification
698 eventChannel.removeEntry(portEvent.getID());
Pavlin Radoslavov26d83402014-02-20 15:24:30 -0800699
Ray Milkey269ffb92014-04-03 14:43:30 -0700700 // Cleanup the Port Event from the local cache
701 Map<ByteBuffer, PortEvent> oldPortEvents =
702 discoveredAddedPortEvents.get(portEvent.getDpid());
703 if (oldPortEvents != null) {
704 ByteBuffer id = portEvent.getIDasByteBuffer();
705 oldPortEvents.remove(id);
706 }
Pavlin Radoslavov26d83402014-02-20 15:24:30 -0800707
Ray Milkey269ffb92014-04-03 14:43:30 -0700708 // Cleanup for the incoming link
709 Map<ByteBuffer, LinkEvent> oldLinkEvents =
710 discoveredAddedLinkEvents.get(portEvent.getDpid());
711 if (oldLinkEvents != null) {
712 for (LinkEvent linkEvent : new ArrayList<>(oldLinkEvents.values())) {
Yuta HIGUCHIbf0a8712014-06-30 18:59:46 -0700713 if (linkEvent.getDst().equals(portEvent.getSwitchPort())) {
Ray Milkey269ffb92014-04-03 14:43:30 -0700714 removeLinkDiscoveryEvent(linkEvent);
715 // XXX If we change our model to allow multiple Link on
716 // a Port, this loop must be fixed to allow continuing.
717 break;
718 }
719 }
720 }
Pavlin Radoslavov26d83402014-02-20 15:24:30 -0800721
Yuta HIGUCHIbfc77f02014-07-14 22:50:25 -0700722 // Cleanup for the connected hosts
Ray Milkey269ffb92014-04-03 14:43:30 -0700723 // TODO: The implementation below is probably wrong
Yuta HIGUCHIbfc77f02014-07-14 22:50:25 -0700724 List<HostEvent> removedHostEvents = new LinkedList<>();
725 Map<ByteBuffer, HostEvent> oldHostEvents =
726 discoveredAddedHostEvents.get(portEvent.getDpid());
727 if (oldHostEvents != null) {
728 for (HostEvent hostEvent : new ArrayList<>(oldHostEvents.values())) {
729 for (SwitchPort swp : hostEvent.getAttachmentPoints()) {
Yuta HIGUCHIbf0a8712014-06-30 18:59:46 -0700730 if (swp.equals(portEvent.getSwitchPort())) {
Yuta HIGUCHIbfc77f02014-07-14 22:50:25 -0700731 removedHostEvents.add(hostEvent);
Ray Milkey269ffb92014-04-03 14:43:30 -0700732 }
733 }
734 }
Yuta HIGUCHIbfc77f02014-07-14 22:50:25 -0700735 for (HostEvent hostEvent : removedHostEvents) {
736 removeHostDiscoveryEvent(hostEvent);
Ray Milkeyb29e6262014-04-09 16:02:14 -0700737 }
Ray Milkey269ffb92014-04-03 14:43:30 -0700738 }
739 }
Pavlin Radoslavovc1cfde52014-02-19 11:35:29 -0800740 }
741
Pavlin Radoslavov734ff5a2014-02-26 10:20:43 -0800742 /**
743 * Link discovered event.
744 *
745 * @param linkEvent the link event.
746 */
Pavlin Radoslavovc1cfde52014-02-19 11:35:29 -0800747 @Override
Pavlin Radoslavov6ea84a42014-02-19 15:50:01 -0800748 public void putLinkDiscoveryEvent(LinkEvent linkEvent) {
Ray Milkey269ffb92014-04-03 14:43:30 -0700749 if (datastore.addLink(linkEvent)) {
Jonathan Hart92c819f2014-05-30 10:53:30 -0700750 log.debug("Sending add link: {}", linkEvent);
Ray Milkey269ffb92014-04-03 14:43:30 -0700751 // Send out notification
752 TopologyEvent topologyEvent = new TopologyEvent(linkEvent);
753 eventChannel.addEntry(topologyEvent.getID(), topologyEvent);
Pavlin Radoslavov26d83402014-02-20 15:24:30 -0800754
Ray Milkey269ffb92014-04-03 14:43:30 -0700755 // Store the new Link Event in the local cache
756 Map<ByteBuffer, LinkEvent> oldLinkEvents =
757 discoveredAddedLinkEvents.get(linkEvent.getDst().getDpid());
758 if (oldLinkEvents == null) {
759 oldLinkEvents = new HashMap<>();
760 discoveredAddedLinkEvents.put(linkEvent.getDst().getDpid(),
761 oldLinkEvents);
762 }
763 ByteBuffer id = linkEvent.getIDasByteBuffer();
764 oldLinkEvents.put(id, linkEvent);
765 }
Pavlin Radoslavovc1cfde52014-02-19 11:35:29 -0800766 }
767
Pavlin Radoslavov734ff5a2014-02-26 10:20:43 -0800768 /**
769 * Link removed event.
770 *
771 * @param linkEvent the link event.
772 */
Pavlin Radoslavovc1cfde52014-02-19 11:35:29 -0800773 @Override
Pavlin Radoslavov6ea84a42014-02-19 15:50:01 -0800774 public void removeLinkDiscoveryEvent(LinkEvent linkEvent) {
Ray Milkey269ffb92014-04-03 14:43:30 -0700775 if (datastore.removeLink(linkEvent)) {
Jonathan Hart92c819f2014-05-30 10:53:30 -0700776 log.debug("Sending remove link: {}", linkEvent);
Ray Milkey269ffb92014-04-03 14:43:30 -0700777 // Send out notification
778 eventChannel.removeEntry(linkEvent.getID());
Pavlin Radoslavov26d83402014-02-20 15:24:30 -0800779
Ray Milkey269ffb92014-04-03 14:43:30 -0700780 // Cleanup the Link Event from the local cache
781 Map<ByteBuffer, LinkEvent> oldLinkEvents =
782 discoveredAddedLinkEvents.get(linkEvent.getDst().getDpid());
783 if (oldLinkEvents != null) {
784 ByteBuffer id = linkEvent.getIDasByteBuffer();
785 oldLinkEvents.remove(id);
786 }
787 }
Pavlin Radoslavovc1cfde52014-02-19 11:35:29 -0800788 }
Jonathan Hart22eb9882014-02-11 15:52:59 -0800789
Pavlin Radoslavov734ff5a2014-02-26 10:20:43 -0800790 /**
Yuta HIGUCHIbfc77f02014-07-14 22:50:25 -0700791 * Host discovered event.
Pavlin Radoslavov734ff5a2014-02-26 10:20:43 -0800792 *
Yuta HIGUCHIbfc77f02014-07-14 22:50:25 -0700793 * @param hostEvent the host event.
Pavlin Radoslavov734ff5a2014-02-26 10:20:43 -0800794 */
Pavlin Radoslavovc1cfde52014-02-19 11:35:29 -0800795 @Override
Yuta HIGUCHIbfc77f02014-07-14 22:50:25 -0700796 public void putHostDiscoveryEvent(HostEvent hostEvent) {
797 if (datastore.addHost(hostEvent)) {
Ray Milkey269ffb92014-04-03 14:43:30 -0700798 // Send out notification
Yuta HIGUCHIbfc77f02014-07-14 22:50:25 -0700799 TopologyEvent topologyEvent = new TopologyEvent(hostEvent);
Ray Milkey269ffb92014-04-03 14:43:30 -0700800 eventChannel.addEntry(topologyEvent.getID(), topologyEvent);
Yuta HIGUCHIbfc77f02014-07-14 22:50:25 -0700801 log.debug("Put the host info into the cache of the topology. mac {}", hostEvent.getMac());
Ray Milkey269ffb92014-04-03 14:43:30 -0700802
Yuta HIGUCHIbfc77f02014-07-14 22:50:25 -0700803 // Store the new Host Event in the local cache
Ray Milkey269ffb92014-04-03 14:43:30 -0700804 // TODO: The implementation below is probably wrong
Yuta HIGUCHIbfc77f02014-07-14 22:50:25 -0700805 for (SwitchPort swp : hostEvent.getAttachmentPoints()) {
806 Map<ByteBuffer, HostEvent> oldHostEvents =
807 discoveredAddedHostEvents.get(swp.getDpid());
808 if (oldHostEvents == null) {
809 oldHostEvents = new HashMap<>();
810 discoveredAddedHostEvents.put(swp.getDpid(),
811 oldHostEvents);
Ray Milkey269ffb92014-04-03 14:43:30 -0700812 }
Yuta HIGUCHIbfc77f02014-07-14 22:50:25 -0700813 ByteBuffer id = hostEvent.getIDasByteBuffer();
814 oldHostEvents.put(id, hostEvent);
Ray Milkey269ffb92014-04-03 14:43:30 -0700815 }
816 }
Pavlin Radoslavovc1cfde52014-02-19 11:35:29 -0800817 }
Jonathan Hart22eb9882014-02-11 15:52:59 -0800818
Pavlin Radoslavov734ff5a2014-02-26 10:20:43 -0800819 /**
Yuta HIGUCHIbfc77f02014-07-14 22:50:25 -0700820 * Host removed event.
Pavlin Radoslavov734ff5a2014-02-26 10:20:43 -0800821 *
Yuta HIGUCHIbfc77f02014-07-14 22:50:25 -0700822 * @param hostEvent the host event.
Pavlin Radoslavov734ff5a2014-02-26 10:20:43 -0800823 */
Pavlin Radoslavovc1cfde52014-02-19 11:35:29 -0800824 @Override
Yuta HIGUCHIbfc77f02014-07-14 22:50:25 -0700825 public void removeHostDiscoveryEvent(HostEvent hostEvent) {
826 if (datastore.removeHost(hostEvent)) {
Ray Milkey269ffb92014-04-03 14:43:30 -0700827 // Send out notification
Yuta HIGUCHIbfc77f02014-07-14 22:50:25 -0700828 eventChannel.removeEntry(hostEvent.getID());
829 log.debug("Remove the host info into the cache of the topology. mac {}", hostEvent.getMac());
Pavlin Radoslavov26d83402014-02-20 15:24:30 -0800830
Yuta HIGUCHIbfc77f02014-07-14 22:50:25 -0700831 // Cleanup the Host Event from the local cache
Ray Milkey269ffb92014-04-03 14:43:30 -0700832 // TODO: The implementation below is probably wrong
Yuta HIGUCHIbfc77f02014-07-14 22:50:25 -0700833 ByteBuffer id = ByteBuffer.wrap(hostEvent.getID());
834 for (SwitchPort swp : hostEvent.getAttachmentPoints()) {
835 Map<ByteBuffer, HostEvent> oldHostEvents =
836 discoveredAddedHostEvents.get(swp.getDpid());
837 if (oldHostEvents != null) {
838 oldHostEvents.remove(id);
Ray Milkey269ffb92014-04-03 14:43:30 -0700839 }
840 }
841 }
Pavlin Radoslavovc1cfde52014-02-19 11:35:29 -0800842 }
Jonathan Hart22eb9882014-02-11 15:52:59 -0800843
Yuta HIGUCHI8b389a72014-07-18 13:50:00 -0700844 //
845 // Methods to update topology replica
846 //
847
Pavlin Radoslavov734ff5a2014-02-26 10:20:43 -0800848 /**
Yuta HIGUCHI7926ba32014-07-09 11:39:32 -0700849 * Adds a switch to the topology replica.
Pavlin Radoslavov734ff5a2014-02-26 10:20:43 -0800850 *
Yuta HIGUCHIbf0a8712014-06-30 18:59:46 -0700851 * @param switchEvent the SwitchEvent with the switch to add.
Pavlin Radoslavov734ff5a2014-02-26 10:20:43 -0800852 */
Yuta HIGUCHIbc67a052014-06-30 10:37:09 -0700853 @GuardedBy("topology.writeLock")
Pavlin Radoslavov74986ce2014-02-20 13:17:20 -0800854 private void addSwitch(SwitchEvent switchEvent) {
Yuta HIGUCHI8b389a72014-07-18 13:50:00 -0700855 if (log.isDebugEnabled()) {
856 SwitchEvent sw = topology.getSwitchEvent(switchEvent.getDpid());
857 if (sw != null) {
858 log.debug("Update {}", switchEvent);
859 } else {
860 log.debug("Added {}", switchEvent);
861 }
Ray Milkey269ffb92014-04-03 14:43:30 -0700862 }
Yuta HIGUCHI8b389a72014-07-18 13:50:00 -0700863 topology.putSwitch(switchEvent.freeze());
Ray Milkey269ffb92014-04-03 14:43:30 -0700864 apiAddedSwitchEvents.add(switchEvent);
Pavlin Radoslavov3c9cc552014-02-20 09:58:38 -0800865 }
866
Pavlin Radoslavov734ff5a2014-02-26 10:20:43 -0800867 /**
Yuta HIGUCHI7926ba32014-07-09 11:39:32 -0700868 * Removes a switch from the topology replica.
Yuta HIGUCHIbf0a8712014-06-30 18:59:46 -0700869 * <p/>
870 * It will call {@link #removePort(PortEvent)} for each ports on this switch.
Pavlin Radoslavov734ff5a2014-02-26 10:20:43 -0800871 *
Yuta HIGUCHIbf0a8712014-06-30 18:59:46 -0700872 * @param switchEvent the SwitchEvent with the switch to remove.
Pavlin Radoslavov734ff5a2014-02-26 10:20:43 -0800873 */
Yuta HIGUCHIbc67a052014-06-30 10:37:09 -0700874 @GuardedBy("topology.writeLock")
Pavlin Radoslavov74986ce2014-02-20 13:17:20 -0800875 private void removeSwitch(SwitchEvent switchEvent) {
Yuta HIGUCHI8b389a72014-07-18 13:50:00 -0700876 final Dpid dpid = switchEvent.getDpid();
877
878 SwitchEvent swInTopo = topology.getSwitchEvent(dpid);
879 if (swInTopo == null) {
Ray Milkey269ffb92014-04-03 14:43:30 -0700880 log.warn("Switch {} already removed, ignoring", switchEvent);
881 return;
882 }
Pavlin Radoslavov3c9cc552014-02-20 09:58:38 -0800883
Ray Milkey269ffb92014-04-03 14:43:30 -0700884 //
885 // Remove all Ports on the Switch
886 //
887 ArrayList<PortEvent> portsToRemove = new ArrayList<>();
Yuta HIGUCHI8b389a72014-07-18 13:50:00 -0700888 for (Port port : topology.getPorts(dpid)) {
Ray Milkey269ffb92014-04-03 14:43:30 -0700889 log.warn("Port {} on Switch {} should be removed prior to removing Switch. Removing Port now.",
890 port, switchEvent);
Yuta HIGUCHI8b389a72014-07-18 13:50:00 -0700891 PortEvent portEvent = new PortEvent(port.asSwitchPort());
Ray Milkey269ffb92014-04-03 14:43:30 -0700892 portsToRemove.add(portEvent);
893 }
Ray Milkeyb29e6262014-04-09 16:02:14 -0700894 for (PortEvent portEvent : portsToRemove) {
Ray Milkey269ffb92014-04-03 14:43:30 -0700895 removePort(portEvent);
Ray Milkeyb29e6262014-04-09 16:02:14 -0700896 }
Pavlin Radoslavov3c9cc552014-02-20 09:58:38 -0800897
Yuta HIGUCHI8b389a72014-07-18 13:50:00 -0700898 log.debug("Removed {}", swInTopo);
899 topology.removeSwitch(dpid);
900 apiRemovedSwitchEvents.add(swInTopo);
Pavlin Radoslavov3c9cc552014-02-20 09:58:38 -0800901 }
902
Pavlin Radoslavov734ff5a2014-02-26 10:20:43 -0800903 /**
Yuta HIGUCHI7926ba32014-07-09 11:39:32 -0700904 * Adds a port to the topology replica.
Pavlin Radoslavov734ff5a2014-02-26 10:20:43 -0800905 *
Yuta HIGUCHIbf0a8712014-06-30 18:59:46 -0700906 * @param portEvent the PortEvent with the port to add.
Pavlin Radoslavov734ff5a2014-02-26 10:20:43 -0800907 */
Yuta HIGUCHIbc67a052014-06-30 10:37:09 -0700908 @GuardedBy("topology.writeLock")
Pavlin Radoslavov3c9cc552014-02-20 09:58:38 -0800909 private void addPort(PortEvent portEvent) {
Jonathan Harte37e4e22014-05-13 19:12:02 -0700910 Switch sw = topology.getSwitch(portEvent.getDpid());
Ray Milkey269ffb92014-04-03 14:43:30 -0700911 if (sw == null) {
Jonathan Hartf1675202014-05-23 14:59:07 -0700912 log.debug("{} reordered because switch is null", portEvent);
Ray Milkey269ffb92014-04-03 14:43:30 -0700913 // Reordered event: delay the event in local cache
914 ByteBuffer id = portEvent.getIDasByteBuffer();
915 reorderedAddedPortEvents.put(id, portEvent);
916 return;
917 }
Pavlin Radoslavov3c9cc552014-02-20 09:58:38 -0800918
Yuta HIGUCHI8b389a72014-07-18 13:50:00 -0700919 if (log.isDebugEnabled()) {
920 PortEvent port = topology.getPortEvent(portEvent.getSwitchPort());
921 if (port != null) {
922 log.debug("Update {}", portEvent);
923 } else {
924 log.debug("Added {}", portEvent);
925 }
Ray Milkey269ffb92014-04-03 14:43:30 -0700926 }
Yuta HIGUCHI8b389a72014-07-18 13:50:00 -0700927 topology.putPort(portEvent.freeze());
Ray Milkey269ffb92014-04-03 14:43:30 -0700928 apiAddedPortEvents.add(portEvent);
Pavlin Radoslavov3c9cc552014-02-20 09:58:38 -0800929 }
930
Pavlin Radoslavov734ff5a2014-02-26 10:20:43 -0800931 /**
Yuta HIGUCHI7926ba32014-07-09 11:39:32 -0700932 * Removes a port from the topology replica.
Yuta HIGUCHIbf0a8712014-06-30 18:59:46 -0700933 * <p/>
Yuta HIGUCHI8b389a72014-07-18 13:50:00 -0700934 * It will remove attachment points from each hosts on this port
Yuta HIGUCHIbf0a8712014-06-30 18:59:46 -0700935 * and call {@link #removeLink(LinkEvent)} for each links on this port.
Pavlin Radoslavov734ff5a2014-02-26 10:20:43 -0800936 *
Yuta HIGUCHIbf0a8712014-06-30 18:59:46 -0700937 * @param portEvent the PortEvent with the port to remove.
Pavlin Radoslavov734ff5a2014-02-26 10:20:43 -0800938 */
Yuta HIGUCHIbc67a052014-06-30 10:37:09 -0700939 @GuardedBy("topology.writeLock")
Pavlin Radoslavov3c9cc552014-02-20 09:58:38 -0800940 private void removePort(PortEvent portEvent) {
Yuta HIGUCHI8b389a72014-07-18 13:50:00 -0700941 SwitchEvent sw = topology.getSwitchEvent(portEvent.getDpid());
Ray Milkey269ffb92014-04-03 14:43:30 -0700942 if (sw == null) {
943 log.warn("Parent Switch for Port {} already removed, ignoring",
944 portEvent);
945 return;
946 }
Pavlin Radoslavov3c9cc552014-02-20 09:58:38 -0800947
Yuta HIGUCHI8b389a72014-07-18 13:50:00 -0700948 final SwitchPort switchPort = portEvent.getSwitchPort();
949 PortEvent portInTopo = topology.getPortEvent(switchPort);
950 if (portInTopo == null) {
Ray Milkey269ffb92014-04-03 14:43:30 -0700951 log.warn("Port {} already removed, ignoring", portEvent);
952 return;
953 }
Pavlin Radoslavov3c9cc552014-02-20 09:58:38 -0800954
Ray Milkey269ffb92014-04-03 14:43:30 -0700955 //
Yuta HIGUCHI8b389a72014-07-18 13:50:00 -0700956 // Remove all Host attachment points bound to this Port
Ray Milkey269ffb92014-04-03 14:43:30 -0700957 //
Yuta HIGUCHI8b389a72014-07-18 13:50:00 -0700958 List<HostEvent> hostsToUpdate = new ArrayList<>();
959 for (Host host : topology.getHosts(switchPort)) {
960 log.debug("Removing Host {} on Port {}", host, portInTopo);
961 HostEvent hostEvent = topology.getHostEvent(host.getMacAddress());
962 hostsToUpdate.add(hostEvent);
Ray Milkey269ffb92014-04-03 14:43:30 -0700963 }
Yuta HIGUCHI8b389a72014-07-18 13:50:00 -0700964 for (HostEvent hostEvent : hostsToUpdate) {
965 HostEvent newHostEvent = new HostEvent(hostEvent);
966 newHostEvent.removeAttachmentPoint(switchPort);
967 newHostEvent.freeze();
968
969 // TODO should this event be fired inside #addHost?
970 if (newHostEvent.getAttachmentPoints().isEmpty()) {
971 // No more attachment point left -> remove Host
972 removeHost(hostEvent);
973 } else {
974 // Update Host
975 addHost(newHostEvent);
976 }
Ray Milkeyb29e6262014-04-09 16:02:14 -0700977 }
Pavlin Radoslavov3c9cc552014-02-20 09:58:38 -0800978
Ray Milkey269ffb92014-04-03 14:43:30 -0700979 //
980 // Remove all Links connected to the Port
981 //
982 Set<Link> links = new HashSet<>();
Yuta HIGUCHI8b389a72014-07-18 13:50:00 -0700983 links.addAll(topology.getOutgoingLinks(switchPort));
984 links.addAll(topology.getIncomingLinks(switchPort));
Ray Milkey269ffb92014-04-03 14:43:30 -0700985 for (Link link : links) {
Ray Milkeyb29e6262014-04-09 16:02:14 -0700986 if (link == null) {
Ray Milkey269ffb92014-04-03 14:43:30 -0700987 continue;
Ray Milkeyb29e6262014-04-09 16:02:14 -0700988 }
Yuta HIGUCHI8b389a72014-07-18 13:50:00 -0700989 LinkEvent linkEvent = topology.getLinkEvent(link.getLinkTuple());
990 if (linkEvent != null) {
991 log.debug("Removing Link {} on Port {}", link, portInTopo);
992 removeLink(linkEvent);
993 }
Ray Milkeyb29e6262014-04-09 16:02:14 -0700994 }
Pavlin Radoslavov3c9cc552014-02-20 09:58:38 -0800995
Yuta HIGUCHI8b389a72014-07-18 13:50:00 -0700996 // Remove the Port from Topology
997 log.debug("Removed {}", portInTopo);
998 topology.removePort(switchPort);
Pavlin Radoslavov74986ce2014-02-20 13:17:20 -0800999
Yuta HIGUCHI8b389a72014-07-18 13:50:00 -07001000 apiRemovedPortEvents.add(portInTopo);
Pavlin Radoslavov3c9cc552014-02-20 09:58:38 -08001001 }
1002
Pavlin Radoslavov734ff5a2014-02-26 10:20:43 -08001003 /**
Yuta HIGUCHI7926ba32014-07-09 11:39:32 -07001004 * Adds a link to the topology replica.
Yuta HIGUCHIbf0a8712014-06-30 18:59:46 -07001005 * <p/>
Yuta HIGUCHI8b389a72014-07-18 13:50:00 -07001006 * It will remove attachment points from each hosts using the same ports.
Pavlin Radoslavov734ff5a2014-02-26 10:20:43 -08001007 *
Yuta HIGUCHIbf0a8712014-06-30 18:59:46 -07001008 * @param linkEvent the LinkEvent with the link to add.
Pavlin Radoslavov734ff5a2014-02-26 10:20:43 -08001009 */
Yuta HIGUCHIbc67a052014-06-30 10:37:09 -07001010 @GuardedBy("topology.writeLock")
Pavlin Radoslavov3c9cc552014-02-20 09:58:38 -08001011 private void addLink(LinkEvent linkEvent) {
Yuta HIGUCHI8b389a72014-07-18 13:50:00 -07001012 PortEvent srcPort = topology.getPortEvent(linkEvent.getSrc());
1013 PortEvent dstPort = topology.getPortEvent(linkEvent.getDst());
Ray Milkey269ffb92014-04-03 14:43:30 -07001014 if ((srcPort == null) || (dstPort == null)) {
Jonathan Hartf1675202014-05-23 14:59:07 -07001015 log.debug("{} reordered because {} port is null", linkEvent,
1016 (srcPort == null) ? "src" : "dst");
1017
Yuta HIGUCHIbf0a8712014-06-30 18:59:46 -07001018 // XXX domain knowledge: port must be present before link.
Ray Milkey269ffb92014-04-03 14:43:30 -07001019 // Reordered event: delay the event in local cache
1020 ByteBuffer id = linkEvent.getIDasByteBuffer();
1021 reorderedAddedLinkEvents.put(id, linkEvent);
1022 return;
1023 }
Pavlin Radoslavov3c9cc552014-02-20 09:58:38 -08001024
Yuta HIGUCHI8b389a72014-07-18 13:50:00 -07001025 // XXX domain knowledge: Sanity check: Port cannot have both Link and Host
Yuta HIGUCHIbf0a8712014-06-30 18:59:46 -07001026 // FIXME potentially local replica may not be up-to-date yet due to HZ delay.
1027 // may need to manage local truth and use them instead.
Yuta HIGUCHI8b389a72014-07-18 13:50:00 -07001028 if (topology.getLinkEvent(linkEvent.getLinkTuple()) == null) {
1029 // Only check for existing Host when adding new Link.
Pavlin Radoslavov3c9cc552014-02-20 09:58:38 -08001030
Yuta HIGUCHI8b389a72014-07-18 13:50:00 -07001031 // Remove all Hosts attached to the ports on both ends
1032
1033 Set<HostEvent> hostsToUpdate = new TreeSet<>(new Comparator<HostEvent>() {
1034 // comparison only using ID(=MAC)
1035 @Override
1036 public int compare(HostEvent o1, HostEvent o2) {
1037 return Long.compare(o1.getMac().toLong(), o2.getMac().toLong());
1038 }
1039 });
1040
1041 List<SwitchPort> portsToCheck = Arrays.asList(
1042 srcPort.getSwitchPort(),
1043 dstPort.getSwitchPort());
1044
1045 // Enumerate Host which needs to be updated by this Link add event
1046 for (SwitchPort port : portsToCheck) {
1047 for (Host host : topology.getHosts(port)) {
Yuta HIGUCHIbfc77f02014-07-14 22:50:25 -07001048 log.error("Host {} on Port {} should have been removed prior to adding Link {}",
1049 host, port, linkEvent);
Yuta HIGUCHI8b389a72014-07-18 13:50:00 -07001050
1051 HostEvent hostEvent = topology.getHostEvent(host.getMacAddress());
1052 hostsToUpdate.add(hostEvent);
Ray Milkey269ffb92014-04-03 14:43:30 -07001053 }
1054 }
Yuta HIGUCHI8b389a72014-07-18 13:50:00 -07001055 // remove attachment point from them.
1056 for (HostEvent hostEvent : hostsToUpdate) {
1057 // remove port from attachment point and update
1058 HostEvent newHostEvent = new HostEvent(hostEvent);
1059 newHostEvent.removeAttachmentPoint(srcPort.getSwitchPort());
1060 newHostEvent.removeAttachmentPoint(dstPort.getSwitchPort());
1061 newHostEvent.freeze();
1062
1063 // TODO should this event be fired inside #addHost?
1064 if (newHostEvent.getAttachmentPoints().isEmpty()) {
1065 // No more attachment point left -> remove Host
1066 removeHost(hostEvent);
1067 } else {
1068 // Update Host
1069 addHost(newHostEvent);
1070 }
Ray Milkeyb29e6262014-04-09 16:02:14 -07001071 }
Ray Milkey269ffb92014-04-03 14:43:30 -07001072 }
Pavlin Radoslavov74986ce2014-02-20 13:17:20 -08001073
Yuta HIGUCHI8b389a72014-07-18 13:50:00 -07001074 if (log.isDebugEnabled()) {
1075 LinkEvent link = topology.getLinkEvent(linkEvent.getLinkTuple());
1076 if (link != null) {
1077 log.debug("Update {}", linkEvent);
1078 } else {
1079 log.debug("Added {}", linkEvent);
1080 }
1081 }
1082 topology.putLink(linkEvent.freeze());
Ray Milkey269ffb92014-04-03 14:43:30 -07001083 apiAddedLinkEvents.add(linkEvent);
Pavlin Radoslavov3c9cc552014-02-20 09:58:38 -08001084 }
1085
Pavlin Radoslavov734ff5a2014-02-26 10:20:43 -08001086 /**
Yuta HIGUCHI7926ba32014-07-09 11:39:32 -07001087 * Removes a link from the topology replica.
Pavlin Radoslavov734ff5a2014-02-26 10:20:43 -08001088 *
Yuta HIGUCHIbf0a8712014-06-30 18:59:46 -07001089 * @param linkEvent the LinkEvent with the link to remove.
Pavlin Radoslavov734ff5a2014-02-26 10:20:43 -08001090 */
Yuta HIGUCHIbc67a052014-06-30 10:37:09 -07001091 @GuardedBy("topology.writeLock")
Pavlin Radoslavov3c9cc552014-02-20 09:58:38 -08001092 private void removeLink(LinkEvent linkEvent) {
Yuta HIGUCHI8f3dfa32014-06-25 00:14:25 -07001093 Port srcPort = topology.getPort(linkEvent.getSrc().getDpid(),
Yuta HIGUCHIb1e2ab72014-06-30 11:01:31 -07001094 linkEvent.getSrc().getPortNumber());
Ray Milkey269ffb92014-04-03 14:43:30 -07001095 if (srcPort == null) {
1096 log.warn("Src Port for Link {} already removed, ignoring",
1097 linkEvent);
1098 return;
1099 }
Pavlin Radoslavov3c9cc552014-02-20 09:58:38 -08001100
Yuta HIGUCHI8f3dfa32014-06-25 00:14:25 -07001101 Port dstPort = topology.getPort(linkEvent.getDst().getDpid(),
Yuta HIGUCHIb1e2ab72014-06-30 11:01:31 -07001102 linkEvent.getDst().getPortNumber());
Ray Milkey269ffb92014-04-03 14:43:30 -07001103 if (dstPort == null) {
1104 log.warn("Dst Port for Link {} already removed, ignoring",
1105 linkEvent);
1106 return;
1107 }
Pavlin Radoslavov3c9cc552014-02-20 09:58:38 -08001108
Yuta HIGUCHI8b389a72014-07-18 13:50:00 -07001109 LinkEvent linkInTopo = topology.getLinkEvent(linkEvent.getLinkTuple(),
1110 linkEvent.getType());
1111 if (linkInTopo == null) {
1112 log.warn("Link {} already removed, ignoring", linkEvent);
1113 return;
Ray Milkey269ffb92014-04-03 14:43:30 -07001114 }
Jonathan Hart25bd53e2014-04-30 23:44:09 -07001115
Yuta HIGUCHI8b389a72014-07-18 13:50:00 -07001116 if (log.isDebugEnabled()) {
1117 // only do sanity check on debug level
1118
1119 Link linkIn = dstPort.getIncomingLink(linkEvent.getType());
1120 if (linkIn == null) {
1121 log.warn("Link {} already removed on destination Port", linkEvent);
1122 }
1123 Link linkOut = srcPort.getOutgoingLink(linkEvent.getType());
1124 if (linkOut == null) {
1125 log.warn("Link {} already removed on src Port", linkEvent);
1126 }
Jonathan Hart25bd53e2014-04-30 23:44:09 -07001127 }
Pavlin Radoslavov74986ce2014-02-20 13:17:20 -08001128
Yuta HIGUCHI8b389a72014-07-18 13:50:00 -07001129 log.debug("Removed {}", linkInTopo);
1130 topology.removeLink(linkEvent.getLinkTuple(), linkEvent.getType());
1131 apiRemovedLinkEvents.add(linkInTopo);
Pavlin Radoslavov3c9cc552014-02-20 09:58:38 -08001132 }
1133
Pavlin Radoslavov734ff5a2014-02-26 10:20:43 -08001134 /**
Yuta HIGUCHIbfc77f02014-07-14 22:50:25 -07001135 * Adds a host to the topology replica.
Ray Milkey269ffb92014-04-03 14:43:30 -07001136 * <p/>
Yuta HIGUCHIbfc77f02014-07-14 22:50:25 -07001137 * TODO: Host-related work is incomplete.
Pavlin Radoslavov734ff5a2014-02-26 10:20:43 -08001138 * TODO: Eventually, we might need to consider reordering
Yuta HIGUCHI8b389a72014-07-18 13:50:00 -07001139 * or {@link #addLink(LinkEvent)} and {@link #addHost(HostEvent)} events on the same port.
Pavlin Radoslavov734ff5a2014-02-26 10:20:43 -08001140 *
Yuta HIGUCHIbfc77f02014-07-14 22:50:25 -07001141 * @param hostEvent the HostEvent with the host to add.
Pavlin Radoslavov734ff5a2014-02-26 10:20:43 -08001142 */
Yuta HIGUCHIbc67a052014-06-30 10:37:09 -07001143 @GuardedBy("topology.writeLock")
Yuta HIGUCHIbfc77f02014-07-14 22:50:25 -07001144 private void addHost(HostEvent hostEvent) {
Pavlin Radoslavov3c9cc552014-02-20 09:58:38 -08001145
Yuta HIGUCHI8b389a72014-07-18 13:50:00 -07001146 // TODO Decide how to handle update scenario.
1147 // If the new HostEvent has less attachment point compared to
1148 // existing HostEvent, what should the event be?
1149 // - AddHostEvent with some attachment point removed? (current behavior)
Pavlin Radoslavov3c9cc552014-02-20 09:58:38 -08001150
Yuta HIGUCHI8b389a72014-07-18 13:50:00 -07001151 // create unfrozen copy
1152 // for removing attachment points which already has a link
1153 HostEvent modifiedHostEvent = new HostEvent(hostEvent);
Pavlin Radoslavov3c9cc552014-02-20 09:58:38 -08001154
Yuta HIGUCHI8b389a72014-07-18 13:50:00 -07001155 // Verify each attachment point
Ray Milkey269ffb92014-04-03 14:43:30 -07001156 boolean attachmentFound = false;
Yuta HIGUCHIbfc77f02014-07-14 22:50:25 -07001157 for (SwitchPort swp : hostEvent.getAttachmentPoints()) {
1158 // XXX domain knowledge: Port must exist before Host
Yuta HIGUCHIbf0a8712014-06-30 18:59:46 -07001159 // but this knowledge cannot be pushed down to driver.
1160
Ray Milkey269ffb92014-04-03 14:43:30 -07001161 // Attached Ports must exist
Yuta HIGUCHIb1e2ab72014-06-30 11:01:31 -07001162 Port port = topology.getPort(swp.getDpid(), swp.getPortNumber());
Ray Milkey269ffb92014-04-03 14:43:30 -07001163 if (port == null) {
Yuta HIGUCHI8b389a72014-07-18 13:50:00 -07001164 log.debug("{} reordered because port {} was not there", hostEvent, swp);
Ray Milkey269ffb92014-04-03 14:43:30 -07001165 // Reordered event: delay the event in local cache
Yuta HIGUCHIbfc77f02014-07-14 22:50:25 -07001166 ByteBuffer id = hostEvent.getIDasByteBuffer();
1167 reorderedAddedHostEvents.put(id, hostEvent);
Yuta HIGUCHI8b389a72014-07-18 13:50:00 -07001168 return; // should not continue if re-applying later
Ray Milkey269ffb92014-04-03 14:43:30 -07001169 }
1170 // Attached Ports must not have Link
1171 if (port.getOutgoingLink() != null ||
1172 port.getIncomingLink() != null) {
Yuta HIGUCHI8b389a72014-07-18 13:50:00 -07001173 log.warn("Link (Out:{},In:{}) exist on the attachment point. "
1174 + "Ignoring this attachmentpoint ({}) from {}.",
1175 port.getOutgoingLink(), port.getIncomingLink(),
1176 swp, modifiedHostEvent);
1177 // FIXME Should either reject, reorder this HostEvent,
1178 // or remove attachment point from given HostEvent
1179 // Removing attachment point from given HostEvent for now.
1180 modifiedHostEvent.removeAttachmentPoint(swp);
Ray Milkey269ffb92014-04-03 14:43:30 -07001181 continue;
1182 }
1183
Ray Milkey269ffb92014-04-03 14:43:30 -07001184 attachmentFound = true;
1185 }
1186
Yuta HIGUCHIbfc77f02014-07-14 22:50:25 -07001187 // Update the host in the topology
Ray Milkey269ffb92014-04-03 14:43:30 -07001188 if (attachmentFound) {
Yuta HIGUCHI8b389a72014-07-18 13:50:00 -07001189 if (modifiedHostEvent.getAttachmentPoints().isEmpty()) {
1190 log.warn("No valid attachment point left. Ignoring."
1191 + "original: {}, modified: {}", hostEvent, modifiedHostEvent);
1192 // TODO Should we call #removeHost to trigger remove event?
1193 // only if this call is update.
1194 return;
1195 }
1196
1197 if (log.isDebugEnabled()) {
1198 HostEvent host = topology.getHostEvent(hostEvent.getMac());
1199 if (host != null) {
1200 log.debug("Update {}", modifiedHostEvent);
1201 } else {
1202 log.debug("Added {}", modifiedHostEvent);
1203 }
1204 }
1205 topology.putHost(modifiedHostEvent.freeze());
1206 apiAddedHostEvents.add(modifiedHostEvent);
Ray Milkey269ffb92014-04-03 14:43:30 -07001207 }
Pavlin Radoslavov3c9cc552014-02-20 09:58:38 -08001208 }
1209
Pavlin Radoslavov734ff5a2014-02-26 10:20:43 -08001210 /**
Yuta HIGUCHIbfc77f02014-07-14 22:50:25 -07001211 * Removes a host from the topology replica.
Ray Milkey269ffb92014-04-03 14:43:30 -07001212 * <p/>
Yuta HIGUCHIbfc77f02014-07-14 22:50:25 -07001213 * TODO: Host-related work is incomplete.
Pavlin Radoslavov734ff5a2014-02-26 10:20:43 -08001214 *
Yuta HIGUCHIbfc77f02014-07-14 22:50:25 -07001215 * @param hostEvent the Host Event with the host to remove.
Pavlin Radoslavov734ff5a2014-02-26 10:20:43 -08001216 */
Yuta HIGUCHIbc67a052014-06-30 10:37:09 -07001217 @GuardedBy("topology.writeLock")
Yuta HIGUCHIbfc77f02014-07-14 22:50:25 -07001218 private void removeHost(HostEvent hostEvent) {
Yuta HIGUCHI8b389a72014-07-18 13:50:00 -07001219
1220 final MACAddress mac = hostEvent.getMac();
1221 HostEvent hostInTopo = topology.getHostEvent(mac);
1222 if (hostInTopo == null) {
Yuta HIGUCHIbfc77f02014-07-14 22:50:25 -07001223 log.warn("Host {} already removed, ignoring", hostEvent);
Ray Milkey269ffb92014-04-03 14:43:30 -07001224 return;
1225 }
Pavlin Radoslavov3c9cc552014-02-20 09:58:38 -08001226
Yuta HIGUCHI8b389a72014-07-18 13:50:00 -07001227 log.debug("Removed {}", hostInTopo);
1228 topology.removeHost(mac);
1229 apiRemovedHostEvents.add(hostInTopo);
Pavlin Radoslavov3c9cc552014-02-20 09:58:38 -08001230 }
Jonathan Hart22eb9882014-02-11 15:52:59 -08001231
Pavlin Radoslavovc1cfde52014-02-19 11:35:29 -08001232 /**
Pavlin Radoslavov734ff5a2014-02-26 10:20:43 -08001233 * Read the whole topology from the database.
1234 *
1235 * @return a collection of EventEntry-encapsulated Topology Events for
1236 * the whole topology.
1237 */
Pavlin Radoslavov018d5332014-02-19 23:08:35 -08001238 private Collection<EventEntry<TopologyEvent>> readWholeTopologyFromDB() {
Ray Milkey269ffb92014-04-03 14:43:30 -07001239 Collection<EventEntry<TopologyEvent>> collection =
1240 new LinkedList<EventEntry<TopologyEvent>>();
Pavlin Radoslavov018d5332014-02-19 23:08:35 -08001241
Ray Milkey269ffb92014-04-03 14:43:30 -07001242 // XXX May need to clear whole topology first, depending on
1243 // how we initially subscribe to replication events
Pavlin Radoslavovc1cfde52014-02-19 11:35:29 -08001244
Ray Milkey269ffb92014-04-03 14:43:30 -07001245 // Add all active switches
1246 for (KVSwitch sw : KVSwitch.getAllSwitches()) {
1247 if (sw.getStatus() != KVSwitch.STATUS.ACTIVE) {
1248 continue;
1249 }
Pavlin Radoslavov018d5332014-02-19 23:08:35 -08001250
Yuta HIGUCHIe2a4e172014-07-03 10:50:39 -07001251 SwitchEvent switchEvent = new SwitchEvent(new Dpid(sw.getDpid()));
Ray Milkey269ffb92014-04-03 14:43:30 -07001252 TopologyEvent topologyEvent = new TopologyEvent(switchEvent);
1253 EventEntry<TopologyEvent> eventEntry =
1254 new EventEntry<TopologyEvent>(EventEntry.Type.ENTRY_ADD,
1255 topologyEvent);
1256 collection.add(eventEntry);
1257 }
Yuta HIGUCHIa536e762014-02-17 21:47:28 -08001258
Ray Milkey269ffb92014-04-03 14:43:30 -07001259 // Add all active ports
1260 for (KVPort p : KVPort.getAllPorts()) {
1261 if (p.getStatus() != KVPort.STATUS.ACTIVE) {
1262 continue;
1263 }
Pavlin Radoslavov018d5332014-02-19 23:08:35 -08001264
Yuta HIGUCHIe2a4e172014-07-03 10:50:39 -07001265 PortEvent portEvent = new PortEvent(
1266 new Dpid(p.getDpid()),
1267 new PortNumber(p.getNumber().shortValue()));
Ray Milkey269ffb92014-04-03 14:43:30 -07001268 TopologyEvent topologyEvent = new TopologyEvent(portEvent);
1269 EventEntry<TopologyEvent> eventEntry =
1270 new EventEntry<TopologyEvent>(EventEntry.Type.ENTRY_ADD,
1271 topologyEvent);
1272 collection.add(eventEntry);
1273 }
Yuta HIGUCHIa536e762014-02-17 21:47:28 -08001274
TeruU28adcc32014-04-15 17:57:35 -07001275 for (KVDevice d : KVDevice.getAllDevices()) {
Yuta HIGUCHIbfc77f02014-07-14 22:50:25 -07001276 HostEvent devEvent = new HostEvent(MACAddress.valueOf(d.getMac()));
TeruU28adcc32014-04-15 17:57:35 -07001277 for (byte[] portId : d.getAllPortIds()) {
Jonathan Hartc00f5c22014-06-10 15:14:40 -07001278 devEvent.addAttachmentPoint(
1279 new SwitchPort(KVPort.getDpidFromKey(portId),
1280 KVPort.getNumberFromKey(portId)));
TeruU28adcc32014-04-15 17:57:35 -07001281 }
1282 }
Pavlin Radoslavovc1cfde52014-02-19 11:35:29 -08001283
Ray Milkey269ffb92014-04-03 14:43:30 -07001284 for (KVLink l : KVLink.getAllLinks()) {
Yuta HIGUCHIe2a4e172014-07-03 10:50:39 -07001285 LinkEvent linkEvent = new LinkEvent(
1286 new SwitchPort(l.getSrc().dpid, l.getSrc().number),
1287 new SwitchPort(l.getDst().dpid, l.getDst().number));
Ray Milkey269ffb92014-04-03 14:43:30 -07001288 TopologyEvent topologyEvent = new TopologyEvent(linkEvent);
1289 EventEntry<TopologyEvent> eventEntry =
1290 new EventEntry<TopologyEvent>(EventEntry.Type.ENTRY_ADD,
1291 topologyEvent);
1292 collection.add(eventEntry);
1293 }
Pavlin Radoslavov018d5332014-02-19 23:08:35 -08001294
Ray Milkey269ffb92014-04-03 14:43:30 -07001295 return collection;
Pavlin Radoslavovc1cfde52014-02-19 11:35:29 -08001296 }
Jonathan Hart062a2e82014-02-03 09:41:57 -08001297}