blob: 9092e98cf54ccfe538065b0d76fe3523e1e7d66b [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;
Pavlin Radoslavovd4f40372014-07-18 16:58:40 -070025import net.onrc.onos.core.metrics.OnosMetrics;
26import net.onrc.onos.core.metrics.OnosMetrics.MetricsComponent;
27import net.onrc.onos.core.metrics.OnosMetrics.MetricsFeature;
Jonathan Hartdeda0ba2014-04-03 11:14:12 -070028import net.onrc.onos.core.registry.IControllerRegistryService;
Yuta HIGUCHI8f3dfa32014-06-25 00:14:25 -070029import net.onrc.onos.core.util.Dpid;
Jonathan Hart23701d12014-04-03 10:45:48 -070030import net.onrc.onos.core.util.EventEntry;
Yuta HIGUCHI5c8cbeb2014-06-27 11:13:48 -070031import net.onrc.onos.core.util.SwitchPort;
32
Jonathan Hart062a2e82014-02-03 09:41:57 -080033import org.slf4j.Logger;
34import org.slf4j.LoggerFactory;
35
Pavlin Radoslavovd4f40372014-07-18 16:58:40 -070036import com.codahale.metrics.Gauge;
37import com.codahale.metrics.Meter;
Pavlin Radoslavov4eaab992014-07-03 18:39:42 -070038
Yuta HIGUCHI181d34d2014-02-05 15:05:46 -080039/**
Jonathan Harte37e4e22014-05-13 19:12:02 -070040 * The TopologyManager receives topology updates from the southbound discovery
41 * modules and from other ONOS instances. These updates are processed and
42 * applied to the in-memory topology instance.
Ray Milkey269ffb92014-04-03 14:43:30 -070043 * <p/>
Yuta HIGUCHI4bfdd532014-02-07 13:47:36 -080044 * - Maintain Invariant/Relationships between Topology Objects.
Ray Milkey269ffb92014-04-03 14:43:30 -070045 * <p/>
Yuta HIGUCHI765cd0d2014-02-06 12:46:41 -080046 * TODO To be synchronized based on TopologyEvent Notification.
Ray Milkey269ffb92014-04-03 14:43:30 -070047 * <p/>
Yuta HIGUCHIcb951982014-02-11 13:31:44 -080048 * TODO TBD: Caller is expected to maintain parent/child calling order. Parent
Yuta HIGUCHI1c700102014-02-12 16:30:52 -080049 * Object must exist before adding sub component(Add Switch -> Port).
Ray Milkey269ffb92014-04-03 14:43:30 -070050 * <p/>
Yuta HIGUCHI4bfdd532014-02-07 13:47:36 -080051 * TODO TBD: This class may delay the requested change to handle event
52 * re-ordering. e.g.) Link Add came in, but Switch was not there.
Yuta HIGUCHI181d34d2014-02-05 15:05:46 -080053 */
Pavlin Radoslavovb46f89b2014-08-15 23:00:26 -070054public class TopologyManager {
Jonathan Hart062a2e82014-02-03 09:41:57 -080055
Yuta HIGUCHI80829d12014-02-05 20:16:56 -080056 private static final Logger log = LoggerFactory
Ray Milkey269ffb92014-04-03 14:43:30 -070057 .getLogger(TopologyManager.class);
Yuta HIGUCHIcd922f42014-02-11 18:59:11 -080058
Pavlin Radoslavov721a2e02014-02-14 23:40:14 -080059 private IEventChannel<byte[], TopologyEvent> eventChannel;
Jonathan Hart10a7e2b2014-02-21 18:30:08 -080060 public static final String EVENT_CHANNEL_NAME = "onos.topology";
Pavlin Radoslavov721a2e02014-02-14 23:40:14 -080061 private EventHandler eventHandler = new EventHandler();
62
Jonathan Harte37e4e22014-05-13 19:12:02 -070063 private final TopologyImpl topology = new TopologyImpl();
Pavlin Radoslavovd7b792e2014-08-01 02:47:47 -070064 private TopologyEventPreprocessor eventPreprocessor;
Pavlin Radoslavov8a44b782014-08-07 12:53:27 -070065 private CopyOnWriteArrayList<ITopologyListener> topologyListeners =
66 new CopyOnWriteArrayList<>();
Pavlin Radoslavov054cd592014-08-07 20:57:16 -070067 private CopyOnWriteArrayList<ITopologyListener> newTopologyListeners =
68 new CopyOnWriteArrayList<>();
Yuta HIGUCHI181d34d2014-02-05 15:05:46 -080069
Pavlin Radoslavov706add22014-02-20 12:15:59 -080070 //
Pavlin Radoslavovd4f40372014-07-18 16:58:40 -070071 // Metrics
72 //
73 private static final MetricsComponent METRICS_COMPONENT =
74 OnosMetrics.registerComponent("Topology");
75 private static final MetricsFeature METRICS_FEATURE_EVENT_NOTIFICATION =
76 METRICS_COMPONENT.registerFeature("EventNotification");
77 //
Pavlin Radoslavovc49917c2014-07-23 12:16:29 -070078 // Timestamp of the last Topology event (ms from the Epoch)
79 private volatile long lastEventTimestampEpochMs = 0;
80 private final Gauge<Long> gaugeLastEventTimestampEpochMs =
Pavlin Radoslavovd4f40372014-07-18 16:58:40 -070081 OnosMetrics.registerMetric(METRICS_COMPONENT,
82 METRICS_FEATURE_EVENT_NOTIFICATION,
Pavlin Radoslavovc49917c2014-07-23 12:16:29 -070083 "LastEventTimestamp.EpochMs",
Pavlin Radoslavovd4f40372014-07-18 16:58:40 -070084 new Gauge<Long>() {
85 @Override
86 public Long getValue() {
Pavlin Radoslavovc49917c2014-07-23 12:16:29 -070087 return lastEventTimestampEpochMs;
Pavlin Radoslavovd4f40372014-07-18 16:58:40 -070088 }
89 });
90 // Rate of the Topology events published to the Topology listeners
91 private final Meter listenerEventRate =
92 OnosMetrics.createMeter(METRICS_COMPONENT,
93 METRICS_FEATURE_EVENT_NOTIFICATION,
94 "ListenerEventRate");
95
96 //
Pavlin Radoslavov8a44b782014-08-07 12:53:27 -070097 // Local state for keeping the last ADD Mastership Event entries.
98 // TODO: In the future, we might have to keep this state somewhere else.
99 //
Yuta HIGUCHId8fd2f52014-09-01 23:19:45 -0700100 private Map<ByteBuffer, MastershipData> lastAddMastershipDataEntries =
Pavlin Radoslavov8a44b782014-08-07 12:53:27 -0700101 new HashMap<>();
102
103 //
Pavlin Radoslavov74986ce2014-02-20 13:17:20 -0800104 // Local state for keeping track of the application event notifications
105 //
Yuta HIGUCHIbc67a052014-06-30 10:37:09 -0700106 // - Queue of events, which will be dispatched to local listeners
107 // on next notification.
Yuta HIGUCHI703696c2014-06-25 20:36:45 -0700108
Yuta HIGUCHId8fd2f52014-09-01 23:19:45 -0700109 private List<MastershipData> apiAddedMastershipDataEntries =
Pavlin Radoslavovcac157d2014-07-31 13:54:08 -0700110 new LinkedList<>();
Yuta HIGUCHId8fd2f52014-09-01 23:19:45 -0700111 private List<MastershipData> apiRemovedMastershipDataEntries =
Pavlin Radoslavovcac157d2014-07-31 13:54:08 -0700112 new LinkedList<>();
Yuta HIGUCHI93d35ea2014-08-31 23:26:13 -0700113 private List<SwitchData> apiAddedSwitchDataEntries = new LinkedList<>();
114 private List<SwitchData> apiRemovedSwitchDataEntries = new LinkedList<>();
115 private List<PortData> apiAddedPortDataEntries = new LinkedList<>();
116 private List<PortData> apiRemovedPortDataEntries = new LinkedList<>();
117 private List<LinkData> apiAddedLinkDataEntries = new LinkedList<>();
118 private List<LinkData> apiRemovedLinkDataEntries = new LinkedList<>();
119 private List<HostData> apiAddedHostDataEntries = new LinkedList<>();
120 private List<HostData> apiRemovedHostDataEntries = new LinkedList<>();
Pavlin Radoslavov74986ce2014-02-20 13:17:20 -0800121
Pavlin Radoslavovc1cfde52014-02-19 11:35:29 -0800122 /**
123 * Constructor.
124 *
Jonathan Harte37e4e22014-05-13 19:12:02 -0700125 * @param registryService the Registry Service to use.
Pavlin Radoslavovc1cfde52014-02-19 11:35:29 -0800126 */
Pavlin Radoslavov8a44b782014-08-07 12:53:27 -0700127 public TopologyManager(IControllerRegistryService registryService) {
Pavlin Radoslavovd7b792e2014-08-01 02:47:47 -0700128 this.eventPreprocessor =
129 new TopologyEventPreprocessor(registryService);
Yuta HIGUCHI80829d12014-02-05 20:16:56 -0800130 }
Yuta HIGUCHI181d34d2014-02-05 15:05:46 -0800131
Pavlin Radoslavovc1cfde52014-02-19 11:35:29 -0800132 /**
Yuta HIGUCHId92b10c2014-08-25 09:30:28 -0700133 * Get the MutableTopology.
Pavlin Radoslavovc1cfde52014-02-19 11:35:29 -0800134 *
Yuta HIGUCHId92b10c2014-08-25 09:30:28 -0700135 * @return the MutableTopology.
Pavlin Radoslavovc1cfde52014-02-19 11:35:29 -0800136 */
Yuta HIGUCHId92b10c2014-08-25 09:30:28 -0700137 MutableTopology getTopology() {
Jonathan Harte37e4e22014-05-13 19:12:02 -0700138 return topology;
Pavlin Radoslavov6d224ee2014-02-18 16:43:15 -0800139 }
140
Yuta HIGUCHI4bfdd532014-02-07 13:47:36 -0800141 /**
Pavlin Radoslavov721a2e02014-02-14 23:40:14 -0800142 * Event handler class.
143 */
Yuta HIGUCHI8b389a72014-07-18 13:50:00 -0700144 class EventHandler extends Thread implements
Ray Milkey269ffb92014-04-03 14:43:30 -0700145 IEventChannelListener<byte[], TopologyEvent> {
146 private BlockingQueue<EventEntry<TopologyEvent>> topologyEvents =
147 new LinkedBlockingQueue<EventEntry<TopologyEvent>>();
Pavlin Radoslavov721a2e02014-02-14 23:40:14 -0800148
Ray Milkey269ffb92014-04-03 14:43:30 -0700149 /**
150 * Startup processing.
151 */
152 private void startup() {
153 //
Pavlin Radoslavovb46f89b2014-08-15 23:00:26 -0700154 // Read all topology state
Ray Milkey269ffb92014-04-03 14:43:30 -0700155 //
Ray Milkey5df613b2014-04-15 10:50:56 -0700156 Collection<TopologyEvent> allTopologyEvents =
Ray Milkey269ffb92014-04-03 14:43:30 -0700157 eventChannel.getAllEntries();
Pavlin Radoslavovd7b792e2014-08-01 02:47:47 -0700158 List<EventEntry<TopologyEvent>> events =
159 new LinkedList<EventEntry<TopologyEvent>>();
Pavlin Radoslavov721a2e02014-02-14 23:40:14 -0800160
Ray Milkey5df613b2014-04-15 10:50:56 -0700161 for (TopologyEvent topologyEvent : allTopologyEvents) {
Ray Milkey269ffb92014-04-03 14:43:30 -0700162 EventEntry<TopologyEvent> eventEntry =
Pavlin Radoslavov8a44b782014-08-07 12:53:27 -0700163 new EventEntry<TopologyEvent>(EventEntry.Type.ENTRY_ADD,
164 topologyEvent);
Pavlin Radoslavovd7b792e2014-08-01 02:47:47 -0700165 events.add(eventEntry);
Ray Milkey269ffb92014-04-03 14:43:30 -0700166 }
Pavlin Radoslavovd7b792e2014-08-01 02:47:47 -0700167 processEvents(events);
Ray Milkey269ffb92014-04-03 14:43:30 -0700168 }
Pavlin Radoslavov721a2e02014-02-14 23:40:14 -0800169
Ray Milkey269ffb92014-04-03 14:43:30 -0700170 /**
171 * Run the thread.
172 */
173 @Override
174 public void run() {
Pavlin Radoslavovd7b792e2014-08-01 02:47:47 -0700175 List<EventEntry<TopologyEvent>> events =
176 new LinkedList<EventEntry<TopologyEvent>>();
Pavlin Radoslavov721a2e02014-02-14 23:40:14 -0800177
Ray Milkey269ffb92014-04-03 14:43:30 -0700178 this.setName("TopologyManager.EventHandler " + this.getId());
179 startup();
Pavlin Radoslavov721a2e02014-02-14 23:40:14 -0800180
Ray Milkey269ffb92014-04-03 14:43:30 -0700181 //
182 // The main loop
183 //
Pavlin Radoslavov8e881a42014-06-24 16:58:07 -0700184 while (true) {
185 try {
186 EventEntry<TopologyEvent> eventEntry =
187 topologyEvents.take();
Pavlin Radoslavovd7b792e2014-08-01 02:47:47 -0700188 events.add(eventEntry);
189 topologyEvents.drainTo(events);
Pavlin Radoslavov721a2e02014-02-14 23:40:14 -0800190
Pavlin Radoslavovd7b792e2014-08-01 02:47:47 -0700191 processEvents(events);
192 events.clear();
Pavlin Radoslavov8e881a42014-06-24 16:58:07 -0700193 } catch (Exception exception) {
194 log.debug("Exception processing Topology Events: ",
195 exception);
Ray Milkey269ffb92014-04-03 14:43:30 -0700196 }
Ray Milkey269ffb92014-04-03 14:43:30 -0700197 }
198 }
Pavlin Radoslavov721a2e02014-02-14 23:40:14 -0800199
Ray Milkey269ffb92014-04-03 14:43:30 -0700200 /**
201 * Process all topology events.
202 *
203 * @param events the events to process.
204 */
Pavlin Radoslavovd7b792e2014-08-01 02:47:47 -0700205 private void processEvents(List<EventEntry<TopologyEvent>> events) {
Pavlin Radoslavovcac157d2014-07-31 13:54:08 -0700206 //
Pavlin Radoslavov054cd592014-08-07 20:57:16 -0700207 // Process pending (new) listeners
208 //
209 processPendingListeners();
210
211 //
Pavlin Radoslavovd7b792e2014-08-01 02:47:47 -0700212 // Pre-process the events
Pavlin Radoslavovcac157d2014-07-31 13:54:08 -0700213 //
Pavlin Radoslavovd7b792e2014-08-01 02:47:47 -0700214 events = eventPreprocessor.processEvents(events);
Pavlin Radoslavov3c9cc552014-02-20 09:58:38 -0800215
Ray Milkey269ffb92014-04-03 14:43:30 -0700216 //
Jonathan Harte37e4e22014-05-13 19:12:02 -0700217 // Lock the topology while it is modified
Ray Milkey269ffb92014-04-03 14:43:30 -0700218 //
Jonathan Harte37e4e22014-05-13 19:12:02 -0700219 topology.acquireWriteLock();
Pavlin Radoslavov8ffb8bf2014-02-20 15:34:26 -0800220
Ray Milkey269ffb92014-04-03 14:43:30 -0700221 try {
Pavlin Radoslavovd7b792e2014-08-01 02:47:47 -0700222 // Apply the events
Ray Milkey269ffb92014-04-03 14:43:30 -0700223 //
Pavlin Radoslavovd7b792e2014-08-01 02:47:47 -0700224 // NOTE: The events are suppose to be in the proper order
225 // to naturally build and update the topology.
Ray Milkey269ffb92014-04-03 14:43:30 -0700226 //
Pavlin Radoslavovd7b792e2014-08-01 02:47:47 -0700227 for (EventEntry<TopologyEvent> event : events) {
Pavlin Radoslavov054cd592014-08-07 20:57:16 -0700228 // Ignore NO-OP events
229 if (event.isNoop()) {
230 continue;
231 }
232
Pavlin Radoslavovd7b792e2014-08-01 02:47:47 -0700233 TopologyEvent topologyEvent = event.eventData();
Yuta HIGUCHI3aca81a2014-02-23 12:41:19 -0800234
Pavlin Radoslavovd7b792e2014-08-01 02:47:47 -0700235 // Get the event itself
Yuta HIGUCHId8fd2f52014-09-01 23:19:45 -0700236 MastershipData mastershipData =
237 topologyEvent.getMastershipData();
Yuta HIGUCHI93d35ea2014-08-31 23:26:13 -0700238 SwitchData switchData = topologyEvent.getSwitchData();
239 PortData portData = topologyEvent.getPortData();
240 LinkData linkData = topologyEvent.getLinkData();
241 HostData hostData = topologyEvent.getHostData();
Pavlin Radoslavovd7b792e2014-08-01 02:47:47 -0700242 boolean wasAdded = false;
Yuta HIGUCHI3aca81a2014-02-23 12:41:19 -0800243
Pavlin Radoslavovd7b792e2014-08-01 02:47:47 -0700244 //
245 // Extract the events
246 //
247 switch (event.eventType()) {
248 case ENTRY_ADD:
Yuta HIGUCHId8fd2f52014-09-01 23:19:45 -0700249 if (mastershipData != null) {
250 wasAdded = addMastershipData(mastershipData);
Pavlin Radoslavovd7b792e2014-08-01 02:47:47 -0700251 }
Yuta HIGUCHI93d35ea2014-08-31 23:26:13 -0700252 if (switchData != null) {
253 wasAdded = addSwitch(switchData);
Pavlin Radoslavovd7b792e2014-08-01 02:47:47 -0700254 }
Yuta HIGUCHI93d35ea2014-08-31 23:26:13 -0700255 if (portData != null) {
256 wasAdded = addPort(portData);
Pavlin Radoslavovd7b792e2014-08-01 02:47:47 -0700257 }
Yuta HIGUCHI93d35ea2014-08-31 23:26:13 -0700258 if (linkData != null) {
259 wasAdded = addLink(linkData);
Pavlin Radoslavovd7b792e2014-08-01 02:47:47 -0700260 }
Yuta HIGUCHI93d35ea2014-08-31 23:26:13 -0700261 if (hostData != null) {
262 wasAdded = addHost(hostData);
Pavlin Radoslavovd7b792e2014-08-01 02:47:47 -0700263 }
264 // If the item wasn't added, probably it was reordered
265 if (!wasAdded) {
266 ByteBuffer id = topologyEvent.getIDasByteBuffer();
267 eventPreprocessor.reorderedEvents.put(id, topologyEvent);
268 }
269 break;
270 case ENTRY_REMOVE:
Yuta HIGUCHId8fd2f52014-09-01 23:19:45 -0700271 if (mastershipData != null) {
272 removeMastershipData(mastershipData);
Pavlin Radoslavovd7b792e2014-08-01 02:47:47 -0700273 }
Yuta HIGUCHI93d35ea2014-08-31 23:26:13 -0700274 if (switchData != null) {
275 removeSwitch(switchData);
Pavlin Radoslavovd7b792e2014-08-01 02:47:47 -0700276 }
Yuta HIGUCHI93d35ea2014-08-31 23:26:13 -0700277 if (portData != null) {
278 removePort(portData);
Pavlin Radoslavovd7b792e2014-08-01 02:47:47 -0700279 }
Yuta HIGUCHI93d35ea2014-08-31 23:26:13 -0700280 if (linkData != null) {
281 removeLink(linkData);
Pavlin Radoslavovd7b792e2014-08-01 02:47:47 -0700282 }
Yuta HIGUCHI93d35ea2014-08-31 23:26:13 -0700283 if (hostData != null) {
284 removeHost(hostData);
Pavlin Radoslavovd7b792e2014-08-01 02:47:47 -0700285 }
286 break;
287 default:
288 log.error("Unknown topology event {}",
289 event.eventType());
290 }
291 }
Ray Milkey269ffb92014-04-03 14:43:30 -0700292 } finally {
293 //
Jonathan Harte37e4e22014-05-13 19:12:02 -0700294 // Topology modifications completed: Release the lock
Ray Milkey269ffb92014-04-03 14:43:30 -0700295 //
Jonathan Harte37e4e22014-05-13 19:12:02 -0700296 topology.releaseWriteLock();
Ray Milkey269ffb92014-04-03 14:43:30 -0700297 }
Yuta HIGUCHI3aca81a2014-02-23 12:41:19 -0800298
Ray Milkey269ffb92014-04-03 14:43:30 -0700299 //
300 // Dispatch the Topology Notification Events to the applications
301 //
Jonathan Harte37e4e22014-05-13 19:12:02 -0700302 dispatchTopologyEvents();
Ray Milkey269ffb92014-04-03 14:43:30 -0700303 }
Pavlin Radoslavov721a2e02014-02-14 23:40:14 -0800304
Ray Milkey269ffb92014-04-03 14:43:30 -0700305 /**
306 * Receive a notification that an entry is added.
307 *
308 * @param value the value for the entry.
309 */
310 @Override
311 public void entryAdded(TopologyEvent value) {
312 EventEntry<TopologyEvent> eventEntry =
313 new EventEntry<TopologyEvent>(EventEntry.Type.ENTRY_ADD,
314 value);
315 topologyEvents.add(eventEntry);
316 }
Pavlin Radoslavov721a2e02014-02-14 23:40:14 -0800317
Ray Milkey269ffb92014-04-03 14:43:30 -0700318 /**
319 * Receive a notification that an entry is removed.
320 *
321 * @param value the value for the entry.
322 */
323 @Override
324 public void entryRemoved(TopologyEvent value) {
325 EventEntry<TopologyEvent> eventEntry =
326 new EventEntry<TopologyEvent>(EventEntry.Type.ENTRY_REMOVE,
327 value);
328 topologyEvents.add(eventEntry);
329 }
Pavlin Radoslavov721a2e02014-02-14 23:40:14 -0800330
Ray Milkey269ffb92014-04-03 14:43:30 -0700331 /**
332 * Receive a notification that an entry is updated.
333 *
334 * @param value the value for the entry.
335 */
336 @Override
337 public void entryUpdated(TopologyEvent value) {
338 // NOTE: The ADD and UPDATE events are processed in same way
339 entryAdded(value);
340 }
Pavlin Radoslavov054cd592014-08-07 20:57:16 -0700341
342 /**
343 * Informs the event handler that a new listener has been added,
344 * and that listener expects the first event to be a snapshot of the
345 * current topology.
346 */
347 void listenerAdded() {
348 //
349 // Generate a NO-OP event so the Event Handler processing can be
350 // triggered to generate in-order a snapshot of the current
351 // topology.
352 // TODO: This is a hack.
353 //
354 EventEntry<TopologyEvent> eventEntry = EventEntry.makeNoop();
355 topologyEvents.add(eventEntry);
356 }
Pavlin Radoslavov721a2e02014-02-14 23:40:14 -0800357 }
358
359 /**
360 * Startup processing.
361 *
362 * @param datagridService the datagrid service to use.
363 */
364 void startup(IDatagridService datagridService) {
Ray Milkey269ffb92014-04-03 14:43:30 -0700365 eventChannel = datagridService.addListener(EVENT_CHANNEL_NAME,
366 eventHandler,
367 byte[].class,
368 TopologyEvent.class);
369 eventHandler.start();
Pavlin Radoslavov721a2e02014-02-14 23:40:14 -0800370 }
371
Pavlin Radoslavov74986ce2014-02-20 13:17:20 -0800372 /**
Pavlin Radoslavov054cd592014-08-07 20:57:16 -0700373 * Adds a listener for topology events.
Pavlin Radoslavov8a44b782014-08-07 12:53:27 -0700374 *
Pavlin Radoslavov054cd592014-08-07 20:57:16 -0700375 * @param listener the listener to add.
376 * @param startFromSnapshot if true, and if the topology is not
377 * empty, the first event should be a snapshot of the current topology.
Pavlin Radoslavov8a44b782014-08-07 12:53:27 -0700378 */
Pavlin Radoslavov054cd592014-08-07 20:57:16 -0700379 void addListener(ITopologyListener listener, boolean startFromSnapshot) {
380 if (startFromSnapshot) {
381 newTopologyListeners.addIfAbsent(listener);
382 eventHandler.listenerAdded();
383 } else {
384 topologyListeners.addIfAbsent(listener);
385 }
Pavlin Radoslavov8a44b782014-08-07 12:53:27 -0700386 }
387
388 /**
Pavlin Radoslavov054cd592014-08-07 20:57:16 -0700389 * Removes a listener for topology events. The listener will no longer
Pavlin Radoslavov8a44b782014-08-07 12:53:27 -0700390 * receive topology events after this call.
391 *
Pavlin Radoslavov054cd592014-08-07 20:57:16 -0700392 * @param listener the listener to remove.
Pavlin Radoslavov8a44b782014-08-07 12:53:27 -0700393 */
Pavlin Radoslavov054cd592014-08-07 20:57:16 -0700394 void removeListener(ITopologyListener listener) {
Pavlin Radoslavov8a44b782014-08-07 12:53:27 -0700395 topologyListeners.remove(listener);
Pavlin Radoslavov054cd592014-08-07 20:57:16 -0700396 newTopologyListeners.remove(listener);
397 }
398
399 /**
400 * Processes pending (new) listeners.
401 * <p>
402 * During the processing, we dispatch Topology Snapshot Events to new
403 * listeners.
404 */
405 private void processPendingListeners() {
406 if (newTopologyListeners.isEmpty()) {
407 return;
408 }
409
410 //
411 // Create the Topology Snapshot Event
412 //
413 TopologyEvents events = null;
Yuta HIGUCHId8fd2f52014-09-01 23:19:45 -0700414 Collection<MastershipData> mastershipDataEntries =
415 lastAddMastershipDataEntries.values();
Yuta HIGUCHI93d35ea2014-08-31 23:26:13 -0700416 Collection<SwitchData> switchDataEntries = topology.getAllSwitchDataEntries();
417 Collection<PortData> portDataEntries = topology.getAllPortDataEntries();
418 Collection<LinkData> linkDataEntries = topology.getAllLinkDataEntries();
419 Collection<HostData> hostDataEntries = topology.getAllHostDataEntries();
Yuta HIGUCHId8fd2f52014-09-01 23:19:45 -0700420 if (!(mastershipDataEntries.isEmpty() &&
Yuta HIGUCHI93d35ea2014-08-31 23:26:13 -0700421 switchDataEntries.isEmpty() &&
422 portDataEntries.isEmpty() &&
423 linkDataEntries.isEmpty() &&
424 hostDataEntries.isEmpty())) {
Yuta HIGUCHId8fd2f52014-09-01 23:19:45 -0700425 events = new TopologyEvents(mastershipDataEntries,
Yuta HIGUCHI93d35ea2014-08-31 23:26:13 -0700426 switchDataEntries,
427 portDataEntries,
428 linkDataEntries,
429 hostDataEntries);
Pavlin Radoslavov054cd592014-08-07 20:57:16 -0700430 }
431
432 //
433 // Dispatch Snapshot Event to each new listener, and keep track
434 // of each processed listener.
435 //
436 // NOTE: We deliver the event only if it is not empty.
437 // NOTE: We need to execute the loop so we can properly
438 // move the new listeners together with the older listeners.
439 //
440 List<ITopologyListener> processedListeners = new LinkedList<>();
441 for (ITopologyListener listener : newTopologyListeners) {
442 processedListeners.add(listener);
443 // Move the new listener together with the rest of the listeners
444 topologyListeners.addIfAbsent(listener);
445
446 // Dispatch the event
447 if (events != null) {
448 listener.topologyEvents(events);
449 }
450 }
451 newTopologyListeners.removeAll(processedListeners);
Pavlin Radoslavov8a44b782014-08-07 12:53:27 -0700452 }
453
454 /**
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() {
Yuta HIGUCHId8fd2f52014-09-01 23:19:45 -0700458 if (apiAddedMastershipDataEntries.isEmpty() &&
459 apiRemovedMastershipDataEntries.isEmpty() &&
Yuta HIGUCHI93d35ea2014-08-31 23:26:13 -0700460 apiAddedSwitchDataEntries.isEmpty() &&
461 apiRemovedSwitchDataEntries.isEmpty() &&
462 apiAddedPortDataEntries.isEmpty() &&
463 apiRemovedPortDataEntries.isEmpty() &&
464 apiAddedLinkDataEntries.isEmpty() &&
465 apiRemovedLinkDataEntries.isEmpty() &&
466 apiAddedHostDataEntries.isEmpty() &&
467 apiRemovedHostDataEntries.isEmpty()) {
Ray Milkey269ffb92014-04-03 14:43:30 -0700468 return; // No events to dispatch
469 }
Pavlin Radoslavov74986ce2014-02-20 13:17:20 -0800470
Ray Milkey269ffb92014-04-03 14:43:30 -0700471 if (log.isDebugEnabled()) {
472 //
473 // Debug statements
474 // TODO: Those statements should be removed in the future
475 //
Yuta HIGUCHId8fd2f52014-09-01 23:19:45 -0700476 for (MastershipData mastershipData : apiAddedMastershipDataEntries) {
Pavlin Radoslavovcac157d2014-07-31 13:54:08 -0700477 log.debug("Dispatch Topology Event: ADDED {}",
Yuta HIGUCHId8fd2f52014-09-01 23:19:45 -0700478 mastershipData);
Pavlin Radoslavovcac157d2014-07-31 13:54:08 -0700479 }
Yuta HIGUCHId8fd2f52014-09-01 23:19:45 -0700480 for (MastershipData mastershipData : apiRemovedMastershipDataEntries) {
Pavlin Radoslavovcac157d2014-07-31 13:54:08 -0700481 log.debug("Dispatch Topology Event: REMOVED {}",
Yuta HIGUCHId8fd2f52014-09-01 23:19:45 -0700482 mastershipData);
Pavlin Radoslavovcac157d2014-07-31 13:54:08 -0700483 }
Yuta HIGUCHI93d35ea2014-08-31 23:26:13 -0700484 for (SwitchData switchData : apiAddedSwitchDataEntries) {
485 log.debug("Dispatch Topology Event: ADDED {}", switchData);
Ray Milkeyb29e6262014-04-09 16:02:14 -0700486 }
Yuta HIGUCHI93d35ea2014-08-31 23:26:13 -0700487 for (SwitchData switchData : apiRemovedSwitchDataEntries) {
488 log.debug("Dispatch Topology Event: REMOVED {}", switchData);
Ray Milkeyb29e6262014-04-09 16:02:14 -0700489 }
Yuta HIGUCHI93d35ea2014-08-31 23:26:13 -0700490 for (PortData portData : apiAddedPortDataEntries) {
491 log.debug("Dispatch Topology Event: ADDED {}", portData);
Ray Milkeyb29e6262014-04-09 16:02:14 -0700492 }
Yuta HIGUCHI93d35ea2014-08-31 23:26:13 -0700493 for (PortData portData : apiRemovedPortDataEntries) {
494 log.debug("Dispatch Topology Event: REMOVED {}", portData);
Ray Milkeyb29e6262014-04-09 16:02:14 -0700495 }
Yuta HIGUCHI93d35ea2014-08-31 23:26:13 -0700496 for (LinkData linkData : apiAddedLinkDataEntries) {
497 log.debug("Dispatch Topology Event: ADDED {}", linkData);
Ray Milkeyb29e6262014-04-09 16:02:14 -0700498 }
Yuta HIGUCHI93d35ea2014-08-31 23:26:13 -0700499 for (LinkData linkData : apiRemovedLinkDataEntries) {
500 log.debug("Dispatch Topology Event: REMOVED {}", linkData);
Ray Milkeyb29e6262014-04-09 16:02:14 -0700501 }
Yuta HIGUCHI93d35ea2014-08-31 23:26:13 -0700502 for (HostData hostData : apiAddedHostDataEntries) {
503 log.debug("Dispatch Topology Event: ADDED {}", hostData);
Ray Milkeyb29e6262014-04-09 16:02:14 -0700504 }
Yuta HIGUCHI93d35ea2014-08-31 23:26:13 -0700505 for (HostData hostData : apiRemovedHostDataEntries) {
506 log.debug("Dispatch Topology Event: REMOVED {}", hostData);
Ray Milkeyb29e6262014-04-09 16:02:14 -0700507 }
Ray Milkey269ffb92014-04-03 14:43:30 -0700508 }
adminbc181552014-02-21 18:36:42 -0800509
Pavlin Radoslavovd4f40372014-07-18 16:58:40 -0700510 //
511 // Update the metrics
512 //
513 long totalEvents =
Yuta HIGUCHId8fd2f52014-09-01 23:19:45 -0700514 apiAddedMastershipDataEntries.size() + apiRemovedMastershipDataEntries.size() +
Yuta HIGUCHI93d35ea2014-08-31 23:26:13 -0700515 apiAddedSwitchDataEntries.size() + apiRemovedSwitchDataEntries.size() +
516 apiAddedPortDataEntries.size() + apiRemovedPortDataEntries.size() +
517 apiAddedLinkDataEntries.size() + apiRemovedLinkDataEntries.size() +
518 apiAddedHostDataEntries.size() + apiRemovedHostDataEntries.size();
Pavlin Radoslavovd4f40372014-07-18 16:58:40 -0700519 this.listenerEventRate.mark(totalEvents);
Pavlin Radoslavovc49917c2014-07-23 12:16:29 -0700520 this.lastEventTimestampEpochMs = System.currentTimeMillis();
Pavlin Radoslavovd4f40372014-07-18 16:58:40 -0700521
522 //
Pavlin Radoslavov054cd592014-08-07 20:57:16 -0700523 // Allocate the events to deliver.
524 //
Pavlin Radoslavov054cd592014-08-07 20:57:16 -0700525 TopologyEvents events = new TopologyEvents(
Yuta HIGUCHId8fd2f52014-09-01 23:19:45 -0700526 apiAddedMastershipDataEntries,
527 apiRemovedMastershipDataEntries,
Yuta HIGUCHI93d35ea2014-08-31 23:26:13 -0700528 apiAddedSwitchDataEntries,
529 apiRemovedSwitchDataEntries,
530 apiAddedPortDataEntries,
531 apiRemovedPortDataEntries,
532 apiAddedLinkDataEntries,
533 apiRemovedLinkDataEntries,
534 apiAddedHostDataEntries,
535 apiRemovedHostDataEntries);
Pavlin Radoslavov054cd592014-08-07 20:57:16 -0700536
537 //
Ray Milkey269ffb92014-04-03 14:43:30 -0700538 // Deliver the events
Pavlin Radoslavovd4f40372014-07-18 16:58:40 -0700539 //
Jonathan Harte37e4e22014-05-13 19:12:02 -0700540 for (ITopologyListener listener : this.topologyListeners) {
Pavlin Radoslavov4eaab992014-07-03 18:39:42 -0700541 listener.topologyEvents(events);
Ray Milkey269ffb92014-04-03 14:43:30 -0700542 }
Pavlin Radoslavov74986ce2014-02-20 13:17:20 -0800543
Ray Milkey269ffb92014-04-03 14:43:30 -0700544 //
545 // Cleanup
546 //
Yuta HIGUCHId8fd2f52014-09-01 23:19:45 -0700547 apiAddedMastershipDataEntries.clear();
548 apiRemovedMastershipDataEntries.clear();
Yuta HIGUCHI93d35ea2014-08-31 23:26:13 -0700549 apiAddedSwitchDataEntries.clear();
550 apiRemovedSwitchDataEntries.clear();
551 apiAddedPortDataEntries.clear();
552 apiRemovedPortDataEntries.clear();
553 apiAddedLinkDataEntries.clear();
554 apiRemovedLinkDataEntries.clear();
555 apiAddedHostDataEntries.clear();
556 apiRemovedHostDataEntries.clear();
Pavlin Radoslavov74986ce2014-02-20 13:17:20 -0800557 }
558
Yuta HIGUCHI8b389a72014-07-18 13:50:00 -0700559 //
560 // Methods to update topology replica
561 //
562
Pavlin Radoslavov734ff5a2014-02-26 10:20:43 -0800563 /**
Pavlin Radoslavovd7b792e2014-08-01 02:47:47 -0700564 * Adds Switch Mastership event.
Pavlin Radoslavov695f8952014-07-23 16:57:01 -0700565 *
Yuta HIGUCHId8fd2f52014-09-01 23:19:45 -0700566 * @param mastershipData the MastershipData to process.
Pavlin Radoslavovd7b792e2014-08-01 02:47:47 -0700567 * @return true if the item was successfully added, otherwise false.
Pavlin Radoslavov695f8952014-07-23 16:57:01 -0700568 */
Pavlin Radoslavovcac157d2014-07-31 13:54:08 -0700569 @GuardedBy("topology.writeLock")
Yuta HIGUCHId8fd2f52014-09-01 23:19:45 -0700570 private boolean addMastershipData(MastershipData mastershipData) {
571 log.debug("Added Mastership event {}", mastershipData);
572 lastAddMastershipDataEntries.put(mastershipData.getIDasByteBuffer(),
573 mastershipData);
574 apiAddedMastershipDataEntries.add(mastershipData);
Pavlin Radoslavovd7b792e2014-08-01 02:47:47 -0700575 return true;
Pavlin Radoslavov695f8952014-07-23 16:57:01 -0700576 }
577
578 /**
Pavlin Radoslavovd7b792e2014-08-01 02:47:47 -0700579 * Removes Switch Mastership event.
Pavlin Radoslavov695f8952014-07-23 16:57:01 -0700580 *
Yuta HIGUCHId8fd2f52014-09-01 23:19:45 -0700581 * @param mastershipData the MastershipData to process.
Pavlin Radoslavov695f8952014-07-23 16:57:01 -0700582 */
Pavlin Radoslavovcac157d2014-07-31 13:54:08 -0700583 @GuardedBy("topology.writeLock")
Yuta HIGUCHId8fd2f52014-09-01 23:19:45 -0700584 private void removeMastershipData(MastershipData mastershipData) {
585 log.debug("Removed Mastership event {}", mastershipData);
586 lastAddMastershipDataEntries.remove(mastershipData.getIDasByteBuffer());
587 apiRemovedMastershipDataEntries.add(mastershipData);
Pavlin Radoslavov695f8952014-07-23 16:57:01 -0700588 }
589
590 /**
Yuta HIGUCHI7926ba32014-07-09 11:39:32 -0700591 * Adds a switch to the topology replica.
Pavlin Radoslavov734ff5a2014-02-26 10:20:43 -0800592 *
Yuta HIGUCHI93d35ea2014-08-31 23:26:13 -0700593 * @param switchData the SwitchData with the switch to add.
Pavlin Radoslavovd7b792e2014-08-01 02:47:47 -0700594 * @return true if the item was successfully added, otherwise false.
Pavlin Radoslavov734ff5a2014-02-26 10:20:43 -0800595 */
Yuta HIGUCHIbc67a052014-06-30 10:37:09 -0700596 @GuardedBy("topology.writeLock")
Yuta HIGUCHI93d35ea2014-08-31 23:26:13 -0700597 private boolean addSwitch(SwitchData switchData) {
Yuta HIGUCHI8b389a72014-07-18 13:50:00 -0700598 if (log.isDebugEnabled()) {
Yuta HIGUCHI93d35ea2014-08-31 23:26:13 -0700599 SwitchData sw = topology.getSwitchData(switchData.getDpid());
Yuta HIGUCHI8b389a72014-07-18 13:50:00 -0700600 if (sw != null) {
Yuta HIGUCHI93d35ea2014-08-31 23:26:13 -0700601 log.debug("Update {}", switchData);
Yuta HIGUCHI8b389a72014-07-18 13:50:00 -0700602 } else {
Yuta HIGUCHI93d35ea2014-08-31 23:26:13 -0700603 log.debug("Added {}", switchData);
Yuta HIGUCHI8b389a72014-07-18 13:50:00 -0700604 }
Ray Milkey269ffb92014-04-03 14:43:30 -0700605 }
Yuta HIGUCHI93d35ea2014-08-31 23:26:13 -0700606 topology.putSwitch(switchData.freeze());
607 apiAddedSwitchDataEntries.add(switchData);
Pavlin Radoslavovd7b792e2014-08-01 02:47:47 -0700608 return true;
Pavlin Radoslavov3c9cc552014-02-20 09:58:38 -0800609 }
610
Pavlin Radoslavov734ff5a2014-02-26 10:20:43 -0800611 /**
Yuta HIGUCHI7926ba32014-07-09 11:39:32 -0700612 * Removes a switch from the topology replica.
Yuta HIGUCHIbf0a8712014-06-30 18:59:46 -0700613 * <p/>
Yuta HIGUCHI93d35ea2014-08-31 23:26:13 -0700614 * It will call {@link #removePort(PortData)} for each ports on this
Pavlin Radoslavovd7b792e2014-08-01 02:47:47 -0700615 * switch.
Pavlin Radoslavov734ff5a2014-02-26 10:20:43 -0800616 *
Yuta HIGUCHI93d35ea2014-08-31 23:26:13 -0700617 * @param switchData the SwitchData with the switch to remove.
Pavlin Radoslavov734ff5a2014-02-26 10:20:43 -0800618 */
Yuta HIGUCHIbc67a052014-06-30 10:37:09 -0700619 @GuardedBy("topology.writeLock")
Yuta HIGUCHI93d35ea2014-08-31 23:26:13 -0700620 private void removeSwitch(SwitchData switchData) {
621 final Dpid dpid = switchData.getDpid();
Yuta HIGUCHI8b389a72014-07-18 13:50:00 -0700622
Yuta HIGUCHI93d35ea2014-08-31 23:26:13 -0700623 SwitchData swInTopo = topology.getSwitchData(dpid);
Yuta HIGUCHI8b389a72014-07-18 13:50:00 -0700624 if (swInTopo == null) {
Yuta HIGUCHI93d35ea2014-08-31 23:26:13 -0700625 log.warn("Switch {} already removed, ignoring", switchData);
Ray Milkey269ffb92014-04-03 14:43:30 -0700626 return;
627 }
Pavlin Radoslavov3c9cc552014-02-20 09:58:38 -0800628
Ray Milkey269ffb92014-04-03 14:43:30 -0700629 //
630 // Remove all Ports on the Switch
631 //
Yuta HIGUCHI93d35ea2014-08-31 23:26:13 -0700632 ArrayList<PortData> portsToRemove = new ArrayList<>();
Yuta HIGUCHI8b389a72014-07-18 13:50:00 -0700633 for (Port port : topology.getPorts(dpid)) {
Ray Milkey269ffb92014-04-03 14:43:30 -0700634 log.warn("Port {} on Switch {} should be removed prior to removing Switch. Removing Port now.",
Yuta HIGUCHI93d35ea2014-08-31 23:26:13 -0700635 port, switchData);
636 PortData portData = new PortData(port.getSwitchPort());
637 portsToRemove.add(portData);
Ray Milkey269ffb92014-04-03 14:43:30 -0700638 }
Yuta HIGUCHI93d35ea2014-08-31 23:26:13 -0700639 for (PortData portData : portsToRemove) {
640 removePort(portData);
Ray Milkeyb29e6262014-04-09 16:02:14 -0700641 }
Pavlin Radoslavov3c9cc552014-02-20 09:58:38 -0800642
Yuta HIGUCHI8b389a72014-07-18 13:50:00 -0700643 log.debug("Removed {}", swInTopo);
644 topology.removeSwitch(dpid);
Yuta HIGUCHI93d35ea2014-08-31 23:26:13 -0700645 apiRemovedSwitchDataEntries.add(swInTopo);
Pavlin Radoslavov3c9cc552014-02-20 09:58:38 -0800646 }
647
Pavlin Radoslavov734ff5a2014-02-26 10:20:43 -0800648 /**
Yuta HIGUCHI7926ba32014-07-09 11:39:32 -0700649 * Adds a port to the topology replica.
Pavlin Radoslavov734ff5a2014-02-26 10:20:43 -0800650 *
Yuta HIGUCHI93d35ea2014-08-31 23:26:13 -0700651 * @param portData the PortData with the port to add.
Pavlin Radoslavovd7b792e2014-08-01 02:47:47 -0700652 * @return true if the item was successfully added, otherwise false.
Pavlin Radoslavov734ff5a2014-02-26 10:20:43 -0800653 */
Yuta HIGUCHIbc67a052014-06-30 10:37:09 -0700654 @GuardedBy("topology.writeLock")
Yuta HIGUCHI93d35ea2014-08-31 23:26:13 -0700655 private boolean addPort(PortData portData) {
656 Switch sw = topology.getSwitch(portData.getDpid());
Ray Milkey269ffb92014-04-03 14:43:30 -0700657 if (sw == null) {
Pavlin Radoslavovd7b792e2014-08-01 02:47:47 -0700658 // Reordered event
Yuta HIGUCHI93d35ea2014-08-31 23:26:13 -0700659 log.debug("{} reordered because switch is null", portData);
Pavlin Radoslavovd7b792e2014-08-01 02:47:47 -0700660 return false;
Ray Milkey269ffb92014-04-03 14:43:30 -0700661 }
Pavlin Radoslavov3c9cc552014-02-20 09:58:38 -0800662
Yuta HIGUCHI8b389a72014-07-18 13:50:00 -0700663 if (log.isDebugEnabled()) {
Yuta HIGUCHI93d35ea2014-08-31 23:26:13 -0700664 PortData port = topology.getPortData(portData.getSwitchPort());
Yuta HIGUCHI8b389a72014-07-18 13:50:00 -0700665 if (port != null) {
Yuta HIGUCHI93d35ea2014-08-31 23:26:13 -0700666 log.debug("Update {}", portData);
Yuta HIGUCHI8b389a72014-07-18 13:50:00 -0700667 } else {
Yuta HIGUCHI93d35ea2014-08-31 23:26:13 -0700668 log.debug("Added {}", portData);
Yuta HIGUCHI8b389a72014-07-18 13:50:00 -0700669 }
Ray Milkey269ffb92014-04-03 14:43:30 -0700670 }
Yuta HIGUCHI93d35ea2014-08-31 23:26:13 -0700671 topology.putPort(portData.freeze());
672 apiAddedPortDataEntries.add(portData);
Pavlin Radoslavovd7b792e2014-08-01 02:47:47 -0700673 return true;
Pavlin Radoslavov3c9cc552014-02-20 09:58:38 -0800674 }
675
Pavlin Radoslavov734ff5a2014-02-26 10:20:43 -0800676 /**
Yuta HIGUCHI7926ba32014-07-09 11:39:32 -0700677 * Removes a port from the topology replica.
Yuta HIGUCHIbf0a8712014-06-30 18:59:46 -0700678 * <p/>
Yuta HIGUCHI8b389a72014-07-18 13:50:00 -0700679 * It will remove attachment points from each hosts on this port
Yuta HIGUCHI93d35ea2014-08-31 23:26:13 -0700680 * and call {@link #removeLink(LinkData)} for each links on this port.
Pavlin Radoslavov734ff5a2014-02-26 10:20:43 -0800681 *
Yuta HIGUCHI93d35ea2014-08-31 23:26:13 -0700682 * @param portData the PortData with the port to remove.
Pavlin Radoslavov734ff5a2014-02-26 10:20:43 -0800683 */
Yuta HIGUCHIbc67a052014-06-30 10:37:09 -0700684 @GuardedBy("topology.writeLock")
Yuta HIGUCHI93d35ea2014-08-31 23:26:13 -0700685 private void removePort(PortData portData) {
686 SwitchData sw = topology.getSwitchData(portData.getDpid());
Ray Milkey269ffb92014-04-03 14:43:30 -0700687 if (sw == null) {
688 log.warn("Parent Switch for Port {} already removed, ignoring",
Yuta HIGUCHI93d35ea2014-08-31 23:26:13 -0700689 portData);
Ray Milkey269ffb92014-04-03 14:43:30 -0700690 return;
691 }
Pavlin Radoslavov3c9cc552014-02-20 09:58:38 -0800692
Yuta HIGUCHI93d35ea2014-08-31 23:26:13 -0700693 final SwitchPort switchPort = portData.getSwitchPort();
694 PortData portInTopo = topology.getPortData(switchPort);
Yuta HIGUCHI8b389a72014-07-18 13:50:00 -0700695 if (portInTopo == null) {
Yuta HIGUCHI93d35ea2014-08-31 23:26:13 -0700696 log.warn("Port {} already removed, ignoring", portData);
Ray Milkey269ffb92014-04-03 14:43:30 -0700697 return;
698 }
Pavlin Radoslavov3c9cc552014-02-20 09:58:38 -0800699
Ray Milkey269ffb92014-04-03 14:43:30 -0700700 //
Yuta HIGUCHI8b389a72014-07-18 13:50:00 -0700701 // Remove all Host attachment points bound to this Port
Ray Milkey269ffb92014-04-03 14:43:30 -0700702 //
Yuta HIGUCHI93d35ea2014-08-31 23:26:13 -0700703 List<HostData> hostsToUpdate = new ArrayList<>();
Yuta HIGUCHI8b389a72014-07-18 13:50:00 -0700704 for (Host host : topology.getHosts(switchPort)) {
705 log.debug("Removing Host {} on Port {}", host, portInTopo);
Yuta HIGUCHI93d35ea2014-08-31 23:26:13 -0700706 HostData hostData = topology.getHostData(host.getMacAddress());
707 hostsToUpdate.add(hostData);
Ray Milkey269ffb92014-04-03 14:43:30 -0700708 }
Yuta HIGUCHI93d35ea2014-08-31 23:26:13 -0700709 for (HostData hostData : hostsToUpdate) {
710 HostData newHostData = new HostData(hostData);
711 newHostData.removeAttachmentPoint(switchPort);
712 newHostData.freeze();
Yuta HIGUCHI8b389a72014-07-18 13:50:00 -0700713
714 // TODO should this event be fired inside #addHost?
Yuta HIGUCHI93d35ea2014-08-31 23:26:13 -0700715 if (newHostData.getAttachmentPoints().isEmpty()) {
Yuta HIGUCHI8b389a72014-07-18 13:50:00 -0700716 // No more attachment point left -> remove Host
Yuta HIGUCHI93d35ea2014-08-31 23:26:13 -0700717 removeHost(hostData);
Yuta HIGUCHI8b389a72014-07-18 13:50:00 -0700718 } else {
719 // Update Host
Yuta HIGUCHI93d35ea2014-08-31 23:26:13 -0700720 addHost(newHostData);
Yuta HIGUCHI8b389a72014-07-18 13:50:00 -0700721 }
Ray Milkeyb29e6262014-04-09 16:02:14 -0700722 }
Pavlin Radoslavov3c9cc552014-02-20 09:58:38 -0800723
Ray Milkey269ffb92014-04-03 14:43:30 -0700724 //
725 // Remove all Links connected to the Port
726 //
727 Set<Link> links = new HashSet<>();
Yuta HIGUCHI8b389a72014-07-18 13:50:00 -0700728 links.addAll(topology.getOutgoingLinks(switchPort));
729 links.addAll(topology.getIncomingLinks(switchPort));
Ray Milkey269ffb92014-04-03 14:43:30 -0700730 for (Link link : links) {
Ray Milkeyb29e6262014-04-09 16:02:14 -0700731 if (link == null) {
Ray Milkey269ffb92014-04-03 14:43:30 -0700732 continue;
Ray Milkeyb29e6262014-04-09 16:02:14 -0700733 }
Yuta HIGUCHI93d35ea2014-08-31 23:26:13 -0700734 LinkData linkData = topology.getLinkData(link.getLinkTuple());
735 if (linkData != null) {
Yuta HIGUCHI8b389a72014-07-18 13:50:00 -0700736 log.debug("Removing Link {} on Port {}", link, portInTopo);
Yuta HIGUCHI93d35ea2014-08-31 23:26:13 -0700737 removeLink(linkData);
Yuta HIGUCHI8b389a72014-07-18 13:50:00 -0700738 }
Ray Milkeyb29e6262014-04-09 16:02:14 -0700739 }
Pavlin Radoslavov3c9cc552014-02-20 09:58:38 -0800740
Yuta HIGUCHI8b389a72014-07-18 13:50:00 -0700741 // Remove the Port from Topology
742 log.debug("Removed {}", portInTopo);
743 topology.removePort(switchPort);
Pavlin Radoslavov74986ce2014-02-20 13:17:20 -0800744
Yuta HIGUCHI93d35ea2014-08-31 23:26:13 -0700745 apiRemovedPortDataEntries.add(portInTopo);
Pavlin Radoslavov3c9cc552014-02-20 09:58:38 -0800746 }
747
Pavlin Radoslavov734ff5a2014-02-26 10:20:43 -0800748 /**
Yuta HIGUCHI7926ba32014-07-09 11:39:32 -0700749 * Adds a link to the topology replica.
Yuta HIGUCHIbf0a8712014-06-30 18:59:46 -0700750 * <p/>
Yuta HIGUCHI8b389a72014-07-18 13:50:00 -0700751 * It will remove attachment points from each hosts using the same ports.
Pavlin Radoslavov734ff5a2014-02-26 10:20:43 -0800752 *
Yuta HIGUCHI93d35ea2014-08-31 23:26:13 -0700753 * @param linkData the LinkData with the link to add.
Pavlin Radoslavovd7b792e2014-08-01 02:47:47 -0700754 * @return true if the item was successfully added, otherwise false.
Pavlin Radoslavov734ff5a2014-02-26 10:20:43 -0800755 */
Yuta HIGUCHIbc67a052014-06-30 10:37:09 -0700756 @GuardedBy("topology.writeLock")
Yuta HIGUCHI93d35ea2014-08-31 23:26:13 -0700757 private boolean addLink(LinkData linkData) {
758 PortData srcPort = topology.getPortData(linkData.getSrc());
759 PortData dstPort = topology.getPortData(linkData.getDst());
Ray Milkey269ffb92014-04-03 14:43:30 -0700760 if ((srcPort == null) || (dstPort == null)) {
Pavlin Radoslavovd7b792e2014-08-01 02:47:47 -0700761 // Reordered event
Yuta HIGUCHI93d35ea2014-08-31 23:26:13 -0700762 log.debug("{} reordered because {} port is null", linkData,
Jonathan Hartf1675202014-05-23 14:59:07 -0700763 (srcPort == null) ? "src" : "dst");
Pavlin Radoslavovd7b792e2014-08-01 02:47:47 -0700764 return false;
Ray Milkey269ffb92014-04-03 14:43:30 -0700765 }
Pavlin Radoslavov3c9cc552014-02-20 09:58:38 -0800766
Pavlin Radoslavovd7b792e2014-08-01 02:47:47 -0700767 //
768 // XXX domain knowledge: Sanity check: Port cannot have both Link and
769 // Host.
770 //
771 // FIXME: Potentially local replica may not be up-to-date yet due to
772 // Hazelcast delay.
773 // FIXME: May need to manage local truth and use them instead.
774 //
Yuta HIGUCHI93d35ea2014-08-31 23:26:13 -0700775 if (topology.getLinkData(linkData.getLinkTuple()) == null) {
Yuta HIGUCHI8b389a72014-07-18 13:50:00 -0700776 // Only check for existing Host when adding new Link.
Yuta HIGUCHI8b389a72014-07-18 13:50:00 -0700777 // Remove all Hosts attached to the ports on both ends
778
Yuta HIGUCHI93d35ea2014-08-31 23:26:13 -0700779 Set<HostData> hostsToUpdate =
780 new TreeSet<>(new Comparator<HostData>() {
Pavlin Radoslavovd7b792e2014-08-01 02:47:47 -0700781 // Comparison only using ID(=MAC)
Yuta HIGUCHI8b389a72014-07-18 13:50:00 -0700782 @Override
Yuta HIGUCHI93d35ea2014-08-31 23:26:13 -0700783 public int compare(HostData o1, HostData o2) {
Yuta HIGUCHI8b389a72014-07-18 13:50:00 -0700784 return Long.compare(o1.getMac().toLong(), o2.getMac().toLong());
785 }
786 });
787
788 List<SwitchPort> portsToCheck = Arrays.asList(
789 srcPort.getSwitchPort(),
790 dstPort.getSwitchPort());
791
792 // Enumerate Host which needs to be updated by this Link add event
793 for (SwitchPort port : portsToCheck) {
794 for (Host host : topology.getHosts(port)) {
Yuta HIGUCHIbfc77f02014-07-14 22:50:25 -0700795 log.error("Host {} on Port {} should have been removed prior to adding Link {}",
Yuta HIGUCHI93d35ea2014-08-31 23:26:13 -0700796 host, port, linkData);
Yuta HIGUCHI8b389a72014-07-18 13:50:00 -0700797
Yuta HIGUCHI93d35ea2014-08-31 23:26:13 -0700798 HostData hostData =
799 topology.getHostData(host.getMacAddress());
800 hostsToUpdate.add(hostData);
Ray Milkey269ffb92014-04-03 14:43:30 -0700801 }
802 }
Pavlin Radoslavovd7b792e2014-08-01 02:47:47 -0700803 // Remove attachment point from them
Yuta HIGUCHI93d35ea2014-08-31 23:26:13 -0700804 for (HostData hostData : hostsToUpdate) {
Pavlin Radoslavovd7b792e2014-08-01 02:47:47 -0700805 // Remove port from attachment point and update
Yuta HIGUCHI93d35ea2014-08-31 23:26:13 -0700806 HostData newHostData = new HostData(hostData);
807 newHostData.removeAttachmentPoint(srcPort.getSwitchPort());
808 newHostData.removeAttachmentPoint(dstPort.getSwitchPort());
809 newHostData.freeze();
Yuta HIGUCHI8b389a72014-07-18 13:50:00 -0700810
811 // TODO should this event be fired inside #addHost?
Yuta HIGUCHI93d35ea2014-08-31 23:26:13 -0700812 if (newHostData.getAttachmentPoints().isEmpty()) {
Yuta HIGUCHI8b389a72014-07-18 13:50:00 -0700813 // No more attachment point left -> remove Host
Yuta HIGUCHI93d35ea2014-08-31 23:26:13 -0700814 removeHost(hostData);
Yuta HIGUCHI8b389a72014-07-18 13:50:00 -0700815 } else {
816 // Update Host
Yuta HIGUCHI93d35ea2014-08-31 23:26:13 -0700817 addHost(newHostData);
Yuta HIGUCHI8b389a72014-07-18 13:50:00 -0700818 }
Ray Milkeyb29e6262014-04-09 16:02:14 -0700819 }
Ray Milkey269ffb92014-04-03 14:43:30 -0700820 }
Pavlin Radoslavov74986ce2014-02-20 13:17:20 -0800821
Yuta HIGUCHI8b389a72014-07-18 13:50:00 -0700822 if (log.isDebugEnabled()) {
Yuta HIGUCHI93d35ea2014-08-31 23:26:13 -0700823 LinkData link = topology.getLinkData(linkData.getLinkTuple());
Yuta HIGUCHI8b389a72014-07-18 13:50:00 -0700824 if (link != null) {
Yuta HIGUCHI93d35ea2014-08-31 23:26:13 -0700825 log.debug("Update {}", linkData);
Yuta HIGUCHI8b389a72014-07-18 13:50:00 -0700826 } else {
Yuta HIGUCHI93d35ea2014-08-31 23:26:13 -0700827 log.debug("Added {}", linkData);
Yuta HIGUCHI8b389a72014-07-18 13:50:00 -0700828 }
829 }
Yuta HIGUCHI93d35ea2014-08-31 23:26:13 -0700830 topology.putLink(linkData.freeze());
831 apiAddedLinkDataEntries.add(linkData);
Pavlin Radoslavovd7b792e2014-08-01 02:47:47 -0700832 return true;
Pavlin Radoslavov3c9cc552014-02-20 09:58:38 -0800833 }
834
Pavlin Radoslavov734ff5a2014-02-26 10:20:43 -0800835 /**
Yuta HIGUCHI7926ba32014-07-09 11:39:32 -0700836 * Removes a link from the topology replica.
Pavlin Radoslavov734ff5a2014-02-26 10:20:43 -0800837 *
Yuta HIGUCHI93d35ea2014-08-31 23:26:13 -0700838 * @param linkData the LinkData with the link to remove.
Pavlin Radoslavov734ff5a2014-02-26 10:20:43 -0800839 */
Yuta HIGUCHIbc67a052014-06-30 10:37:09 -0700840 @GuardedBy("topology.writeLock")
Yuta HIGUCHI93d35ea2014-08-31 23:26:13 -0700841 private void removeLink(LinkData linkData) {
842 Port srcPort = topology.getPort(linkData.getSrc().getDpid(),
843 linkData.getSrc().getPortNumber());
Ray Milkey269ffb92014-04-03 14:43:30 -0700844 if (srcPort == null) {
845 log.warn("Src Port for Link {} already removed, ignoring",
Yuta HIGUCHI93d35ea2014-08-31 23:26:13 -0700846 linkData);
Ray Milkey269ffb92014-04-03 14:43:30 -0700847 return;
848 }
Pavlin Radoslavov3c9cc552014-02-20 09:58:38 -0800849
Yuta HIGUCHI93d35ea2014-08-31 23:26:13 -0700850 Port dstPort = topology.getPort(linkData.getDst().getDpid(),
851 linkData.getDst().getPortNumber());
Ray Milkey269ffb92014-04-03 14:43:30 -0700852 if (dstPort == null) {
853 log.warn("Dst Port for Link {} already removed, ignoring",
Yuta HIGUCHI93d35ea2014-08-31 23:26:13 -0700854 linkData);
Ray Milkey269ffb92014-04-03 14:43:30 -0700855 return;
856 }
Pavlin Radoslavov3c9cc552014-02-20 09:58:38 -0800857
Yuta HIGUCHI93d35ea2014-08-31 23:26:13 -0700858 LinkData linkInTopo = topology.getLinkData(linkData.getLinkTuple(),
859 linkData.getType());
Yuta HIGUCHI8b389a72014-07-18 13:50:00 -0700860 if (linkInTopo == null) {
Yuta HIGUCHI93d35ea2014-08-31 23:26:13 -0700861 log.warn("Link {} already removed, ignoring", linkData);
Yuta HIGUCHI8b389a72014-07-18 13:50:00 -0700862 return;
Ray Milkey269ffb92014-04-03 14:43:30 -0700863 }
Jonathan Hart25bd53e2014-04-30 23:44:09 -0700864
Yuta HIGUCHI8b389a72014-07-18 13:50:00 -0700865 if (log.isDebugEnabled()) {
866 // only do sanity check on debug level
867
Yuta HIGUCHI93d35ea2014-08-31 23:26:13 -0700868 Link linkIn = dstPort.getIncomingLink(linkData.getType());
Yuta HIGUCHI8b389a72014-07-18 13:50:00 -0700869 if (linkIn == null) {
Pavlin Radoslavov8a44b782014-08-07 12:53:27 -0700870 log.warn("Link {} already removed on destination Port",
Yuta HIGUCHI93d35ea2014-08-31 23:26:13 -0700871 linkData);
Yuta HIGUCHI8b389a72014-07-18 13:50:00 -0700872 }
Yuta HIGUCHI93d35ea2014-08-31 23:26:13 -0700873 Link linkOut = srcPort.getOutgoingLink(linkData.getType());
Yuta HIGUCHI8b389a72014-07-18 13:50:00 -0700874 if (linkOut == null) {
Yuta HIGUCHI93d35ea2014-08-31 23:26:13 -0700875 log.warn("Link {} already removed on src Port", linkData);
Yuta HIGUCHI8b389a72014-07-18 13:50:00 -0700876 }
Jonathan Hart25bd53e2014-04-30 23:44:09 -0700877 }
Pavlin Radoslavov74986ce2014-02-20 13:17:20 -0800878
Yuta HIGUCHI8b389a72014-07-18 13:50:00 -0700879 log.debug("Removed {}", linkInTopo);
Yuta HIGUCHI93d35ea2014-08-31 23:26:13 -0700880 topology.removeLink(linkData.getLinkTuple(), linkData.getType());
881 apiRemovedLinkDataEntries.add(linkInTopo);
Pavlin Radoslavov3c9cc552014-02-20 09:58:38 -0800882 }
883
Pavlin Radoslavov734ff5a2014-02-26 10:20:43 -0800884 /**
Yuta HIGUCHIbfc77f02014-07-14 22:50:25 -0700885 * Adds a host to the topology replica.
Ray Milkey269ffb92014-04-03 14:43:30 -0700886 * <p/>
Yuta HIGUCHIbfc77f02014-07-14 22:50:25 -0700887 * TODO: Host-related work is incomplete.
Pavlin Radoslavov734ff5a2014-02-26 10:20:43 -0800888 * TODO: Eventually, we might need to consider reordering
Yuta HIGUCHI93d35ea2014-08-31 23:26:13 -0700889 * or {@link #addLink(LinkData)} and {@link #addHost(HostData)} events
Pavlin Radoslavovd7b792e2014-08-01 02:47:47 -0700890 * on the same port.
Pavlin Radoslavov734ff5a2014-02-26 10:20:43 -0800891 *
Yuta HIGUCHI93d35ea2014-08-31 23:26:13 -0700892 * @param hostData the HostData with the host to add.
Pavlin Radoslavovd7b792e2014-08-01 02:47:47 -0700893 * @return true if the item was successfully added, otherwise false.
Pavlin Radoslavov734ff5a2014-02-26 10:20:43 -0800894 */
Yuta HIGUCHIbc67a052014-06-30 10:37:09 -0700895 @GuardedBy("topology.writeLock")
Yuta HIGUCHI93d35ea2014-08-31 23:26:13 -0700896 private boolean addHost(HostData hostData) {
Pavlin Radoslavov3c9cc552014-02-20 09:58:38 -0800897
Yuta HIGUCHI8b389a72014-07-18 13:50:00 -0700898 // TODO Decide how to handle update scenario.
Yuta HIGUCHI93d35ea2014-08-31 23:26:13 -0700899 // If the new HostData has less attachment point compared to
900 // existing HostData, what should the event be?
901 // - Add HostData with some attachment point removed? (current behavior)
Pavlin Radoslavov3c9cc552014-02-20 09:58:38 -0800902
Yuta HIGUCHI8b389a72014-07-18 13:50:00 -0700903 // create unfrozen copy
904 // for removing attachment points which already has a link
Yuta HIGUCHI93d35ea2014-08-31 23:26:13 -0700905 HostData modifiedHostData = new HostData(hostData);
Pavlin Radoslavov3c9cc552014-02-20 09:58:38 -0800906
Yuta HIGUCHI8b389a72014-07-18 13:50:00 -0700907 // Verify each attachment point
Ray Milkey269ffb92014-04-03 14:43:30 -0700908 boolean attachmentFound = false;
Yuta HIGUCHI93d35ea2014-08-31 23:26:13 -0700909 for (SwitchPort swp : hostData.getAttachmentPoints()) {
Yuta HIGUCHIbfc77f02014-07-14 22:50:25 -0700910 // XXX domain knowledge: Port must exist before Host
Yuta HIGUCHIbf0a8712014-06-30 18:59:46 -0700911 // but this knowledge cannot be pushed down to driver.
912
Ray Milkey269ffb92014-04-03 14:43:30 -0700913 // Attached Ports must exist
Yuta HIGUCHIb1e2ab72014-06-30 11:01:31 -0700914 Port port = topology.getPort(swp.getDpid(), swp.getPortNumber());
Ray Milkey269ffb92014-04-03 14:43:30 -0700915 if (port == null) {
Pavlin Radoslavov8a44b782014-08-07 12:53:27 -0700916 log.debug("{} reordered because port {} was not there",
Yuta HIGUCHI93d35ea2014-08-31 23:26:13 -0700917 hostData, swp);
Pavlin Radoslavovd7b792e2014-08-01 02:47:47 -0700918 // Reordered event
919 return false; // should not continue if re-applying later
Ray Milkey269ffb92014-04-03 14:43:30 -0700920 }
921 // Attached Ports must not have Link
922 if (port.getOutgoingLink() != null ||
923 port.getIncomingLink() != null) {
Yuta HIGUCHI8b389a72014-07-18 13:50:00 -0700924 log.warn("Link (Out:{},In:{}) exist on the attachment point. "
925 + "Ignoring this attachmentpoint ({}) from {}.",
926 port.getOutgoingLink(), port.getIncomingLink(),
Yuta HIGUCHI93d35ea2014-08-31 23:26:13 -0700927 swp, modifiedHostData);
928 // FIXME Should either reject, reorder this HostData,
929 // or remove attachment point from given HostData
930 // Removing attachment point from given HostData for now.
931 modifiedHostData.removeAttachmentPoint(swp);
Ray Milkey269ffb92014-04-03 14:43:30 -0700932 continue;
933 }
934
Ray Milkey269ffb92014-04-03 14:43:30 -0700935 attachmentFound = true;
936 }
937
Yuta HIGUCHIbfc77f02014-07-14 22:50:25 -0700938 // Update the host in the topology
Ray Milkey269ffb92014-04-03 14:43:30 -0700939 if (attachmentFound) {
Yuta HIGUCHI93d35ea2014-08-31 23:26:13 -0700940 if (modifiedHostData.getAttachmentPoints().isEmpty()) {
Yuta HIGUCHI8b389a72014-07-18 13:50:00 -0700941 log.warn("No valid attachment point left. Ignoring."
Pavlin Radoslavov8a44b782014-08-07 12:53:27 -0700942 + "original: {}, modified: {}",
Yuta HIGUCHI93d35ea2014-08-31 23:26:13 -0700943 hostData, modifiedHostData);
Yuta HIGUCHI8b389a72014-07-18 13:50:00 -0700944 // TODO Should we call #removeHost to trigger remove event?
945 // only if this call is update.
Pavlin Radoslavovd7b792e2014-08-01 02:47:47 -0700946 return false;
Yuta HIGUCHI8b389a72014-07-18 13:50:00 -0700947 }
948
949 if (log.isDebugEnabled()) {
Yuta HIGUCHI93d35ea2014-08-31 23:26:13 -0700950 HostData host = topology.getHostData(hostData.getMac());
Yuta HIGUCHI8b389a72014-07-18 13:50:00 -0700951 if (host != null) {
Yuta HIGUCHI93d35ea2014-08-31 23:26:13 -0700952 log.debug("Update {}", modifiedHostData);
Yuta HIGUCHI8b389a72014-07-18 13:50:00 -0700953 } else {
Yuta HIGUCHI93d35ea2014-08-31 23:26:13 -0700954 log.debug("Added {}", modifiedHostData);
Yuta HIGUCHI8b389a72014-07-18 13:50:00 -0700955 }
956 }
Yuta HIGUCHI93d35ea2014-08-31 23:26:13 -0700957 topology.putHost(modifiedHostData.freeze());
958 apiAddedHostDataEntries.add(modifiedHostData);
Pavlin Radoslavovd7b792e2014-08-01 02:47:47 -0700959 return true;
Ray Milkey269ffb92014-04-03 14:43:30 -0700960 }
Pavlin Radoslavovd7b792e2014-08-01 02:47:47 -0700961 return false;
Pavlin Radoslavov3c9cc552014-02-20 09:58:38 -0800962 }
963
Pavlin Radoslavov734ff5a2014-02-26 10:20:43 -0800964 /**
Yuta HIGUCHIbfc77f02014-07-14 22:50:25 -0700965 * Removes a host from the topology replica.
Ray Milkey269ffb92014-04-03 14:43:30 -0700966 * <p/>
Yuta HIGUCHIbfc77f02014-07-14 22:50:25 -0700967 * TODO: Host-related work is incomplete.
Pavlin Radoslavov734ff5a2014-02-26 10:20:43 -0800968 *
Yuta HIGUCHI93d35ea2014-08-31 23:26:13 -0700969 * @param hostData the Host Event with the host to remove.
Pavlin Radoslavov734ff5a2014-02-26 10:20:43 -0800970 */
Yuta HIGUCHIbc67a052014-06-30 10:37:09 -0700971 @GuardedBy("topology.writeLock")
Yuta HIGUCHI93d35ea2014-08-31 23:26:13 -0700972 private void removeHost(HostData hostData) {
Yuta HIGUCHI8b389a72014-07-18 13:50:00 -0700973
Yuta HIGUCHI93d35ea2014-08-31 23:26:13 -0700974 final MACAddress mac = hostData.getMac();
975 HostData hostInTopo = topology.getHostData(mac);
Yuta HIGUCHI8b389a72014-07-18 13:50:00 -0700976 if (hostInTopo == null) {
Yuta HIGUCHI93d35ea2014-08-31 23:26:13 -0700977 log.warn("Host {} already removed, ignoring", hostData);
Ray Milkey269ffb92014-04-03 14:43:30 -0700978 return;
979 }
Pavlin Radoslavov3c9cc552014-02-20 09:58:38 -0800980
Yuta HIGUCHI8b389a72014-07-18 13:50:00 -0700981 log.debug("Removed {}", hostInTopo);
982 topology.removeHost(mac);
Yuta HIGUCHI93d35ea2014-08-31 23:26:13 -0700983 apiRemovedHostDataEntries.add(hostInTopo);
Pavlin Radoslavov3c9cc552014-02-20 09:58:38 -0800984 }
Jonathan Hart062a2e82014-02-03 09:41:57 -0800985}