blob: dccef166254d68901a891dac254ceb32cfdff114 [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;
Pavlin Radoslavovd4f40372014-07-18 16:58:40 -070029import net.onrc.onos.core.metrics.OnosMetrics;
30import net.onrc.onos.core.metrics.OnosMetrics.MetricsComponent;
31import net.onrc.onos.core.metrics.OnosMetrics.MetricsFeature;
Jonathan Hartdeda0ba2014-04-03 11:14:12 -070032import net.onrc.onos.core.registry.IControllerRegistryService;
Yuta HIGUCHI8f3dfa32014-06-25 00:14:25 -070033import net.onrc.onos.core.util.Dpid;
Jonathan Hart23701d12014-04-03 10:45:48 -070034import net.onrc.onos.core.util.EventEntry;
Yuta HIGUCHIe2a4e172014-07-03 10:50:39 -070035import net.onrc.onos.core.util.PortNumber;
Yuta HIGUCHI5c8cbeb2014-06-27 11:13:48 -070036import net.onrc.onos.core.util.SwitchPort;
Pavlin Radoslavov4eaab992014-07-03 18:39:42 -070037import net.onrc.onos.core.util.serializers.KryoFactory;
Yuta HIGUCHI5c8cbeb2014-06-27 11:13:48 -070038
Jonathan Hart062a2e82014-02-03 09:41:57 -080039import org.slf4j.Logger;
40import org.slf4j.LoggerFactory;
41
Pavlin Radoslavovd4f40372014-07-18 16:58:40 -070042import com.codahale.metrics.Gauge;
43import com.codahale.metrics.Meter;
Pavlin Radoslavov4eaab992014-07-03 18:39:42 -070044import com.esotericsoftware.kryo.Kryo;
45
Yuta HIGUCHI181d34d2014-02-05 15:05:46 -080046/**
Jonathan Harte37e4e22014-05-13 19:12:02 -070047 * The TopologyManager receives topology updates from the southbound discovery
48 * modules and from other ONOS instances. These updates are processed and
49 * applied to the in-memory topology instance.
Ray Milkey269ffb92014-04-03 14:43:30 -070050 * <p/>
Yuta HIGUCHI4bfdd532014-02-07 13:47:36 -080051 * - Maintain Invariant/Relationships between Topology Objects.
Ray Milkey269ffb92014-04-03 14:43:30 -070052 * <p/>
Yuta HIGUCHI765cd0d2014-02-06 12:46:41 -080053 * TODO To be synchronized based on TopologyEvent Notification.
Ray Milkey269ffb92014-04-03 14:43:30 -070054 * <p/>
Yuta HIGUCHIcb951982014-02-11 13:31:44 -080055 * TODO TBD: Caller is expected to maintain parent/child calling order. Parent
Yuta HIGUCHI1c700102014-02-12 16:30:52 -080056 * Object must exist before adding sub component(Add Switch -> Port).
Ray Milkey269ffb92014-04-03 14:43:30 -070057 * <p/>
Yuta HIGUCHI4bfdd532014-02-07 13:47:36 -080058 * TODO TBD: This class may delay the requested change to handle event
59 * re-ordering. e.g.) Link Add came in, but Switch was not there.
Yuta HIGUCHI181d34d2014-02-05 15:05:46 -080060 */
Jonathan Harte37e4e22014-05-13 19:12:02 -070061public class TopologyManager implements TopologyDiscoveryInterface {
Jonathan Hart062a2e82014-02-03 09:41:57 -080062
Yuta HIGUCHI80829d12014-02-05 20:16:56 -080063 private static final Logger log = LoggerFactory
Ray Milkey269ffb92014-04-03 14:43:30 -070064 .getLogger(TopologyManager.class);
Yuta HIGUCHIcd922f42014-02-11 18:59:11 -080065
Pavlin Radoslavov721a2e02014-02-14 23:40:14 -080066 private IEventChannel<byte[], TopologyEvent> eventChannel;
Jonathan Hart10a7e2b2014-02-21 18:30:08 -080067 public static final String EVENT_CHANNEL_NAME = "onos.topology";
Pavlin Radoslavov721a2e02014-02-14 23:40:14 -080068 private EventHandler eventHandler = new EventHandler();
69
weibitf7c31a42014-06-23 16:51:01 -070070 private TopologyDatastore datastore;
Jonathan Harte37e4e22014-05-13 19:12:02 -070071 private final TopologyImpl topology = new TopologyImpl();
Yuta HIGUCHI170229f2014-02-17 15:47:54 -080072 private final IControllerRegistryService registryService;
Jonathan Harte37e4e22014-05-13 19:12:02 -070073 private CopyOnWriteArrayList<ITopologyListener> topologyListeners;
Pavlin Radoslavov4eaab992014-07-03 18:39:42 -070074 private Kryo kryo = KryoFactory.newKryoObject();
Yuta HIGUCHI181d34d2014-02-05 15:05:46 -080075
Pavlin Radoslavov706add22014-02-20 12:15:59 -080076 //
Pavlin Radoslavovd4f40372014-07-18 16:58:40 -070077 // Metrics
78 //
79 private static final MetricsComponent METRICS_COMPONENT =
80 OnosMetrics.registerComponent("Topology");
81 private static final MetricsFeature METRICS_FEATURE_EVENT_NOTIFICATION =
82 METRICS_COMPONENT.registerFeature("EventNotification");
83 //
Pavlin Radoslavovc49917c2014-07-23 12:16:29 -070084 // Timestamp of the last Topology event (ms from the Epoch)
85 private volatile long lastEventTimestampEpochMs = 0;
86 private final Gauge<Long> gaugeLastEventTimestampEpochMs =
Pavlin Radoslavovd4f40372014-07-18 16:58:40 -070087 OnosMetrics.registerMetric(METRICS_COMPONENT,
88 METRICS_FEATURE_EVENT_NOTIFICATION,
Pavlin Radoslavovc49917c2014-07-23 12:16:29 -070089 "LastEventTimestamp.EpochMs",
Pavlin Radoslavovd4f40372014-07-18 16:58:40 -070090 new Gauge<Long>() {
91 @Override
92 public Long getValue() {
Pavlin Radoslavovc49917c2014-07-23 12:16:29 -070093 return lastEventTimestampEpochMs;
Pavlin Radoslavovd4f40372014-07-18 16:58:40 -070094 }
95 });
96 // Rate of the Topology events published to the Topology listeners
97 private final Meter listenerEventRate =
98 OnosMetrics.createMeter(METRICS_COMPONENT,
99 METRICS_FEATURE_EVENT_NOTIFICATION,
100 "ListenerEventRate");
101
102 //
Pavlin Radoslavov706add22014-02-20 12:15:59 -0800103 // Local state for keeping track of reordered events.
104 // NOTE: Switch Events are not affected by the event reordering.
105 //
106 private Map<ByteBuffer, PortEvent> reorderedAddedPortEvents =
Ray Milkey269ffb92014-04-03 14:43:30 -0700107 new HashMap<ByteBuffer, PortEvent>();
Pavlin Radoslavov706add22014-02-20 12:15:59 -0800108 private Map<ByteBuffer, LinkEvent> reorderedAddedLinkEvents =
Ray Milkey269ffb92014-04-03 14:43:30 -0700109 new HashMap<ByteBuffer, LinkEvent>();
Yuta HIGUCHIbfc77f02014-07-14 22:50:25 -0700110 private Map<ByteBuffer, HostEvent> reorderedAddedHostEvents =
111 new HashMap<ByteBuffer, HostEvent>();
Pavlin Radoslavov018d5332014-02-19 23:08:35 -0800112
Pavlin Radoslavov74986ce2014-02-20 13:17:20 -0800113 //
Pavlin Radoslavov26d83402014-02-20 15:24:30 -0800114 // Local state for keeping track of locally discovered events so we can
115 // cleanup properly when a Switch or Port is removed.
116 //
Yuta HIGUCHIbfc77f02014-07-14 22:50:25 -0700117 // We keep all Port, (incoming) Link and Host events per Switch DPID:
Pavlin Radoslavov26d83402014-02-20 15:24:30 -0800118 // - If a switch goes down, we remove all corresponding Port, Link and
Yuta HIGUCHIbfc77f02014-07-14 22:50:25 -0700119 // Host events.
Pavlin Radoslavov26d83402014-02-20 15:24:30 -0800120 // - If a port on a switch goes down, we remove all corresponding Link
Yuta HIGUCHIbfc77f02014-07-14 22:50:25 -0700121 // and Host events discovered by this instance.
Yuta HIGUCHIbc67a052014-06-30 10:37:09 -0700122 //
123 // How to handle side-effect of remote events.
124 // - Remote Port Down event -> Link Down
125 // Not handled. (XXX Shouldn't it be removed from discovered.. Map)
Yuta HIGUCHIbfc77f02014-07-14 22:50:25 -0700126 // - Remote Host Added -> lose ownership of Host)
Yuta HIGUCHIbc67a052014-06-30 10:37:09 -0700127 // Not handled. (XXX Shouldn't it be removed from discovered.. Map)
128 //
129 // XXX Domain knowledge based invariant maintenance should be moved to
130 // driver module, since the invariant may be different on optical, etc.
131 //
132 // What happens on leadership change?
133 // - Probably should: remove from discovered.. Maps, but not send DELETE events
Yuta HIGUCHIbfc77f02014-07-14 22:50:25 -0700134 // XXX Switch/Port can be rediscovered by new leader, but Link, Host?
Yuta HIGUCHIbc67a052014-06-30 10:37:09 -0700135 // - Current: There is no way to recognize leadership change?
136 // ZookeeperRegistry.requestControl(long, ControlChangeCallback)
137 // is the only way to register listener, and it allows only 1 listener,
138 // which is already used by Controller class.
139 //
140 // FIXME Replace with concurrent variant.
141 // #removeSwitchDiscoveryEvent(SwitchEvent) runs in different thread.
Pavlin Radoslavov26d83402014-02-20 15:24:30 -0800142 //
Yuta HIGUCHI8f3dfa32014-06-25 00:14:25 -0700143 private Map<Dpid, Map<ByteBuffer, PortEvent>> discoveredAddedPortEvents =
Ray Milkey269ffb92014-04-03 14:43:30 -0700144 new HashMap<>();
Yuta HIGUCHI8f3dfa32014-06-25 00:14:25 -0700145 private Map<Dpid, Map<ByteBuffer, LinkEvent>> discoveredAddedLinkEvents =
Ray Milkey269ffb92014-04-03 14:43:30 -0700146 new HashMap<>();
Yuta HIGUCHIbfc77f02014-07-14 22:50:25 -0700147 private Map<Dpid, Map<ByteBuffer, HostEvent>> discoveredAddedHostEvents =
Ray Milkey269ffb92014-04-03 14:43:30 -0700148 new HashMap<>();
Pavlin Radoslavov26d83402014-02-20 15:24:30 -0800149
150 //
Pavlin Radoslavov74986ce2014-02-20 13:17:20 -0800151 // Local state for keeping track of the application event notifications
152 //
Yuta HIGUCHIbc67a052014-06-30 10:37:09 -0700153 // - Queue of events, which will be dispatched to local listeners
154 // on next notification.
Yuta HIGUCHI703696c2014-06-25 20:36:45 -0700155
156 private List<SwitchEvent> apiAddedSwitchEvents = new LinkedList<>();
157 private List<SwitchEvent> apiRemovedSwitchEvents = new LinkedList<>();
158 private List<PortEvent> apiAddedPortEvents = new LinkedList<>();
159 private List<PortEvent> apiRemovedPortEvents = new LinkedList<>();
160 private List<LinkEvent> apiAddedLinkEvents = new LinkedList<>();
161 private List<LinkEvent> apiRemovedLinkEvents = new LinkedList<>();
Yuta HIGUCHIbfc77f02014-07-14 22:50:25 -0700162 private List<HostEvent> apiAddedHostEvents = new LinkedList<>();
163 private List<HostEvent> apiRemovedHostEvents = new LinkedList<>();
Pavlin Radoslavov74986ce2014-02-20 13:17:20 -0800164
Pavlin Radoslavovc1cfde52014-02-19 11:35:29 -0800165 /**
166 * Constructor.
167 *
Jonathan Harte37e4e22014-05-13 19:12:02 -0700168 * @param registryService the Registry Service to use.
169 * @param topologyListeners the collection of topology listeners to use.
Pavlin Radoslavovc1cfde52014-02-19 11:35:29 -0800170 */
171 public TopologyManager(IControllerRegistryService registryService,
Jonathan Harte37e4e22014-05-13 19:12:02 -0700172 CopyOnWriteArrayList<ITopologyListener> topologyListeners) {
173 datastore = new TopologyDatastore();
Ray Milkey269ffb92014-04-03 14:43:30 -0700174 this.registryService = registryService;
Jonathan Harte37e4e22014-05-13 19:12:02 -0700175 this.topologyListeners = topologyListeners;
Yuta HIGUCHI80829d12014-02-05 20:16:56 -0800176 }
Yuta HIGUCHI181d34d2014-02-05 15:05:46 -0800177
Pavlin Radoslavovc1cfde52014-02-19 11:35:29 -0800178 /**
Jonathan Harte37e4e22014-05-13 19:12:02 -0700179 * Get the Topology.
Pavlin Radoslavovc1cfde52014-02-19 11:35:29 -0800180 *
Jonathan Harte37e4e22014-05-13 19:12:02 -0700181 * @return the Topology.
Pavlin Radoslavovc1cfde52014-02-19 11:35:29 -0800182 */
Jonathan Harte37e4e22014-05-13 19:12:02 -0700183 Topology getTopology() {
184 return topology;
Pavlin Radoslavov6d224ee2014-02-18 16:43:15 -0800185 }
186
Yuta HIGUCHI4bfdd532014-02-07 13:47:36 -0800187 /**
Pavlin Radoslavov721a2e02014-02-14 23:40:14 -0800188 * Event handler class.
189 */
Yuta HIGUCHI8b389a72014-07-18 13:50:00 -0700190 class EventHandler extends Thread implements
Ray Milkey269ffb92014-04-03 14:43:30 -0700191 IEventChannelListener<byte[], TopologyEvent> {
192 private BlockingQueue<EventEntry<TopologyEvent>> topologyEvents =
193 new LinkedBlockingQueue<EventEntry<TopologyEvent>>();
Pavlin Radoslavov721a2e02014-02-14 23:40:14 -0800194
Ray Milkey269ffb92014-04-03 14:43:30 -0700195 /**
196 * Startup processing.
197 */
198 private void startup() {
199 //
200 // TODO: Read all state from the database:
201 //
202 // Collection<EventEntry<TopologyEvent>> collection =
203 // readWholeTopologyFromDB();
204 //
205 // For now, as a shortcut we read it from the datagrid
206 //
Ray Milkey5df613b2014-04-15 10:50:56 -0700207 Collection<TopologyEvent> allTopologyEvents =
Ray Milkey269ffb92014-04-03 14:43:30 -0700208 eventChannel.getAllEntries();
209 Collection<EventEntry<TopologyEvent>> collection =
210 new LinkedList<EventEntry<TopologyEvent>>();
Pavlin Radoslavov721a2e02014-02-14 23:40:14 -0800211
Ray Milkey5df613b2014-04-15 10:50:56 -0700212 for (TopologyEvent topologyEvent : allTopologyEvents) {
Ray Milkey269ffb92014-04-03 14:43:30 -0700213 EventEntry<TopologyEvent> eventEntry =
214 new EventEntry<TopologyEvent>(EventEntry.Type.ENTRY_ADD,
215 topologyEvent);
216 collection.add(eventEntry);
217 }
218 processEvents(collection);
219 }
Pavlin Radoslavov721a2e02014-02-14 23:40:14 -0800220
Ray Milkey269ffb92014-04-03 14:43:30 -0700221 /**
222 * Run the thread.
223 */
224 @Override
225 public void run() {
226 Collection<EventEntry<TopologyEvent>> collection =
227 new LinkedList<EventEntry<TopologyEvent>>();
Pavlin Radoslavov721a2e02014-02-14 23:40:14 -0800228
Ray Milkey269ffb92014-04-03 14:43:30 -0700229 this.setName("TopologyManager.EventHandler " + this.getId());
230 startup();
Pavlin Radoslavov721a2e02014-02-14 23:40:14 -0800231
Ray Milkey269ffb92014-04-03 14:43:30 -0700232 //
233 // The main loop
234 //
Pavlin Radoslavov8e881a42014-06-24 16:58:07 -0700235 while (true) {
236 try {
237 EventEntry<TopologyEvent> eventEntry =
238 topologyEvents.take();
Ray Milkey269ffb92014-04-03 14:43:30 -0700239 collection.add(eventEntry);
240 topologyEvents.drainTo(collection);
Pavlin Radoslavov721a2e02014-02-14 23:40:14 -0800241
Ray Milkey269ffb92014-04-03 14:43:30 -0700242 processEvents(collection);
243 collection.clear();
Pavlin Radoslavov8e881a42014-06-24 16:58:07 -0700244 } catch (Exception exception) {
245 log.debug("Exception processing Topology Events: ",
246 exception);
Ray Milkey269ffb92014-04-03 14:43:30 -0700247 }
Ray Milkey269ffb92014-04-03 14:43:30 -0700248 }
249 }
Pavlin Radoslavov721a2e02014-02-14 23:40:14 -0800250
Ray Milkey269ffb92014-04-03 14:43:30 -0700251 /**
252 * Process all topology events.
253 *
254 * @param events the events to process.
255 */
256 private void processEvents(Collection<EventEntry<TopologyEvent>> events) {
257 // Local state for computing the final set of events
258 Map<ByteBuffer, SwitchEvent> addedSwitchEvents = new HashMap<>();
259 Map<ByteBuffer, SwitchEvent> removedSwitchEvents = new HashMap<>();
260 Map<ByteBuffer, PortEvent> addedPortEvents = new HashMap<>();
261 Map<ByteBuffer, PortEvent> removedPortEvents = new HashMap<>();
262 Map<ByteBuffer, LinkEvent> addedLinkEvents = new HashMap<>();
263 Map<ByteBuffer, LinkEvent> removedLinkEvents = new HashMap<>();
Yuta HIGUCHIbfc77f02014-07-14 22:50:25 -0700264 Map<ByteBuffer, HostEvent> addedHostEvents = new HashMap<>();
265 Map<ByteBuffer, HostEvent> removedHostEvents = new HashMap<>();
Pavlin Radoslavov3c9cc552014-02-20 09:58:38 -0800266
Ray Milkey269ffb92014-04-03 14:43:30 -0700267 //
268 // Classify and suppress matching events
269 //
270 for (EventEntry<TopologyEvent> event : events) {
271 TopologyEvent topologyEvent = event.eventData();
272 SwitchEvent switchEvent = topologyEvent.switchEvent;
273 PortEvent portEvent = topologyEvent.portEvent;
274 LinkEvent linkEvent = topologyEvent.linkEvent;
Yuta HIGUCHIbfc77f02014-07-14 22:50:25 -0700275 HostEvent hostEvent = topologyEvent.hostEvent;
Pavlin Radoslavov018d5332014-02-19 23:08:35 -0800276
Ray Milkey269ffb92014-04-03 14:43:30 -0700277 //
278 // Extract the events
279 //
Yuta HIGUCHI8b389a72014-07-18 13:50:00 -0700280 // FIXME Following event squashing logic based only on ID
281 // potentially lose attribute change.
Ray Milkey269ffb92014-04-03 14:43:30 -0700282 switch (event.eventType()) {
283 case ENTRY_ADD:
284 log.debug("Topology event ENTRY_ADD: {}", topologyEvent);
285 if (switchEvent != null) {
286 ByteBuffer id = switchEvent.getIDasByteBuffer();
287 addedSwitchEvents.put(id, switchEvent);
288 removedSwitchEvents.remove(id);
289 // Switch Events are not affected by event reordering
290 }
291 if (portEvent != null) {
292 ByteBuffer id = portEvent.getIDasByteBuffer();
293 addedPortEvents.put(id, portEvent);
294 removedPortEvents.remove(id);
295 reorderedAddedPortEvents.remove(id);
296 }
297 if (linkEvent != null) {
298 ByteBuffer id = linkEvent.getIDasByteBuffer();
299 addedLinkEvents.put(id, linkEvent);
300 removedLinkEvents.remove(id);
301 reorderedAddedLinkEvents.remove(id);
302 }
Yuta HIGUCHIbfc77f02014-07-14 22:50:25 -0700303 if (hostEvent != null) {
304 ByteBuffer id = hostEvent.getIDasByteBuffer();
305 addedHostEvents.put(id, hostEvent);
306 removedHostEvents.remove(id);
307 reorderedAddedHostEvents.remove(id);
Ray Milkey269ffb92014-04-03 14:43:30 -0700308 }
309 break;
310 case ENTRY_REMOVE:
311 log.debug("Topology event ENTRY_REMOVE: {}", topologyEvent);
312 if (switchEvent != null) {
313 ByteBuffer id = switchEvent.getIDasByteBuffer();
314 addedSwitchEvents.remove(id);
315 removedSwitchEvents.put(id, switchEvent);
316 // Switch Events are not affected by event reordering
317 }
318 if (portEvent != null) {
319 ByteBuffer id = portEvent.getIDasByteBuffer();
320 addedPortEvents.remove(id);
321 removedPortEvents.put(id, portEvent);
322 reorderedAddedPortEvents.remove(id);
323 }
324 if (linkEvent != null) {
325 ByteBuffer id = linkEvent.getIDasByteBuffer();
326 addedLinkEvents.remove(id);
327 removedLinkEvents.put(id, linkEvent);
328 reorderedAddedLinkEvents.remove(id);
329 }
Yuta HIGUCHIbfc77f02014-07-14 22:50:25 -0700330 if (hostEvent != null) {
331 ByteBuffer id = hostEvent.getIDasByteBuffer();
332 addedHostEvents.remove(id);
333 removedHostEvents.put(id, hostEvent);
334 reorderedAddedHostEvents.remove(id);
Ray Milkey269ffb92014-04-03 14:43:30 -0700335 }
336 break;
Ray Milkey0b122ed2014-04-14 10:06:03 -0700337 default:
338 log.error("Unknown topology event {}",
339 event.eventType());
Ray Milkey269ffb92014-04-03 14:43:30 -0700340 }
341 }
Pavlin Radoslavov3c9cc552014-02-20 09:58:38 -0800342
Ray Milkey269ffb92014-04-03 14:43:30 -0700343 //
Jonathan Harte37e4e22014-05-13 19:12:02 -0700344 // Lock the topology while it is modified
Ray Milkey269ffb92014-04-03 14:43:30 -0700345 //
Jonathan Harte37e4e22014-05-13 19:12:02 -0700346 topology.acquireWriteLock();
Pavlin Radoslavov8ffb8bf2014-02-20 15:34:26 -0800347
Ray Milkey269ffb92014-04-03 14:43:30 -0700348 try {
349 //
350 // Apply the classified events.
351 //
352 // Apply the "add" events in the proper order:
Yuta HIGUCHIbfc77f02014-07-14 22:50:25 -0700353 // switch, port, link, host
Ray Milkey269ffb92014-04-03 14:43:30 -0700354 //
Ray Milkeyb29e6262014-04-09 16:02:14 -0700355 for (SwitchEvent switchEvent : addedSwitchEvents.values()) {
Ray Milkey269ffb92014-04-03 14:43:30 -0700356 addSwitch(switchEvent);
Ray Milkeyb29e6262014-04-09 16:02:14 -0700357 }
358 for (PortEvent portEvent : addedPortEvents.values()) {
Ray Milkey269ffb92014-04-03 14:43:30 -0700359 addPort(portEvent);
Ray Milkeyb29e6262014-04-09 16:02:14 -0700360 }
361 for (LinkEvent linkEvent : addedLinkEvents.values()) {
Ray Milkey269ffb92014-04-03 14:43:30 -0700362 addLink(linkEvent);
Ray Milkeyb29e6262014-04-09 16:02:14 -0700363 }
Yuta HIGUCHIbfc77f02014-07-14 22:50:25 -0700364 for (HostEvent hostEvent : addedHostEvents.values()) {
365 addHost(hostEvent);
Ray Milkeyb29e6262014-04-09 16:02:14 -0700366 }
Ray Milkey269ffb92014-04-03 14:43:30 -0700367 //
368 // Apply the "remove" events in the reverse order:
Yuta HIGUCHIbfc77f02014-07-14 22:50:25 -0700369 // host, link, port, switch
Ray Milkey269ffb92014-04-03 14:43:30 -0700370 //
Yuta HIGUCHIbfc77f02014-07-14 22:50:25 -0700371 for (HostEvent hostEvent : removedHostEvents.values()) {
372 removeHost(hostEvent);
Ray Milkeyb29e6262014-04-09 16:02:14 -0700373 }
374 for (LinkEvent linkEvent : removedLinkEvents.values()) {
Ray Milkey269ffb92014-04-03 14:43:30 -0700375 removeLink(linkEvent);
Ray Milkeyb29e6262014-04-09 16:02:14 -0700376 }
377 for (PortEvent portEvent : removedPortEvents.values()) {
Ray Milkey269ffb92014-04-03 14:43:30 -0700378 removePort(portEvent);
Ray Milkeyb29e6262014-04-09 16:02:14 -0700379 }
380 for (SwitchEvent switchEvent : removedSwitchEvents.values()) {
Ray Milkey269ffb92014-04-03 14:43:30 -0700381 removeSwitch(switchEvent);
Ray Milkeyb29e6262014-04-09 16:02:14 -0700382 }
Yuta HIGUCHI3aca81a2014-02-23 12:41:19 -0800383
Ray Milkey269ffb92014-04-03 14:43:30 -0700384 //
385 // Apply reordered events
386 //
387 applyReorderedEvents(!addedSwitchEvents.isEmpty(),
388 !addedPortEvents.isEmpty());
Yuta HIGUCHI3aca81a2014-02-23 12:41:19 -0800389
Ray Milkey269ffb92014-04-03 14:43:30 -0700390 } finally {
391 //
Jonathan Harte37e4e22014-05-13 19:12:02 -0700392 // Topology modifications completed: Release the lock
Ray Milkey269ffb92014-04-03 14:43:30 -0700393 //
Jonathan Harte37e4e22014-05-13 19:12:02 -0700394 topology.releaseWriteLock();
Ray Milkey269ffb92014-04-03 14:43:30 -0700395 }
Yuta HIGUCHI3aca81a2014-02-23 12:41:19 -0800396
Ray Milkey269ffb92014-04-03 14:43:30 -0700397 //
398 // Dispatch the Topology Notification Events to the applications
399 //
Jonathan Harte37e4e22014-05-13 19:12:02 -0700400 dispatchTopologyEvents();
Ray Milkey269ffb92014-04-03 14:43:30 -0700401 }
Pavlin Radoslavov721a2e02014-02-14 23:40:14 -0800402
Ray Milkey269ffb92014-04-03 14:43:30 -0700403 /**
404 * Receive a notification that an entry is added.
405 *
406 * @param value the value for the entry.
407 */
408 @Override
409 public void entryAdded(TopologyEvent value) {
410 EventEntry<TopologyEvent> eventEntry =
411 new EventEntry<TopologyEvent>(EventEntry.Type.ENTRY_ADD,
412 value);
413 topologyEvents.add(eventEntry);
414 }
Pavlin Radoslavov721a2e02014-02-14 23:40:14 -0800415
Ray Milkey269ffb92014-04-03 14:43:30 -0700416 /**
417 * Receive a notification that an entry is removed.
418 *
419 * @param value the value for the entry.
420 */
421 @Override
422 public void entryRemoved(TopologyEvent value) {
423 EventEntry<TopologyEvent> eventEntry =
424 new EventEntry<TopologyEvent>(EventEntry.Type.ENTRY_REMOVE,
425 value);
426 topologyEvents.add(eventEntry);
427 }
Pavlin Radoslavov721a2e02014-02-14 23:40:14 -0800428
Ray Milkey269ffb92014-04-03 14:43:30 -0700429 /**
430 * Receive a notification that an entry is updated.
431 *
432 * @param value the value for the entry.
433 */
434 @Override
435 public void entryUpdated(TopologyEvent value) {
436 // NOTE: The ADD and UPDATE events are processed in same way
437 entryAdded(value);
438 }
Pavlin Radoslavov721a2e02014-02-14 23:40:14 -0800439 }
440
441 /**
442 * Startup processing.
443 *
444 * @param datagridService the datagrid service to use.
445 */
446 void startup(IDatagridService datagridService) {
Ray Milkey269ffb92014-04-03 14:43:30 -0700447 eventChannel = datagridService.addListener(EVENT_CHANNEL_NAME,
448 eventHandler,
449 byte[].class,
450 TopologyEvent.class);
451 eventHandler.start();
Pavlin Radoslavov721a2e02014-02-14 23:40:14 -0800452 }
453
Pavlin Radoslavov74986ce2014-02-20 13:17:20 -0800454 /**
Jonathan Harte37e4e22014-05-13 19:12:02 -0700455 * Dispatch Topology Events to the listeners.
Pavlin Radoslavov74986ce2014-02-20 13:17:20 -0800456 */
Jonathan Harte37e4e22014-05-13 19:12:02 -0700457 private void dispatchTopologyEvents() {
Ray Milkey269ffb92014-04-03 14:43:30 -0700458 if (apiAddedSwitchEvents.isEmpty() &&
459 apiRemovedSwitchEvents.isEmpty() &&
460 apiAddedPortEvents.isEmpty() &&
461 apiRemovedPortEvents.isEmpty() &&
462 apiAddedLinkEvents.isEmpty() &&
463 apiRemovedLinkEvents.isEmpty() &&
Yuta HIGUCHIbfc77f02014-07-14 22:50:25 -0700464 apiAddedHostEvents.isEmpty() &&
465 apiRemovedHostEvents.isEmpty()) {
Ray Milkey269ffb92014-04-03 14:43:30 -0700466 return; // No events to dispatch
467 }
Pavlin Radoslavov74986ce2014-02-20 13:17:20 -0800468
Ray Milkey269ffb92014-04-03 14:43:30 -0700469 if (log.isDebugEnabled()) {
470 //
471 // Debug statements
472 // TODO: Those statements should be removed in the future
473 //
Ray Milkeyb29e6262014-04-09 16:02:14 -0700474 for (SwitchEvent switchEvent : apiAddedSwitchEvents) {
Jonathan Harte37e4e22014-05-13 19:12:02 -0700475 log.debug("Dispatch Topology Event: ADDED {}", switchEvent);
Ray Milkeyb29e6262014-04-09 16:02:14 -0700476 }
477 for (SwitchEvent switchEvent : apiRemovedSwitchEvents) {
Jonathan Harte37e4e22014-05-13 19:12:02 -0700478 log.debug("Dispatch Topology Event: REMOVED {}", switchEvent);
Ray Milkeyb29e6262014-04-09 16:02:14 -0700479 }
480 for (PortEvent portEvent : apiAddedPortEvents) {
Jonathan Harte37e4e22014-05-13 19:12:02 -0700481 log.debug("Dispatch Topology Event: ADDED {}", portEvent);
Ray Milkeyb29e6262014-04-09 16:02:14 -0700482 }
483 for (PortEvent portEvent : apiRemovedPortEvents) {
Jonathan Harte37e4e22014-05-13 19:12:02 -0700484 log.debug("Dispatch Topology Event: REMOVED {}", portEvent);
Ray Milkeyb29e6262014-04-09 16:02:14 -0700485 }
486 for (LinkEvent linkEvent : apiAddedLinkEvents) {
Jonathan Harte37e4e22014-05-13 19:12:02 -0700487 log.debug("Dispatch Topology Event: ADDED {}", linkEvent);
Ray Milkeyb29e6262014-04-09 16:02:14 -0700488 }
489 for (LinkEvent linkEvent : apiRemovedLinkEvents) {
Jonathan Harte37e4e22014-05-13 19:12:02 -0700490 log.debug("Dispatch Topology Event: REMOVED {}", linkEvent);
Ray Milkeyb29e6262014-04-09 16:02:14 -0700491 }
Yuta HIGUCHIbfc77f02014-07-14 22:50:25 -0700492 for (HostEvent hostEvent : apiAddedHostEvents) {
493 log.debug("Dispatch Topology Event: ADDED {}", hostEvent);
Ray Milkeyb29e6262014-04-09 16:02:14 -0700494 }
Yuta HIGUCHIbfc77f02014-07-14 22:50:25 -0700495 for (HostEvent hostEvent : apiRemovedHostEvents) {
496 log.debug("Dispatch Topology Event: REMOVED {}", hostEvent);
Ray Milkeyb29e6262014-04-09 16:02:14 -0700497 }
Ray Milkey269ffb92014-04-03 14:43:30 -0700498 }
adminbc181552014-02-21 18:36:42 -0800499
Pavlin Radoslavovd4f40372014-07-18 16:58:40 -0700500 //
501 // Update the metrics
502 //
503 long totalEvents =
504 apiAddedSwitchEvents.size() + apiRemovedSwitchEvents.size() +
505 apiAddedPortEvents.size() + apiRemovedPortEvents.size() +
506 apiAddedLinkEvents.size() + apiRemovedLinkEvents.size() +
507 apiAddedHostEvents.size() + apiRemovedHostEvents.size();
508 this.listenerEventRate.mark(totalEvents);
Pavlin Radoslavovc49917c2014-07-23 12:16:29 -0700509 this.lastEventTimestampEpochMs = System.currentTimeMillis();
Pavlin Radoslavovd4f40372014-07-18 16:58:40 -0700510
511 //
Ray Milkey269ffb92014-04-03 14:43:30 -0700512 // Deliver the events
Pavlin Radoslavovd4f40372014-07-18 16:58:40 -0700513 //
Jonathan Harte37e4e22014-05-13 19:12:02 -0700514 for (ITopologyListener listener : this.topologyListeners) {
Pavlin Radoslavov4eaab992014-07-03 18:39:42 -0700515 TopologyEvents events =
Pavlin Radoslavovc49917c2014-07-23 12:16:29 -0700516 new TopologyEvents(lastEventTimestampEpochMs,
Pavlin Radoslavov4eaab992014-07-03 18:39:42 -0700517 kryo.copy(apiAddedSwitchEvents),
518 kryo.copy(apiRemovedSwitchEvents),
519 kryo.copy(apiAddedPortEvents),
520 kryo.copy(apiRemovedPortEvents),
521 kryo.copy(apiAddedLinkEvents),
522 kryo.copy(apiRemovedLinkEvents),
Yuta HIGUCHIbfc77f02014-07-14 22:50:25 -0700523 kryo.copy(apiAddedHostEvents),
524 kryo.copy(apiRemovedHostEvents));
Pavlin Radoslavov4eaab992014-07-03 18:39:42 -0700525 listener.topologyEvents(events);
Ray Milkey269ffb92014-04-03 14:43:30 -0700526 }
Pavlin Radoslavov74986ce2014-02-20 13:17:20 -0800527
Ray Milkey269ffb92014-04-03 14:43:30 -0700528 //
529 // Cleanup
530 //
531 apiAddedSwitchEvents.clear();
532 apiRemovedSwitchEvents.clear();
533 apiAddedPortEvents.clear();
534 apiRemovedPortEvents.clear();
535 apiAddedLinkEvents.clear();
536 apiRemovedLinkEvents.clear();
Yuta HIGUCHIbfc77f02014-07-14 22:50:25 -0700537 apiAddedHostEvents.clear();
538 apiRemovedHostEvents.clear();
Pavlin Radoslavov74986ce2014-02-20 13:17:20 -0800539 }
540
541 /**
542 * Apply reordered events.
543 *
544 * @param hasAddedSwitchEvents true if there were Added Switch Events.
Ray Milkey269ffb92014-04-03 14:43:30 -0700545 * @param hasAddedPortEvents true if there were Added Port Events.
Pavlin Radoslavov74986ce2014-02-20 13:17:20 -0800546 */
Yuta HIGUCHIbc67a052014-06-30 10:37:09 -0700547 @GuardedBy("topology.writeLock")
Pavlin Radoslavov74986ce2014-02-20 13:17:20 -0800548 private void applyReorderedEvents(boolean hasAddedSwitchEvents,
Ray Milkey269ffb92014-04-03 14:43:30 -0700549 boolean hasAddedPortEvents) {
Ray Milkeyb29e6262014-04-09 16:02:14 -0700550 if (!(hasAddedSwitchEvents || hasAddedPortEvents)) {
Ray Milkey269ffb92014-04-03 14:43:30 -0700551 return; // Nothing to do
Ray Milkeyb29e6262014-04-09 16:02:14 -0700552 }
Pavlin Radoslavov74986ce2014-02-20 13:17:20 -0800553
Ray Milkey269ffb92014-04-03 14:43:30 -0700554 //
555 // Try to apply the reordered events.
556 //
557 // NOTE: For simplicity we try to apply all events of a particular
558 // type if any "parent" type event was processed:
559 // - Apply reordered Port Events if Switches were added
Yuta HIGUCHIbfc77f02014-07-14 22:50:25 -0700560 // - Apply reordered Link and Host Events if Switches or Ports
Ray Milkey269ffb92014-04-03 14:43:30 -0700561 // were added
562 //
adminbc181552014-02-21 18:36:42 -0800563
Ray Milkey269ffb92014-04-03 14:43:30 -0700564 //
565 // Apply reordered Port Events if Switches were added
566 //
567 if (hasAddedSwitchEvents) {
568 Map<ByteBuffer, PortEvent> portEvents = reorderedAddedPortEvents;
569 reorderedAddedPortEvents = new HashMap<>();
Ray Milkeyb29e6262014-04-09 16:02:14 -0700570 for (PortEvent portEvent : portEvents.values()) {
Ray Milkey269ffb92014-04-03 14:43:30 -0700571 addPort(portEvent);
Ray Milkeyb29e6262014-04-09 16:02:14 -0700572 }
Ray Milkey269ffb92014-04-03 14:43:30 -0700573 }
574 //
Yuta HIGUCHIbfc77f02014-07-14 22:50:25 -0700575 // Apply reordered Link and Host Events if Switches or Ports
Ray Milkey269ffb92014-04-03 14:43:30 -0700576 // were added.
577 //
578 Map<ByteBuffer, LinkEvent> linkEvents = reorderedAddedLinkEvents;
579 reorderedAddedLinkEvents = new HashMap<>();
Ray Milkeyb29e6262014-04-09 16:02:14 -0700580 for (LinkEvent linkEvent : linkEvents.values()) {
Ray Milkey269ffb92014-04-03 14:43:30 -0700581 addLink(linkEvent);
Ray Milkeyb29e6262014-04-09 16:02:14 -0700582 }
Ray Milkey269ffb92014-04-03 14:43:30 -0700583 //
Yuta HIGUCHIbfc77f02014-07-14 22:50:25 -0700584 Map<ByteBuffer, HostEvent> hostEvents = reorderedAddedHostEvents;
585 reorderedAddedHostEvents = new HashMap<>();
586 for (HostEvent hostEvent : hostEvents.values()) {
587 addHost(hostEvent);
Ray Milkeyb29e6262014-04-09 16:02:14 -0700588 }
Pavlin Radoslavov74986ce2014-02-20 13:17:20 -0800589 }
590
Pavlin Radoslavov734ff5a2014-02-26 10:20:43 -0800591 /**
592 * Switch discovered event.
593 *
594 * @param switchEvent the switch event.
Ray Milkey269ffb92014-04-03 14:43:30 -0700595 * @param portEvents the corresponding port events for the switch.
Pavlin Radoslavov734ff5a2014-02-26 10:20:43 -0800596 */
Pavlin Radoslavovc1cfde52014-02-19 11:35:29 -0800597 @Override
Pavlin Radoslavov018d5332014-02-19 23:08:35 -0800598 public void putSwitchDiscoveryEvent(SwitchEvent switchEvent,
Ray Milkey269ffb92014-04-03 14:43:30 -0700599 Collection<PortEvent> portEvents) {
600 if (datastore.addSwitch(switchEvent, portEvents)) {
Jonathan Hart92c819f2014-05-30 10:53:30 -0700601 log.debug("Sending add switch: {}", switchEvent);
Ray Milkey269ffb92014-04-03 14:43:30 -0700602 // Send out notification
603 TopologyEvent topologyEvent = new TopologyEvent(switchEvent);
604 eventChannel.addEntry(topologyEvent.getID(), topologyEvent);
Pavlin Radoslavov26d83402014-02-20 15:24:30 -0800605
Ray Milkey269ffb92014-04-03 14:43:30 -0700606 // Send out notification for each port
607 for (PortEvent portEvent : portEvents) {
Jonathan Hart92c819f2014-05-30 10:53:30 -0700608 log.debug("Sending add port: {}", portEvent);
Ray Milkey269ffb92014-04-03 14:43:30 -0700609 topologyEvent = new TopologyEvent(portEvent);
610 eventChannel.addEntry(topologyEvent.getID(), topologyEvent);
611 }
Pavlin Radoslavov26d83402014-02-20 15:24:30 -0800612
Ray Milkey269ffb92014-04-03 14:43:30 -0700613 //
614 // Keep track of the added ports
615 //
616 // Get the old Port Events
617 Map<ByteBuffer, PortEvent> oldPortEvents =
618 discoveredAddedPortEvents.get(switchEvent.getDpid());
Ray Milkeyb29e6262014-04-09 16:02:14 -0700619 if (oldPortEvents == null) {
Ray Milkey269ffb92014-04-03 14:43:30 -0700620 oldPortEvents = new HashMap<>();
Ray Milkeyb29e6262014-04-09 16:02:14 -0700621 }
Pavlin Radoslavov26d83402014-02-20 15:24:30 -0800622
Ray Milkey269ffb92014-04-03 14:43:30 -0700623 // Store the new Port Events in the local cache
624 Map<ByteBuffer, PortEvent> newPortEvents = new HashMap<>();
625 for (PortEvent portEvent : portEvents) {
626 ByteBuffer id = portEvent.getIDasByteBuffer();
627 newPortEvents.put(id, portEvent);
628 }
629 discoveredAddedPortEvents.put(switchEvent.getDpid(),
630 newPortEvents);
Pavlin Radoslavov26d83402014-02-20 15:24:30 -0800631
Ray Milkey269ffb92014-04-03 14:43:30 -0700632 //
633 // Extract the removed ports
634 //
635 List<PortEvent> removedPortEvents = new LinkedList<>();
636 for (Map.Entry<ByteBuffer, PortEvent> entry : oldPortEvents.entrySet()) {
637 ByteBuffer key = entry.getKey();
638 PortEvent portEvent = entry.getValue();
Ray Milkeyb29e6262014-04-09 16:02:14 -0700639 if (!newPortEvents.containsKey(key)) {
Ray Milkey269ffb92014-04-03 14:43:30 -0700640 removedPortEvents.add(portEvent);
Ray Milkeyb29e6262014-04-09 16:02:14 -0700641 }
Ray Milkey269ffb92014-04-03 14:43:30 -0700642 }
643
644 // Cleanup old removed ports
Ray Milkeyb29e6262014-04-09 16:02:14 -0700645 for (PortEvent portEvent : removedPortEvents) {
Ray Milkey269ffb92014-04-03 14:43:30 -0700646 removePortDiscoveryEvent(portEvent);
Ray Milkeyb29e6262014-04-09 16:02:14 -0700647 }
Ray Milkey269ffb92014-04-03 14:43:30 -0700648 }
Pavlin Radoslavovc1cfde52014-02-19 11:35:29 -0800649 }
650
Pavlin Radoslavov734ff5a2014-02-26 10:20:43 -0800651 /**
Yuta HIGUCHIbc67a052014-06-30 10:37:09 -0700652 * {@inheritDoc}
653 * <p/>
654 * Called by {@link TopologyPublisher.SwitchCleanup} thread.
Pavlin Radoslavov734ff5a2014-02-26 10:20:43 -0800655 */
Pavlin Radoslavovc1cfde52014-02-19 11:35:29 -0800656 @Override
Pavlin Radoslavov6ea84a42014-02-19 15:50:01 -0800657 public void removeSwitchDiscoveryEvent(SwitchEvent switchEvent) {
Ray Milkey269ffb92014-04-03 14:43:30 -0700658 // Get the old Port Events
659 Map<ByteBuffer, PortEvent> oldPortEvents =
660 discoveredAddedPortEvents.get(switchEvent.getDpid());
Ray Milkeyb29e6262014-04-09 16:02:14 -0700661 if (oldPortEvents == null) {
Ray Milkey269ffb92014-04-03 14:43:30 -0700662 oldPortEvents = new HashMap<>();
Ray Milkeyb29e6262014-04-09 16:02:14 -0700663 }
Pavlin Radoslavov018d5332014-02-19 23:08:35 -0800664
Ray Milkey269ffb92014-04-03 14:43:30 -0700665 if (datastore.deactivateSwitch(switchEvent, oldPortEvents.values())) {
Jonathan Hart92c819f2014-05-30 10:53:30 -0700666 log.debug("Sending remove switch: {}", switchEvent);
Ray Milkey269ffb92014-04-03 14:43:30 -0700667 // Send out notification
668 eventChannel.removeEntry(switchEvent.getID());
Pavlin Radoslavov018d5332014-02-19 23:08:35 -0800669
Ray Milkey269ffb92014-04-03 14:43:30 -0700670 //
671 // Send out notification for each port.
672 //
673 // NOTE: We don't use removePortDiscoveryEvent() for the cleanup,
674 // because it will attempt to remove the port from the database,
675 // and the deactiveSwitch() call above already removed all ports.
676 //
Ray Milkeyb29e6262014-04-09 16:02:14 -0700677 for (PortEvent portEvent : oldPortEvents.values()) {
Jonathan Hart92c819f2014-05-30 10:53:30 -0700678 log.debug("Sending remove port:", portEvent);
Ray Milkey269ffb92014-04-03 14:43:30 -0700679 eventChannel.removeEntry(portEvent.getID());
Ray Milkeyb29e6262014-04-09 16:02:14 -0700680 }
Ray Milkey269ffb92014-04-03 14:43:30 -0700681 discoveredAddedPortEvents.remove(switchEvent.getDpid());
Pavlin Radoslavov26d83402014-02-20 15:24:30 -0800682
Ray Milkey269ffb92014-04-03 14:43:30 -0700683 // Cleanup for each link
684 Map<ByteBuffer, LinkEvent> oldLinkEvents =
685 discoveredAddedLinkEvents.get(switchEvent.getDpid());
686 if (oldLinkEvents != null) {
687 for (LinkEvent linkEvent : new ArrayList<>(oldLinkEvents.values())) {
688 removeLinkDiscoveryEvent(linkEvent);
689 }
690 discoveredAddedLinkEvents.remove(switchEvent.getDpid());
691 }
Pavlin Radoslavov26d83402014-02-20 15:24:30 -0800692
Yuta HIGUCHIbfc77f02014-07-14 22:50:25 -0700693 // Cleanup for each host
694 Map<ByteBuffer, HostEvent> oldHostEvents =
695 discoveredAddedHostEvents.get(switchEvent.getDpid());
696 if (oldHostEvents != null) {
697 for (HostEvent hostEvent : new ArrayList<>(oldHostEvents.values())) {
698 removeHostDiscoveryEvent(hostEvent);
Ray Milkey269ffb92014-04-03 14:43:30 -0700699 }
Yuta HIGUCHIbfc77f02014-07-14 22:50:25 -0700700 discoveredAddedHostEvents.remove(switchEvent.getDpid());
Ray Milkey269ffb92014-04-03 14:43:30 -0700701 }
702 }
Pavlin Radoslavovc1cfde52014-02-19 11:35:29 -0800703 }
704
Pavlin Radoslavov734ff5a2014-02-26 10:20:43 -0800705 /**
706 * Port discovered event.
707 *
708 * @param portEvent the port event.
709 */
Pavlin Radoslavovc1cfde52014-02-19 11:35:29 -0800710 @Override
Pavlin Radoslavov6ea84a42014-02-19 15:50:01 -0800711 public void putPortDiscoveryEvent(PortEvent portEvent) {
Ray Milkey269ffb92014-04-03 14:43:30 -0700712 if (datastore.addPort(portEvent)) {
Jonathan Hart92c819f2014-05-30 10:53:30 -0700713 log.debug("Sending add port: {}", portEvent);
Ray Milkey269ffb92014-04-03 14:43:30 -0700714 // Send out notification
715 TopologyEvent topologyEvent = new TopologyEvent(portEvent);
716 eventChannel.addEntry(topologyEvent.getID(), topologyEvent);
Pavlin Radoslavov26d83402014-02-20 15:24:30 -0800717
Ray Milkey269ffb92014-04-03 14:43:30 -0700718 // Store the new Port Event in the local cache
719 Map<ByteBuffer, PortEvent> oldPortEvents =
720 discoveredAddedPortEvents.get(portEvent.getDpid());
721 if (oldPortEvents == null) {
722 oldPortEvents = new HashMap<>();
723 discoveredAddedPortEvents.put(portEvent.getDpid(),
724 oldPortEvents);
725 }
726 ByteBuffer id = portEvent.getIDasByteBuffer();
727 oldPortEvents.put(id, portEvent);
728 }
Pavlin Radoslavovc1cfde52014-02-19 11:35:29 -0800729 }
730
Pavlin Radoslavov734ff5a2014-02-26 10:20:43 -0800731 /**
732 * Port removed event.
733 *
734 * @param portEvent the port event.
735 */
Pavlin Radoslavovc1cfde52014-02-19 11:35:29 -0800736 @Override
Pavlin Radoslavov6ea84a42014-02-19 15:50:01 -0800737 public void removePortDiscoveryEvent(PortEvent portEvent) {
Ray Milkey269ffb92014-04-03 14:43:30 -0700738 if (datastore.deactivatePort(portEvent)) {
Jonathan Hart92c819f2014-05-30 10:53:30 -0700739 log.debug("Sending remove port: {}", portEvent);
Ray Milkey269ffb92014-04-03 14:43:30 -0700740 // Send out notification
741 eventChannel.removeEntry(portEvent.getID());
Pavlin Radoslavov26d83402014-02-20 15:24:30 -0800742
Ray Milkey269ffb92014-04-03 14:43:30 -0700743 // Cleanup the Port Event from the local cache
744 Map<ByteBuffer, PortEvent> oldPortEvents =
745 discoveredAddedPortEvents.get(portEvent.getDpid());
746 if (oldPortEvents != null) {
747 ByteBuffer id = portEvent.getIDasByteBuffer();
748 oldPortEvents.remove(id);
749 }
Pavlin Radoslavov26d83402014-02-20 15:24:30 -0800750
Ray Milkey269ffb92014-04-03 14:43:30 -0700751 // Cleanup for the incoming link
752 Map<ByteBuffer, LinkEvent> oldLinkEvents =
753 discoveredAddedLinkEvents.get(portEvent.getDpid());
754 if (oldLinkEvents != null) {
755 for (LinkEvent linkEvent : new ArrayList<>(oldLinkEvents.values())) {
Yuta HIGUCHIbf0a8712014-06-30 18:59:46 -0700756 if (linkEvent.getDst().equals(portEvent.getSwitchPort())) {
Ray Milkey269ffb92014-04-03 14:43:30 -0700757 removeLinkDiscoveryEvent(linkEvent);
758 // XXX If we change our model to allow multiple Link on
759 // a Port, this loop must be fixed to allow continuing.
760 break;
761 }
762 }
763 }
Pavlin Radoslavov26d83402014-02-20 15:24:30 -0800764
Yuta HIGUCHIbfc77f02014-07-14 22:50:25 -0700765 // Cleanup for the connected hosts
Ray Milkey269ffb92014-04-03 14:43:30 -0700766 // TODO: The implementation below is probably wrong
Yuta HIGUCHIbfc77f02014-07-14 22:50:25 -0700767 List<HostEvent> removedHostEvents = new LinkedList<>();
768 Map<ByteBuffer, HostEvent> oldHostEvents =
769 discoveredAddedHostEvents.get(portEvent.getDpid());
770 if (oldHostEvents != null) {
771 for (HostEvent hostEvent : new ArrayList<>(oldHostEvents.values())) {
772 for (SwitchPort swp : hostEvent.getAttachmentPoints()) {
Yuta HIGUCHIbf0a8712014-06-30 18:59:46 -0700773 if (swp.equals(portEvent.getSwitchPort())) {
Yuta HIGUCHIbfc77f02014-07-14 22:50:25 -0700774 removedHostEvents.add(hostEvent);
Ray Milkey269ffb92014-04-03 14:43:30 -0700775 }
776 }
777 }
Yuta HIGUCHIbfc77f02014-07-14 22:50:25 -0700778 for (HostEvent hostEvent : removedHostEvents) {
779 removeHostDiscoveryEvent(hostEvent);
Ray Milkeyb29e6262014-04-09 16:02:14 -0700780 }
Ray Milkey269ffb92014-04-03 14:43:30 -0700781 }
782 }
Pavlin Radoslavovc1cfde52014-02-19 11:35:29 -0800783 }
784
Pavlin Radoslavov734ff5a2014-02-26 10:20:43 -0800785 /**
786 * Link discovered event.
787 *
788 * @param linkEvent the link event.
789 */
Pavlin Radoslavovc1cfde52014-02-19 11:35:29 -0800790 @Override
Pavlin Radoslavov6ea84a42014-02-19 15:50:01 -0800791 public void putLinkDiscoveryEvent(LinkEvent linkEvent) {
Ray Milkey269ffb92014-04-03 14:43:30 -0700792 if (datastore.addLink(linkEvent)) {
Jonathan Hart92c819f2014-05-30 10:53:30 -0700793 log.debug("Sending add link: {}", linkEvent);
Ray Milkey269ffb92014-04-03 14:43:30 -0700794 // Send out notification
795 TopologyEvent topologyEvent = new TopologyEvent(linkEvent);
796 eventChannel.addEntry(topologyEvent.getID(), topologyEvent);
Pavlin Radoslavov26d83402014-02-20 15:24:30 -0800797
Ray Milkey269ffb92014-04-03 14:43:30 -0700798 // Store the new Link Event in the local cache
799 Map<ByteBuffer, LinkEvent> oldLinkEvents =
800 discoveredAddedLinkEvents.get(linkEvent.getDst().getDpid());
801 if (oldLinkEvents == null) {
802 oldLinkEvents = new HashMap<>();
803 discoveredAddedLinkEvents.put(linkEvent.getDst().getDpid(),
804 oldLinkEvents);
805 }
806 ByteBuffer id = linkEvent.getIDasByteBuffer();
807 oldLinkEvents.put(id, linkEvent);
808 }
Pavlin Radoslavovc1cfde52014-02-19 11:35:29 -0800809 }
810
Pavlin Radoslavov734ff5a2014-02-26 10:20:43 -0800811 /**
812 * Link removed event.
813 *
814 * @param linkEvent the link event.
815 */
Pavlin Radoslavovc1cfde52014-02-19 11:35:29 -0800816 @Override
Pavlin Radoslavov6ea84a42014-02-19 15:50:01 -0800817 public void removeLinkDiscoveryEvent(LinkEvent linkEvent) {
Ray Milkey269ffb92014-04-03 14:43:30 -0700818 if (datastore.removeLink(linkEvent)) {
Jonathan Hart92c819f2014-05-30 10:53:30 -0700819 log.debug("Sending remove link: {}", linkEvent);
Ray Milkey269ffb92014-04-03 14:43:30 -0700820 // Send out notification
821 eventChannel.removeEntry(linkEvent.getID());
Pavlin Radoslavov26d83402014-02-20 15:24:30 -0800822
Ray Milkey269ffb92014-04-03 14:43:30 -0700823 // Cleanup the Link Event from the local cache
824 Map<ByteBuffer, LinkEvent> oldLinkEvents =
825 discoveredAddedLinkEvents.get(linkEvent.getDst().getDpid());
826 if (oldLinkEvents != null) {
827 ByteBuffer id = linkEvent.getIDasByteBuffer();
828 oldLinkEvents.remove(id);
829 }
830 }
Pavlin Radoslavovc1cfde52014-02-19 11:35:29 -0800831 }
Jonathan Hart22eb9882014-02-11 15:52:59 -0800832
Pavlin Radoslavov734ff5a2014-02-26 10:20:43 -0800833 /**
Yuta HIGUCHIbfc77f02014-07-14 22:50:25 -0700834 * Host discovered event.
Pavlin Radoslavov734ff5a2014-02-26 10:20:43 -0800835 *
Yuta HIGUCHIbfc77f02014-07-14 22:50:25 -0700836 * @param hostEvent the host event.
Pavlin Radoslavov734ff5a2014-02-26 10:20:43 -0800837 */
Pavlin Radoslavovc1cfde52014-02-19 11:35:29 -0800838 @Override
Yuta HIGUCHIbfc77f02014-07-14 22:50:25 -0700839 public void putHostDiscoveryEvent(HostEvent hostEvent) {
840 if (datastore.addHost(hostEvent)) {
Ray Milkey269ffb92014-04-03 14:43:30 -0700841 // Send out notification
Yuta HIGUCHIbfc77f02014-07-14 22:50:25 -0700842 TopologyEvent topologyEvent = new TopologyEvent(hostEvent);
Ray Milkey269ffb92014-04-03 14:43:30 -0700843 eventChannel.addEntry(topologyEvent.getID(), topologyEvent);
Yuta HIGUCHIbfc77f02014-07-14 22:50:25 -0700844 log.debug("Put the host info into the cache of the topology. mac {}", hostEvent.getMac());
Ray Milkey269ffb92014-04-03 14:43:30 -0700845
Yuta HIGUCHIbfc77f02014-07-14 22:50:25 -0700846 // Store the new Host Event in the local cache
Ray Milkey269ffb92014-04-03 14:43:30 -0700847 // TODO: The implementation below is probably wrong
Yuta HIGUCHIbfc77f02014-07-14 22:50:25 -0700848 for (SwitchPort swp : hostEvent.getAttachmentPoints()) {
849 Map<ByteBuffer, HostEvent> oldHostEvents =
850 discoveredAddedHostEvents.get(swp.getDpid());
851 if (oldHostEvents == null) {
852 oldHostEvents = new HashMap<>();
853 discoveredAddedHostEvents.put(swp.getDpid(),
854 oldHostEvents);
Ray Milkey269ffb92014-04-03 14:43:30 -0700855 }
Yuta HIGUCHIbfc77f02014-07-14 22:50:25 -0700856 ByteBuffer id = hostEvent.getIDasByteBuffer();
857 oldHostEvents.put(id, hostEvent);
Ray Milkey269ffb92014-04-03 14:43:30 -0700858 }
859 }
Pavlin Radoslavovc1cfde52014-02-19 11:35:29 -0800860 }
Jonathan Hart22eb9882014-02-11 15:52:59 -0800861
Pavlin Radoslavov734ff5a2014-02-26 10:20:43 -0800862 /**
Yuta HIGUCHIbfc77f02014-07-14 22:50:25 -0700863 * Host removed event.
Pavlin Radoslavov734ff5a2014-02-26 10:20:43 -0800864 *
Yuta HIGUCHIbfc77f02014-07-14 22:50:25 -0700865 * @param hostEvent the host event.
Pavlin Radoslavov734ff5a2014-02-26 10:20:43 -0800866 */
Pavlin Radoslavovc1cfde52014-02-19 11:35:29 -0800867 @Override
Yuta HIGUCHIbfc77f02014-07-14 22:50:25 -0700868 public void removeHostDiscoveryEvent(HostEvent hostEvent) {
869 if (datastore.removeHost(hostEvent)) {
Ray Milkey269ffb92014-04-03 14:43:30 -0700870 // Send out notification
Yuta HIGUCHIbfc77f02014-07-14 22:50:25 -0700871 eventChannel.removeEntry(hostEvent.getID());
872 log.debug("Remove the host info into the cache of the topology. mac {}", hostEvent.getMac());
Pavlin Radoslavov26d83402014-02-20 15:24:30 -0800873
Yuta HIGUCHIbfc77f02014-07-14 22:50:25 -0700874 // Cleanup the Host Event from the local cache
Ray Milkey269ffb92014-04-03 14:43:30 -0700875 // TODO: The implementation below is probably wrong
Yuta HIGUCHIbfc77f02014-07-14 22:50:25 -0700876 ByteBuffer id = ByteBuffer.wrap(hostEvent.getID());
877 for (SwitchPort swp : hostEvent.getAttachmentPoints()) {
878 Map<ByteBuffer, HostEvent> oldHostEvents =
879 discoveredAddedHostEvents.get(swp.getDpid());
880 if (oldHostEvents != null) {
881 oldHostEvents.remove(id);
Ray Milkey269ffb92014-04-03 14:43:30 -0700882 }
883 }
884 }
Pavlin Radoslavovc1cfde52014-02-19 11:35:29 -0800885 }
Jonathan Hart22eb9882014-02-11 15:52:59 -0800886
Yuta HIGUCHI8b389a72014-07-18 13:50:00 -0700887 //
888 // Methods to update topology replica
889 //
890
Pavlin Radoslavov734ff5a2014-02-26 10:20:43 -0800891 /**
Yuta HIGUCHI7926ba32014-07-09 11:39:32 -0700892 * Adds a switch to the topology replica.
Pavlin Radoslavov734ff5a2014-02-26 10:20:43 -0800893 *
Yuta HIGUCHIbf0a8712014-06-30 18:59:46 -0700894 * @param switchEvent the SwitchEvent with the switch to add.
Pavlin Radoslavov734ff5a2014-02-26 10:20:43 -0800895 */
Yuta HIGUCHIbc67a052014-06-30 10:37:09 -0700896 @GuardedBy("topology.writeLock")
Pavlin Radoslavov74986ce2014-02-20 13:17:20 -0800897 private void addSwitch(SwitchEvent switchEvent) {
Yuta HIGUCHI8b389a72014-07-18 13:50:00 -0700898 if (log.isDebugEnabled()) {
899 SwitchEvent sw = topology.getSwitchEvent(switchEvent.getDpid());
900 if (sw != null) {
901 log.debug("Update {}", switchEvent);
902 } else {
903 log.debug("Added {}", switchEvent);
904 }
Ray Milkey269ffb92014-04-03 14:43:30 -0700905 }
Yuta HIGUCHI8b389a72014-07-18 13:50:00 -0700906 topology.putSwitch(switchEvent.freeze());
Ray Milkey269ffb92014-04-03 14:43:30 -0700907 apiAddedSwitchEvents.add(switchEvent);
Pavlin Radoslavov3c9cc552014-02-20 09:58:38 -0800908 }
909
Pavlin Radoslavov734ff5a2014-02-26 10:20:43 -0800910 /**
Yuta HIGUCHI7926ba32014-07-09 11:39:32 -0700911 * Removes a switch from the topology replica.
Yuta HIGUCHIbf0a8712014-06-30 18:59:46 -0700912 * <p/>
913 * It will call {@link #removePort(PortEvent)} for each ports on this switch.
Pavlin Radoslavov734ff5a2014-02-26 10:20:43 -0800914 *
Yuta HIGUCHIbf0a8712014-06-30 18:59:46 -0700915 * @param switchEvent the SwitchEvent with the switch to remove.
Pavlin Radoslavov734ff5a2014-02-26 10:20:43 -0800916 */
Yuta HIGUCHIbc67a052014-06-30 10:37:09 -0700917 @GuardedBy("topology.writeLock")
Pavlin Radoslavov74986ce2014-02-20 13:17:20 -0800918 private void removeSwitch(SwitchEvent switchEvent) {
Yuta HIGUCHI8b389a72014-07-18 13:50:00 -0700919 final Dpid dpid = switchEvent.getDpid();
920
921 SwitchEvent swInTopo = topology.getSwitchEvent(dpid);
922 if (swInTopo == null) {
Ray Milkey269ffb92014-04-03 14:43:30 -0700923 log.warn("Switch {} already removed, ignoring", switchEvent);
924 return;
925 }
Pavlin Radoslavov3c9cc552014-02-20 09:58:38 -0800926
Ray Milkey269ffb92014-04-03 14:43:30 -0700927 //
928 // Remove all Ports on the Switch
929 //
930 ArrayList<PortEvent> portsToRemove = new ArrayList<>();
Yuta HIGUCHI8b389a72014-07-18 13:50:00 -0700931 for (Port port : topology.getPorts(dpid)) {
Ray Milkey269ffb92014-04-03 14:43:30 -0700932 log.warn("Port {} on Switch {} should be removed prior to removing Switch. Removing Port now.",
933 port, switchEvent);
Yuta HIGUCHI8b389a72014-07-18 13:50:00 -0700934 PortEvent portEvent = new PortEvent(port.asSwitchPort());
Ray Milkey269ffb92014-04-03 14:43:30 -0700935 portsToRemove.add(portEvent);
936 }
Ray Milkeyb29e6262014-04-09 16:02:14 -0700937 for (PortEvent portEvent : portsToRemove) {
Ray Milkey269ffb92014-04-03 14:43:30 -0700938 removePort(portEvent);
Ray Milkeyb29e6262014-04-09 16:02:14 -0700939 }
Pavlin Radoslavov3c9cc552014-02-20 09:58:38 -0800940
Yuta HIGUCHI8b389a72014-07-18 13:50:00 -0700941 log.debug("Removed {}", swInTopo);
942 topology.removeSwitch(dpid);
943 apiRemovedSwitchEvents.add(swInTopo);
Pavlin Radoslavov3c9cc552014-02-20 09:58:38 -0800944 }
945
Pavlin Radoslavov734ff5a2014-02-26 10:20:43 -0800946 /**
Yuta HIGUCHI7926ba32014-07-09 11:39:32 -0700947 * Adds a port to the topology replica.
Pavlin Radoslavov734ff5a2014-02-26 10:20:43 -0800948 *
Yuta HIGUCHIbf0a8712014-06-30 18:59:46 -0700949 * @param portEvent the PortEvent with the port to add.
Pavlin Radoslavov734ff5a2014-02-26 10:20:43 -0800950 */
Yuta HIGUCHIbc67a052014-06-30 10:37:09 -0700951 @GuardedBy("topology.writeLock")
Pavlin Radoslavov3c9cc552014-02-20 09:58:38 -0800952 private void addPort(PortEvent portEvent) {
Jonathan Harte37e4e22014-05-13 19:12:02 -0700953 Switch sw = topology.getSwitch(portEvent.getDpid());
Ray Milkey269ffb92014-04-03 14:43:30 -0700954 if (sw == null) {
Jonathan Hartf1675202014-05-23 14:59:07 -0700955 log.debug("{} reordered because switch is null", portEvent);
Ray Milkey269ffb92014-04-03 14:43:30 -0700956 // Reordered event: delay the event in local cache
957 ByteBuffer id = portEvent.getIDasByteBuffer();
958 reorderedAddedPortEvents.put(id, portEvent);
959 return;
960 }
Pavlin Radoslavov3c9cc552014-02-20 09:58:38 -0800961
Yuta HIGUCHI8b389a72014-07-18 13:50:00 -0700962 if (log.isDebugEnabled()) {
963 PortEvent port = topology.getPortEvent(portEvent.getSwitchPort());
964 if (port != null) {
965 log.debug("Update {}", portEvent);
966 } else {
967 log.debug("Added {}", portEvent);
968 }
Ray Milkey269ffb92014-04-03 14:43:30 -0700969 }
Yuta HIGUCHI8b389a72014-07-18 13:50:00 -0700970 topology.putPort(portEvent.freeze());
Ray Milkey269ffb92014-04-03 14:43:30 -0700971 apiAddedPortEvents.add(portEvent);
Pavlin Radoslavov3c9cc552014-02-20 09:58:38 -0800972 }
973
Pavlin Radoslavov734ff5a2014-02-26 10:20:43 -0800974 /**
Yuta HIGUCHI7926ba32014-07-09 11:39:32 -0700975 * Removes a port from the topology replica.
Yuta HIGUCHIbf0a8712014-06-30 18:59:46 -0700976 * <p/>
Yuta HIGUCHI8b389a72014-07-18 13:50:00 -0700977 * It will remove attachment points from each hosts on this port
Yuta HIGUCHIbf0a8712014-06-30 18:59:46 -0700978 * and call {@link #removeLink(LinkEvent)} for each links on this port.
Pavlin Radoslavov734ff5a2014-02-26 10:20:43 -0800979 *
Yuta HIGUCHIbf0a8712014-06-30 18:59:46 -0700980 * @param portEvent the PortEvent with the port to remove.
Pavlin Radoslavov734ff5a2014-02-26 10:20:43 -0800981 */
Yuta HIGUCHIbc67a052014-06-30 10:37:09 -0700982 @GuardedBy("topology.writeLock")
Pavlin Radoslavov3c9cc552014-02-20 09:58:38 -0800983 private void removePort(PortEvent portEvent) {
Yuta HIGUCHI8b389a72014-07-18 13:50:00 -0700984 SwitchEvent sw = topology.getSwitchEvent(portEvent.getDpid());
Ray Milkey269ffb92014-04-03 14:43:30 -0700985 if (sw == null) {
986 log.warn("Parent Switch for Port {} already removed, ignoring",
987 portEvent);
988 return;
989 }
Pavlin Radoslavov3c9cc552014-02-20 09:58:38 -0800990
Yuta HIGUCHI8b389a72014-07-18 13:50:00 -0700991 final SwitchPort switchPort = portEvent.getSwitchPort();
992 PortEvent portInTopo = topology.getPortEvent(switchPort);
993 if (portInTopo == null) {
Ray Milkey269ffb92014-04-03 14:43:30 -0700994 log.warn("Port {} already removed, ignoring", portEvent);
995 return;
996 }
Pavlin Radoslavov3c9cc552014-02-20 09:58:38 -0800997
Ray Milkey269ffb92014-04-03 14:43:30 -0700998 //
Yuta HIGUCHI8b389a72014-07-18 13:50:00 -0700999 // Remove all Host attachment points bound to this Port
Ray Milkey269ffb92014-04-03 14:43:30 -07001000 //
Yuta HIGUCHI8b389a72014-07-18 13:50:00 -07001001 List<HostEvent> hostsToUpdate = new ArrayList<>();
1002 for (Host host : topology.getHosts(switchPort)) {
1003 log.debug("Removing Host {} on Port {}", host, portInTopo);
1004 HostEvent hostEvent = topology.getHostEvent(host.getMacAddress());
1005 hostsToUpdate.add(hostEvent);
Ray Milkey269ffb92014-04-03 14:43:30 -07001006 }
Yuta HIGUCHI8b389a72014-07-18 13:50:00 -07001007 for (HostEvent hostEvent : hostsToUpdate) {
1008 HostEvent newHostEvent = new HostEvent(hostEvent);
1009 newHostEvent.removeAttachmentPoint(switchPort);
1010 newHostEvent.freeze();
1011
1012 // TODO should this event be fired inside #addHost?
1013 if (newHostEvent.getAttachmentPoints().isEmpty()) {
1014 // No more attachment point left -> remove Host
1015 removeHost(hostEvent);
1016 } else {
1017 // Update Host
1018 addHost(newHostEvent);
1019 }
Ray Milkeyb29e6262014-04-09 16:02:14 -07001020 }
Pavlin Radoslavov3c9cc552014-02-20 09:58:38 -08001021
Ray Milkey269ffb92014-04-03 14:43:30 -07001022 //
1023 // Remove all Links connected to the Port
1024 //
1025 Set<Link> links = new HashSet<>();
Yuta HIGUCHI8b389a72014-07-18 13:50:00 -07001026 links.addAll(topology.getOutgoingLinks(switchPort));
1027 links.addAll(topology.getIncomingLinks(switchPort));
Ray Milkey269ffb92014-04-03 14:43:30 -07001028 for (Link link : links) {
Ray Milkeyb29e6262014-04-09 16:02:14 -07001029 if (link == null) {
Ray Milkey269ffb92014-04-03 14:43:30 -07001030 continue;
Ray Milkeyb29e6262014-04-09 16:02:14 -07001031 }
Yuta HIGUCHI8b389a72014-07-18 13:50:00 -07001032 LinkEvent linkEvent = topology.getLinkEvent(link.getLinkTuple());
1033 if (linkEvent != null) {
1034 log.debug("Removing Link {} on Port {}", link, portInTopo);
1035 removeLink(linkEvent);
1036 }
Ray Milkeyb29e6262014-04-09 16:02:14 -07001037 }
Pavlin Radoslavov3c9cc552014-02-20 09:58:38 -08001038
Yuta HIGUCHI8b389a72014-07-18 13:50:00 -07001039 // Remove the Port from Topology
1040 log.debug("Removed {}", portInTopo);
1041 topology.removePort(switchPort);
Pavlin Radoslavov74986ce2014-02-20 13:17:20 -08001042
Yuta HIGUCHI8b389a72014-07-18 13:50:00 -07001043 apiRemovedPortEvents.add(portInTopo);
Pavlin Radoslavov3c9cc552014-02-20 09:58:38 -08001044 }
1045
Pavlin Radoslavov734ff5a2014-02-26 10:20:43 -08001046 /**
Yuta HIGUCHI7926ba32014-07-09 11:39:32 -07001047 * Adds a link to the topology replica.
Yuta HIGUCHIbf0a8712014-06-30 18:59:46 -07001048 * <p/>
Yuta HIGUCHI8b389a72014-07-18 13:50:00 -07001049 * It will remove attachment points from each hosts using the same ports.
Pavlin Radoslavov734ff5a2014-02-26 10:20:43 -08001050 *
Yuta HIGUCHIbf0a8712014-06-30 18:59:46 -07001051 * @param linkEvent the LinkEvent with the link to add.
Pavlin Radoslavov734ff5a2014-02-26 10:20:43 -08001052 */
Yuta HIGUCHIbc67a052014-06-30 10:37:09 -07001053 @GuardedBy("topology.writeLock")
Pavlin Radoslavov3c9cc552014-02-20 09:58:38 -08001054 private void addLink(LinkEvent linkEvent) {
Yuta HIGUCHI8b389a72014-07-18 13:50:00 -07001055 PortEvent srcPort = topology.getPortEvent(linkEvent.getSrc());
1056 PortEvent dstPort = topology.getPortEvent(linkEvent.getDst());
Ray Milkey269ffb92014-04-03 14:43:30 -07001057 if ((srcPort == null) || (dstPort == null)) {
Jonathan Hartf1675202014-05-23 14:59:07 -07001058 log.debug("{} reordered because {} port is null", linkEvent,
1059 (srcPort == null) ? "src" : "dst");
1060
Yuta HIGUCHIbf0a8712014-06-30 18:59:46 -07001061 // XXX domain knowledge: port must be present before link.
Ray Milkey269ffb92014-04-03 14:43:30 -07001062 // Reordered event: delay the event in local cache
1063 ByteBuffer id = linkEvent.getIDasByteBuffer();
1064 reorderedAddedLinkEvents.put(id, linkEvent);
1065 return;
1066 }
Pavlin Radoslavov3c9cc552014-02-20 09:58:38 -08001067
Yuta HIGUCHI8b389a72014-07-18 13:50:00 -07001068 // XXX domain knowledge: Sanity check: Port cannot have both Link and Host
Yuta HIGUCHIbf0a8712014-06-30 18:59:46 -07001069 // FIXME potentially local replica may not be up-to-date yet due to HZ delay.
1070 // may need to manage local truth and use them instead.
Yuta HIGUCHI8b389a72014-07-18 13:50:00 -07001071 if (topology.getLinkEvent(linkEvent.getLinkTuple()) == null) {
1072 // Only check for existing Host when adding new Link.
Pavlin Radoslavov3c9cc552014-02-20 09:58:38 -08001073
Yuta HIGUCHI8b389a72014-07-18 13:50:00 -07001074 // Remove all Hosts attached to the ports on both ends
1075
1076 Set<HostEvent> hostsToUpdate = new TreeSet<>(new Comparator<HostEvent>() {
1077 // comparison only using ID(=MAC)
1078 @Override
1079 public int compare(HostEvent o1, HostEvent o2) {
1080 return Long.compare(o1.getMac().toLong(), o2.getMac().toLong());
1081 }
1082 });
1083
1084 List<SwitchPort> portsToCheck = Arrays.asList(
1085 srcPort.getSwitchPort(),
1086 dstPort.getSwitchPort());
1087
1088 // Enumerate Host which needs to be updated by this Link add event
1089 for (SwitchPort port : portsToCheck) {
1090 for (Host host : topology.getHosts(port)) {
Yuta HIGUCHIbfc77f02014-07-14 22:50:25 -07001091 log.error("Host {} on Port {} should have been removed prior to adding Link {}",
1092 host, port, linkEvent);
Yuta HIGUCHI8b389a72014-07-18 13:50:00 -07001093
1094 HostEvent hostEvent = topology.getHostEvent(host.getMacAddress());
1095 hostsToUpdate.add(hostEvent);
Ray Milkey269ffb92014-04-03 14:43:30 -07001096 }
1097 }
Yuta HIGUCHI8b389a72014-07-18 13:50:00 -07001098 // remove attachment point from them.
1099 for (HostEvent hostEvent : hostsToUpdate) {
1100 // remove port from attachment point and update
1101 HostEvent newHostEvent = new HostEvent(hostEvent);
1102 newHostEvent.removeAttachmentPoint(srcPort.getSwitchPort());
1103 newHostEvent.removeAttachmentPoint(dstPort.getSwitchPort());
1104 newHostEvent.freeze();
1105
1106 // TODO should this event be fired inside #addHost?
1107 if (newHostEvent.getAttachmentPoints().isEmpty()) {
1108 // No more attachment point left -> remove Host
1109 removeHost(hostEvent);
1110 } else {
1111 // Update Host
1112 addHost(newHostEvent);
1113 }
Ray Milkeyb29e6262014-04-09 16:02:14 -07001114 }
Ray Milkey269ffb92014-04-03 14:43:30 -07001115 }
Pavlin Radoslavov74986ce2014-02-20 13:17:20 -08001116
Yuta HIGUCHI8b389a72014-07-18 13:50:00 -07001117 if (log.isDebugEnabled()) {
1118 LinkEvent link = topology.getLinkEvent(linkEvent.getLinkTuple());
1119 if (link != null) {
1120 log.debug("Update {}", linkEvent);
1121 } else {
1122 log.debug("Added {}", linkEvent);
1123 }
1124 }
1125 topology.putLink(linkEvent.freeze());
Ray Milkey269ffb92014-04-03 14:43:30 -07001126 apiAddedLinkEvents.add(linkEvent);
Pavlin Radoslavov3c9cc552014-02-20 09:58:38 -08001127 }
1128
Pavlin Radoslavov734ff5a2014-02-26 10:20:43 -08001129 /**
Yuta HIGUCHI7926ba32014-07-09 11:39:32 -07001130 * Removes a link from the topology replica.
Pavlin Radoslavov734ff5a2014-02-26 10:20:43 -08001131 *
Yuta HIGUCHIbf0a8712014-06-30 18:59:46 -07001132 * @param linkEvent the LinkEvent with the link to remove.
Pavlin Radoslavov734ff5a2014-02-26 10:20:43 -08001133 */
Yuta HIGUCHIbc67a052014-06-30 10:37:09 -07001134 @GuardedBy("topology.writeLock")
Pavlin Radoslavov3c9cc552014-02-20 09:58:38 -08001135 private void removeLink(LinkEvent linkEvent) {
Yuta HIGUCHI8f3dfa32014-06-25 00:14:25 -07001136 Port srcPort = topology.getPort(linkEvent.getSrc().getDpid(),
Yuta HIGUCHIb1e2ab72014-06-30 11:01:31 -07001137 linkEvent.getSrc().getPortNumber());
Ray Milkey269ffb92014-04-03 14:43:30 -07001138 if (srcPort == null) {
1139 log.warn("Src Port for Link {} already removed, ignoring",
1140 linkEvent);
1141 return;
1142 }
Pavlin Radoslavov3c9cc552014-02-20 09:58:38 -08001143
Yuta HIGUCHI8f3dfa32014-06-25 00:14:25 -07001144 Port dstPort = topology.getPort(linkEvent.getDst().getDpid(),
Yuta HIGUCHIb1e2ab72014-06-30 11:01:31 -07001145 linkEvent.getDst().getPortNumber());
Ray Milkey269ffb92014-04-03 14:43:30 -07001146 if (dstPort == null) {
1147 log.warn("Dst Port for Link {} already removed, ignoring",
1148 linkEvent);
1149 return;
1150 }
Pavlin Radoslavov3c9cc552014-02-20 09:58:38 -08001151
Yuta HIGUCHI8b389a72014-07-18 13:50:00 -07001152 LinkEvent linkInTopo = topology.getLinkEvent(linkEvent.getLinkTuple(),
1153 linkEvent.getType());
1154 if (linkInTopo == null) {
1155 log.warn("Link {} already removed, ignoring", linkEvent);
1156 return;
Ray Milkey269ffb92014-04-03 14:43:30 -07001157 }
Jonathan Hart25bd53e2014-04-30 23:44:09 -07001158
Yuta HIGUCHI8b389a72014-07-18 13:50:00 -07001159 if (log.isDebugEnabled()) {
1160 // only do sanity check on debug level
1161
1162 Link linkIn = dstPort.getIncomingLink(linkEvent.getType());
1163 if (linkIn == null) {
1164 log.warn("Link {} already removed on destination Port", linkEvent);
1165 }
1166 Link linkOut = srcPort.getOutgoingLink(linkEvent.getType());
1167 if (linkOut == null) {
1168 log.warn("Link {} already removed on src Port", linkEvent);
1169 }
Jonathan Hart25bd53e2014-04-30 23:44:09 -07001170 }
Pavlin Radoslavov74986ce2014-02-20 13:17:20 -08001171
Yuta HIGUCHI8b389a72014-07-18 13:50:00 -07001172 log.debug("Removed {}", linkInTopo);
1173 topology.removeLink(linkEvent.getLinkTuple(), linkEvent.getType());
1174 apiRemovedLinkEvents.add(linkInTopo);
Pavlin Radoslavov3c9cc552014-02-20 09:58:38 -08001175 }
1176
Pavlin Radoslavov734ff5a2014-02-26 10:20:43 -08001177 /**
Yuta HIGUCHIbfc77f02014-07-14 22:50:25 -07001178 * Adds a host to the topology replica.
Ray Milkey269ffb92014-04-03 14:43:30 -07001179 * <p/>
Yuta HIGUCHIbfc77f02014-07-14 22:50:25 -07001180 * TODO: Host-related work is incomplete.
Pavlin Radoslavov734ff5a2014-02-26 10:20:43 -08001181 * TODO: Eventually, we might need to consider reordering
Yuta HIGUCHI8b389a72014-07-18 13:50:00 -07001182 * or {@link #addLink(LinkEvent)} and {@link #addHost(HostEvent)} events on the same port.
Pavlin Radoslavov734ff5a2014-02-26 10:20:43 -08001183 *
Yuta HIGUCHIbfc77f02014-07-14 22:50:25 -07001184 * @param hostEvent the HostEvent with the host to add.
Pavlin Radoslavov734ff5a2014-02-26 10:20:43 -08001185 */
Yuta HIGUCHIbc67a052014-06-30 10:37:09 -07001186 @GuardedBy("topology.writeLock")
Yuta HIGUCHIbfc77f02014-07-14 22:50:25 -07001187 private void addHost(HostEvent hostEvent) {
Pavlin Radoslavov3c9cc552014-02-20 09:58:38 -08001188
Yuta HIGUCHI8b389a72014-07-18 13:50:00 -07001189 // TODO Decide how to handle update scenario.
1190 // If the new HostEvent has less attachment point compared to
1191 // existing HostEvent, what should the event be?
1192 // - AddHostEvent with some attachment point removed? (current behavior)
Pavlin Radoslavov3c9cc552014-02-20 09:58:38 -08001193
Yuta HIGUCHI8b389a72014-07-18 13:50:00 -07001194 // create unfrozen copy
1195 // for removing attachment points which already has a link
1196 HostEvent modifiedHostEvent = new HostEvent(hostEvent);
Pavlin Radoslavov3c9cc552014-02-20 09:58:38 -08001197
Yuta HIGUCHI8b389a72014-07-18 13:50:00 -07001198 // Verify each attachment point
Ray Milkey269ffb92014-04-03 14:43:30 -07001199 boolean attachmentFound = false;
Yuta HIGUCHIbfc77f02014-07-14 22:50:25 -07001200 for (SwitchPort swp : hostEvent.getAttachmentPoints()) {
1201 // XXX domain knowledge: Port must exist before Host
Yuta HIGUCHIbf0a8712014-06-30 18:59:46 -07001202 // but this knowledge cannot be pushed down to driver.
1203
Ray Milkey269ffb92014-04-03 14:43:30 -07001204 // Attached Ports must exist
Yuta HIGUCHIb1e2ab72014-06-30 11:01:31 -07001205 Port port = topology.getPort(swp.getDpid(), swp.getPortNumber());
Ray Milkey269ffb92014-04-03 14:43:30 -07001206 if (port == null) {
Yuta HIGUCHI8b389a72014-07-18 13:50:00 -07001207 log.debug("{} reordered because port {} was not there", hostEvent, swp);
Ray Milkey269ffb92014-04-03 14:43:30 -07001208 // Reordered event: delay the event in local cache
Yuta HIGUCHIbfc77f02014-07-14 22:50:25 -07001209 ByteBuffer id = hostEvent.getIDasByteBuffer();
1210 reorderedAddedHostEvents.put(id, hostEvent);
Yuta HIGUCHI8b389a72014-07-18 13:50:00 -07001211 return; // should not continue if re-applying later
Ray Milkey269ffb92014-04-03 14:43:30 -07001212 }
1213 // Attached Ports must not have Link
1214 if (port.getOutgoingLink() != null ||
1215 port.getIncomingLink() != null) {
Yuta HIGUCHI8b389a72014-07-18 13:50:00 -07001216 log.warn("Link (Out:{},In:{}) exist on the attachment point. "
1217 + "Ignoring this attachmentpoint ({}) from {}.",
1218 port.getOutgoingLink(), port.getIncomingLink(),
1219 swp, modifiedHostEvent);
1220 // FIXME Should either reject, reorder this HostEvent,
1221 // or remove attachment point from given HostEvent
1222 // Removing attachment point from given HostEvent for now.
1223 modifiedHostEvent.removeAttachmentPoint(swp);
Ray Milkey269ffb92014-04-03 14:43:30 -07001224 continue;
1225 }
1226
Ray Milkey269ffb92014-04-03 14:43:30 -07001227 attachmentFound = true;
1228 }
1229
Yuta HIGUCHIbfc77f02014-07-14 22:50:25 -07001230 // Update the host in the topology
Ray Milkey269ffb92014-04-03 14:43:30 -07001231 if (attachmentFound) {
Yuta HIGUCHI8b389a72014-07-18 13:50:00 -07001232 if (modifiedHostEvent.getAttachmentPoints().isEmpty()) {
1233 log.warn("No valid attachment point left. Ignoring."
1234 + "original: {}, modified: {}", hostEvent, modifiedHostEvent);
1235 // TODO Should we call #removeHost to trigger remove event?
1236 // only if this call is update.
1237 return;
1238 }
1239
1240 if (log.isDebugEnabled()) {
1241 HostEvent host = topology.getHostEvent(hostEvent.getMac());
1242 if (host != null) {
1243 log.debug("Update {}", modifiedHostEvent);
1244 } else {
1245 log.debug("Added {}", modifiedHostEvent);
1246 }
1247 }
1248 topology.putHost(modifiedHostEvent.freeze());
1249 apiAddedHostEvents.add(modifiedHostEvent);
Ray Milkey269ffb92014-04-03 14:43:30 -07001250 }
Pavlin Radoslavov3c9cc552014-02-20 09:58:38 -08001251 }
1252
Pavlin Radoslavov734ff5a2014-02-26 10:20:43 -08001253 /**
Yuta HIGUCHIbfc77f02014-07-14 22:50:25 -07001254 * Removes a host from the topology replica.
Ray Milkey269ffb92014-04-03 14:43:30 -07001255 * <p/>
Yuta HIGUCHIbfc77f02014-07-14 22:50:25 -07001256 * TODO: Host-related work is incomplete.
Pavlin Radoslavov734ff5a2014-02-26 10:20:43 -08001257 *
Yuta HIGUCHIbfc77f02014-07-14 22:50:25 -07001258 * @param hostEvent the Host Event with the host to remove.
Pavlin Radoslavov734ff5a2014-02-26 10:20:43 -08001259 */
Yuta HIGUCHIbc67a052014-06-30 10:37:09 -07001260 @GuardedBy("topology.writeLock")
Yuta HIGUCHIbfc77f02014-07-14 22:50:25 -07001261 private void removeHost(HostEvent hostEvent) {
Yuta HIGUCHI8b389a72014-07-18 13:50:00 -07001262
1263 final MACAddress mac = hostEvent.getMac();
1264 HostEvent hostInTopo = topology.getHostEvent(mac);
1265 if (hostInTopo == null) {
Yuta HIGUCHIbfc77f02014-07-14 22:50:25 -07001266 log.warn("Host {} already removed, ignoring", hostEvent);
Ray Milkey269ffb92014-04-03 14:43:30 -07001267 return;
1268 }
Pavlin Radoslavov3c9cc552014-02-20 09:58:38 -08001269
Yuta HIGUCHI8b389a72014-07-18 13:50:00 -07001270 log.debug("Removed {}", hostInTopo);
1271 topology.removeHost(mac);
1272 apiRemovedHostEvents.add(hostInTopo);
Pavlin Radoslavov3c9cc552014-02-20 09:58:38 -08001273 }
Jonathan Hart22eb9882014-02-11 15:52:59 -08001274
Pavlin Radoslavovc1cfde52014-02-19 11:35:29 -08001275 /**
Pavlin Radoslavov734ff5a2014-02-26 10:20:43 -08001276 * Read the whole topology from the database.
1277 *
1278 * @return a collection of EventEntry-encapsulated Topology Events for
1279 * the whole topology.
1280 */
Pavlin Radoslavov018d5332014-02-19 23:08:35 -08001281 private Collection<EventEntry<TopologyEvent>> readWholeTopologyFromDB() {
Ray Milkey269ffb92014-04-03 14:43:30 -07001282 Collection<EventEntry<TopologyEvent>> collection =
1283 new LinkedList<EventEntry<TopologyEvent>>();
Pavlin Radoslavov018d5332014-02-19 23:08:35 -08001284
Ray Milkey269ffb92014-04-03 14:43:30 -07001285 // XXX May need to clear whole topology first, depending on
1286 // how we initially subscribe to replication events
Pavlin Radoslavovc1cfde52014-02-19 11:35:29 -08001287
Ray Milkey269ffb92014-04-03 14:43:30 -07001288 // Add all active switches
1289 for (KVSwitch sw : KVSwitch.getAllSwitches()) {
1290 if (sw.getStatus() != KVSwitch.STATUS.ACTIVE) {
1291 continue;
1292 }
Pavlin Radoslavov018d5332014-02-19 23:08:35 -08001293
Yuta HIGUCHIe2a4e172014-07-03 10:50:39 -07001294 SwitchEvent switchEvent = new SwitchEvent(new Dpid(sw.getDpid()));
Ray Milkey269ffb92014-04-03 14:43:30 -07001295 TopologyEvent topologyEvent = new TopologyEvent(switchEvent);
1296 EventEntry<TopologyEvent> eventEntry =
1297 new EventEntry<TopologyEvent>(EventEntry.Type.ENTRY_ADD,
1298 topologyEvent);
1299 collection.add(eventEntry);
1300 }
Yuta HIGUCHIa536e762014-02-17 21:47:28 -08001301
Ray Milkey269ffb92014-04-03 14:43:30 -07001302 // Add all active ports
1303 for (KVPort p : KVPort.getAllPorts()) {
1304 if (p.getStatus() != KVPort.STATUS.ACTIVE) {
1305 continue;
1306 }
Pavlin Radoslavov018d5332014-02-19 23:08:35 -08001307
Yuta HIGUCHIe2a4e172014-07-03 10:50:39 -07001308 PortEvent portEvent = new PortEvent(
1309 new Dpid(p.getDpid()),
1310 new PortNumber(p.getNumber().shortValue()));
Ray Milkey269ffb92014-04-03 14:43:30 -07001311 TopologyEvent topologyEvent = new TopologyEvent(portEvent);
1312 EventEntry<TopologyEvent> eventEntry =
1313 new EventEntry<TopologyEvent>(EventEntry.Type.ENTRY_ADD,
1314 topologyEvent);
1315 collection.add(eventEntry);
1316 }
Yuta HIGUCHIa536e762014-02-17 21:47:28 -08001317
TeruU28adcc32014-04-15 17:57:35 -07001318 for (KVDevice d : KVDevice.getAllDevices()) {
Yuta HIGUCHIbfc77f02014-07-14 22:50:25 -07001319 HostEvent devEvent = new HostEvent(MACAddress.valueOf(d.getMac()));
TeruU28adcc32014-04-15 17:57:35 -07001320 for (byte[] portId : d.getAllPortIds()) {
Jonathan Hartc00f5c22014-06-10 15:14:40 -07001321 devEvent.addAttachmentPoint(
1322 new SwitchPort(KVPort.getDpidFromKey(portId),
1323 KVPort.getNumberFromKey(portId)));
TeruU28adcc32014-04-15 17:57:35 -07001324 }
1325 }
Pavlin Radoslavovc1cfde52014-02-19 11:35:29 -08001326
Ray Milkey269ffb92014-04-03 14:43:30 -07001327 for (KVLink l : KVLink.getAllLinks()) {
Yuta HIGUCHIe2a4e172014-07-03 10:50:39 -07001328 LinkEvent linkEvent = new LinkEvent(
1329 new SwitchPort(l.getSrc().dpid, l.getSrc().number),
1330 new SwitchPort(l.getDst().dpid, l.getDst().number));
Ray Milkey269ffb92014-04-03 14:43:30 -07001331 TopologyEvent topologyEvent = new TopologyEvent(linkEvent);
1332 EventEntry<TopologyEvent> eventEntry =
1333 new EventEntry<TopologyEvent>(EventEntry.Type.ENTRY_ADD,
1334 topologyEvent);
1335 collection.add(eventEntry);
1336 }
Pavlin Radoslavov018d5332014-02-19 23:08:35 -08001337
Ray Milkey269ffb92014-04-03 14:43:30 -07001338 return collection;
Pavlin Radoslavovc1cfde52014-02-19 11:35:29 -08001339 }
Jonathan Hart062a2e82014-02-03 09:41:57 -08001340}