blob: 1e3dccd960f17416519004aa9cfce85c10b9eb1a [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();
Pavlin Radoslavovd7b792e2014-08-01 02:47:47 -070075 private TopologyEventPreprocessor eventPreprocessor;
Yuta HIGUCHI181d34d2014-02-05 15:05:46 -080076
Pavlin Radoslavov706add22014-02-20 12:15:59 -080077 //
Pavlin Radoslavovd4f40372014-07-18 16:58:40 -070078 // Metrics
79 //
80 private static final MetricsComponent METRICS_COMPONENT =
81 OnosMetrics.registerComponent("Topology");
82 private static final MetricsFeature METRICS_FEATURE_EVENT_NOTIFICATION =
83 METRICS_COMPONENT.registerFeature("EventNotification");
84 //
Pavlin Radoslavovc49917c2014-07-23 12:16:29 -070085 // Timestamp of the last Topology event (ms from the Epoch)
86 private volatile long lastEventTimestampEpochMs = 0;
87 private final Gauge<Long> gaugeLastEventTimestampEpochMs =
Pavlin Radoslavovd4f40372014-07-18 16:58:40 -070088 OnosMetrics.registerMetric(METRICS_COMPONENT,
89 METRICS_FEATURE_EVENT_NOTIFICATION,
Pavlin Radoslavovc49917c2014-07-23 12:16:29 -070090 "LastEventTimestamp.EpochMs",
Pavlin Radoslavovd4f40372014-07-18 16:58:40 -070091 new Gauge<Long>() {
92 @Override
93 public Long getValue() {
Pavlin Radoslavovc49917c2014-07-23 12:16:29 -070094 return lastEventTimestampEpochMs;
Pavlin Radoslavovd4f40372014-07-18 16:58:40 -070095 }
96 });
97 // Rate of the Topology events published to the Topology listeners
98 private final Meter listenerEventRate =
99 OnosMetrics.createMeter(METRICS_COMPONENT,
100 METRICS_FEATURE_EVENT_NOTIFICATION,
101 "ListenerEventRate");
102
103 //
Pavlin Radoslavov26d83402014-02-20 15:24:30 -0800104 // Local state for keeping track of locally discovered events so we can
105 // cleanup properly when a Switch or Port is removed.
106 //
Yuta HIGUCHIbfc77f02014-07-14 22:50:25 -0700107 // We keep all Port, (incoming) Link and Host events per Switch DPID:
Pavlin Radoslavov26d83402014-02-20 15:24:30 -0800108 // - If a switch goes down, we remove all corresponding Port, Link and
Yuta HIGUCHIbfc77f02014-07-14 22:50:25 -0700109 // Host events.
Pavlin Radoslavov26d83402014-02-20 15:24:30 -0800110 // - If a port on a switch goes down, we remove all corresponding Link
Yuta HIGUCHIbfc77f02014-07-14 22:50:25 -0700111 // and Host events discovered by this instance.
Yuta HIGUCHIbc67a052014-06-30 10:37:09 -0700112 //
113 // How to handle side-effect of remote events.
114 // - Remote Port Down event -> Link Down
115 // Not handled. (XXX Shouldn't it be removed from discovered.. Map)
Yuta HIGUCHIbfc77f02014-07-14 22:50:25 -0700116 // - Remote Host Added -> lose ownership of Host)
Yuta HIGUCHIbc67a052014-06-30 10:37:09 -0700117 // Not handled. (XXX Shouldn't it be removed from discovered.. Map)
118 //
119 // XXX Domain knowledge based invariant maintenance should be moved to
120 // driver module, since the invariant may be different on optical, etc.
121 //
122 // What happens on leadership change?
123 // - Probably should: remove from discovered.. Maps, but not send DELETE events
Yuta HIGUCHIbfc77f02014-07-14 22:50:25 -0700124 // XXX Switch/Port can be rediscovered by new leader, but Link, Host?
Yuta HIGUCHIbc67a052014-06-30 10:37:09 -0700125 // - Current: There is no way to recognize leadership change?
126 // ZookeeperRegistry.requestControl(long, ControlChangeCallback)
127 // is the only way to register listener, and it allows only 1 listener,
128 // which is already used by Controller class.
129 //
130 // FIXME Replace with concurrent variant.
131 // #removeSwitchDiscoveryEvent(SwitchEvent) runs in different thread.
Pavlin Radoslavov26d83402014-02-20 15:24:30 -0800132 //
Yuta HIGUCHI8f3dfa32014-06-25 00:14:25 -0700133 private Map<Dpid, Map<ByteBuffer, PortEvent>> discoveredAddedPortEvents =
Ray Milkey269ffb92014-04-03 14:43:30 -0700134 new HashMap<>();
Yuta HIGUCHI8f3dfa32014-06-25 00:14:25 -0700135 private Map<Dpid, Map<ByteBuffer, LinkEvent>> discoveredAddedLinkEvents =
Ray Milkey269ffb92014-04-03 14:43:30 -0700136 new HashMap<>();
Yuta HIGUCHIbfc77f02014-07-14 22:50:25 -0700137 private Map<Dpid, Map<ByteBuffer, HostEvent>> discoveredAddedHostEvents =
Ray Milkey269ffb92014-04-03 14:43:30 -0700138 new HashMap<>();
Pavlin Radoslavov26d83402014-02-20 15:24:30 -0800139
140 //
Pavlin Radoslavov74986ce2014-02-20 13:17:20 -0800141 // Local state for keeping track of the application event notifications
142 //
Yuta HIGUCHIbc67a052014-06-30 10:37:09 -0700143 // - Queue of events, which will be dispatched to local listeners
144 // on next notification.
Yuta HIGUCHI703696c2014-06-25 20:36:45 -0700145
Pavlin Radoslavovcac157d2014-07-31 13:54:08 -0700146 private List<MastershipEvent> apiAddedMastershipEvents =
147 new LinkedList<>();
148 private List<MastershipEvent> apiRemovedMastershipEvents =
149 new LinkedList<>();
Yuta HIGUCHI703696c2014-06-25 20:36:45 -0700150 private List<SwitchEvent> apiAddedSwitchEvents = new LinkedList<>();
151 private List<SwitchEvent> apiRemovedSwitchEvents = new LinkedList<>();
152 private List<PortEvent> apiAddedPortEvents = new LinkedList<>();
153 private List<PortEvent> apiRemovedPortEvents = new LinkedList<>();
154 private List<LinkEvent> apiAddedLinkEvents = new LinkedList<>();
155 private List<LinkEvent> apiRemovedLinkEvents = new LinkedList<>();
Yuta HIGUCHIbfc77f02014-07-14 22:50:25 -0700156 private List<HostEvent> apiAddedHostEvents = new LinkedList<>();
157 private List<HostEvent> apiRemovedHostEvents = new LinkedList<>();
Pavlin Radoslavov74986ce2014-02-20 13:17:20 -0800158
Pavlin Radoslavovc1cfde52014-02-19 11:35:29 -0800159 /**
160 * Constructor.
161 *
Jonathan Harte37e4e22014-05-13 19:12:02 -0700162 * @param registryService the Registry Service to use.
163 * @param topologyListeners the collection of topology listeners to use.
Pavlin Radoslavovc1cfde52014-02-19 11:35:29 -0800164 */
165 public TopologyManager(IControllerRegistryService registryService,
Jonathan Harte37e4e22014-05-13 19:12:02 -0700166 CopyOnWriteArrayList<ITopologyListener> topologyListeners) {
167 datastore = new TopologyDatastore();
Ray Milkey269ffb92014-04-03 14:43:30 -0700168 this.registryService = registryService;
Jonathan Harte37e4e22014-05-13 19:12:02 -0700169 this.topologyListeners = topologyListeners;
Pavlin Radoslavovd7b792e2014-08-01 02:47:47 -0700170 this.eventPreprocessor =
171 new TopologyEventPreprocessor(registryService);
Yuta HIGUCHI80829d12014-02-05 20:16:56 -0800172 }
Yuta HIGUCHI181d34d2014-02-05 15:05:46 -0800173
Pavlin Radoslavovc1cfde52014-02-19 11:35:29 -0800174 /**
Jonathan Harte37e4e22014-05-13 19:12:02 -0700175 * Get the Topology.
Pavlin Radoslavovc1cfde52014-02-19 11:35:29 -0800176 *
Jonathan Harte37e4e22014-05-13 19:12:02 -0700177 * @return the Topology.
Pavlin Radoslavovc1cfde52014-02-19 11:35:29 -0800178 */
Jonathan Harte37e4e22014-05-13 19:12:02 -0700179 Topology getTopology() {
180 return topology;
Pavlin Radoslavov6d224ee2014-02-18 16:43:15 -0800181 }
182
Yuta HIGUCHI4bfdd532014-02-07 13:47:36 -0800183 /**
Pavlin Radoslavov721a2e02014-02-14 23:40:14 -0800184 * Event handler class.
185 */
Yuta HIGUCHI8b389a72014-07-18 13:50:00 -0700186 class EventHandler extends Thread implements
Ray Milkey269ffb92014-04-03 14:43:30 -0700187 IEventChannelListener<byte[], TopologyEvent> {
188 private BlockingQueue<EventEntry<TopologyEvent>> topologyEvents =
189 new LinkedBlockingQueue<EventEntry<TopologyEvent>>();
Pavlin Radoslavov721a2e02014-02-14 23:40:14 -0800190
Ray Milkey269ffb92014-04-03 14:43:30 -0700191 /**
192 * Startup processing.
193 */
194 private void startup() {
195 //
196 // TODO: Read all state from the database:
197 //
198 // Collection<EventEntry<TopologyEvent>> collection =
199 // readWholeTopologyFromDB();
200 //
201 // For now, as a shortcut we read it from the datagrid
202 //
Ray Milkey5df613b2014-04-15 10:50:56 -0700203 Collection<TopologyEvent> allTopologyEvents =
Ray Milkey269ffb92014-04-03 14:43:30 -0700204 eventChannel.getAllEntries();
Pavlin Radoslavovd7b792e2014-08-01 02:47:47 -0700205 List<EventEntry<TopologyEvent>> events =
206 new LinkedList<EventEntry<TopologyEvent>>();
Pavlin Radoslavov721a2e02014-02-14 23:40:14 -0800207
Ray Milkey5df613b2014-04-15 10:50:56 -0700208 for (TopologyEvent topologyEvent : allTopologyEvents) {
Ray Milkey269ffb92014-04-03 14:43:30 -0700209 EventEntry<TopologyEvent> eventEntry =
210 new EventEntry<TopologyEvent>(EventEntry.Type.ENTRY_ADD,
211 topologyEvent);
Pavlin Radoslavovd7b792e2014-08-01 02:47:47 -0700212 events.add(eventEntry);
Ray Milkey269ffb92014-04-03 14:43:30 -0700213 }
Pavlin Radoslavovd7b792e2014-08-01 02:47:47 -0700214 processEvents(events);
Ray Milkey269ffb92014-04-03 14:43:30 -0700215 }
Pavlin Radoslavov721a2e02014-02-14 23:40:14 -0800216
Ray Milkey269ffb92014-04-03 14:43:30 -0700217 /**
218 * Run the thread.
219 */
220 @Override
221 public void run() {
Pavlin Radoslavovd7b792e2014-08-01 02:47:47 -0700222 List<EventEntry<TopologyEvent>> events =
223 new LinkedList<EventEntry<TopologyEvent>>();
Pavlin Radoslavov721a2e02014-02-14 23:40:14 -0800224
Ray Milkey269ffb92014-04-03 14:43:30 -0700225 this.setName("TopologyManager.EventHandler " + this.getId());
226 startup();
Pavlin Radoslavov721a2e02014-02-14 23:40:14 -0800227
Ray Milkey269ffb92014-04-03 14:43:30 -0700228 //
229 // The main loop
230 //
Pavlin Radoslavov8e881a42014-06-24 16:58:07 -0700231 while (true) {
232 try {
233 EventEntry<TopologyEvent> eventEntry =
234 topologyEvents.take();
Pavlin Radoslavovd7b792e2014-08-01 02:47:47 -0700235 events.add(eventEntry);
236 topologyEvents.drainTo(events);
Pavlin Radoslavov721a2e02014-02-14 23:40:14 -0800237
Pavlin Radoslavovd7b792e2014-08-01 02:47:47 -0700238 processEvents(events);
239 events.clear();
Pavlin Radoslavov8e881a42014-06-24 16:58:07 -0700240 } catch (Exception exception) {
241 log.debug("Exception processing Topology Events: ",
242 exception);
Ray Milkey269ffb92014-04-03 14:43:30 -0700243 }
Ray Milkey269ffb92014-04-03 14:43:30 -0700244 }
245 }
Pavlin Radoslavov721a2e02014-02-14 23:40:14 -0800246
Ray Milkey269ffb92014-04-03 14:43:30 -0700247 /**
248 * Process all topology events.
249 *
250 * @param events the events to process.
251 */
Pavlin Radoslavovd7b792e2014-08-01 02:47:47 -0700252 private void processEvents(List<EventEntry<TopologyEvent>> events) {
Pavlin Radoslavovcac157d2014-07-31 13:54:08 -0700253 //
Pavlin Radoslavovd7b792e2014-08-01 02:47:47 -0700254 // Pre-process the events
Pavlin Radoslavovcac157d2014-07-31 13:54:08 -0700255 //
Pavlin Radoslavovd7b792e2014-08-01 02:47:47 -0700256 events = eventPreprocessor.processEvents(events);
Pavlin Radoslavov3c9cc552014-02-20 09:58:38 -0800257
Ray Milkey269ffb92014-04-03 14:43:30 -0700258 //
Jonathan Harte37e4e22014-05-13 19:12:02 -0700259 // Lock the topology while it is modified
Ray Milkey269ffb92014-04-03 14:43:30 -0700260 //
Jonathan Harte37e4e22014-05-13 19:12:02 -0700261 topology.acquireWriteLock();
Pavlin Radoslavov8ffb8bf2014-02-20 15:34:26 -0800262
Ray Milkey269ffb92014-04-03 14:43:30 -0700263 try {
Pavlin Radoslavovd7b792e2014-08-01 02:47:47 -0700264 // Apply the events
Ray Milkey269ffb92014-04-03 14:43:30 -0700265 //
Pavlin Radoslavovd7b792e2014-08-01 02:47:47 -0700266 // NOTE: The events are suppose to be in the proper order
267 // to naturally build and update the topology.
Ray Milkey269ffb92014-04-03 14:43:30 -0700268 //
Pavlin Radoslavovd7b792e2014-08-01 02:47:47 -0700269 for (EventEntry<TopologyEvent> event : events) {
270 TopologyEvent topologyEvent = event.eventData();
Yuta HIGUCHI3aca81a2014-02-23 12:41:19 -0800271
Pavlin Radoslavovd7b792e2014-08-01 02:47:47 -0700272 // Get the event itself
273 MastershipEvent mastershipEvent =
274 topologyEvent.getMastershipEvent();
275 SwitchEvent switchEvent = topologyEvent.getSwitchEvent();
276 PortEvent portEvent = topologyEvent.getPortEvent();
277 LinkEvent linkEvent = topologyEvent.getLinkEvent();
278 HostEvent hostEvent = topologyEvent.getHostEvent();
279 boolean wasAdded = false;
Yuta HIGUCHI3aca81a2014-02-23 12:41:19 -0800280
Pavlin Radoslavovd7b792e2014-08-01 02:47:47 -0700281 //
282 // Extract the events
283 //
284 switch (event.eventType()) {
285 case ENTRY_ADD:
286 if (mastershipEvent != null) {
287 wasAdded = addMastershipEvent(mastershipEvent);
288 }
289 if (switchEvent != null) {
290 wasAdded = addSwitch(switchEvent);
291 }
292 if (portEvent != null) {
293 wasAdded = addPort(portEvent);
294 }
295 if (linkEvent != null) {
296 wasAdded = addLink(linkEvent);
297 }
298 if (hostEvent != null) {
299 wasAdded = addHost(hostEvent);
300 }
301 // If the item wasn't added, probably it was reordered
302 if (!wasAdded) {
303 ByteBuffer id = topologyEvent.getIDasByteBuffer();
304 eventPreprocessor.reorderedEvents.put(id, topologyEvent);
305 }
306 break;
307 case ENTRY_REMOVE:
308 if (mastershipEvent != null) {
309 removeMastershipEvent(mastershipEvent);
310 }
311 if (switchEvent != null) {
312 removeSwitch(switchEvent);
313 }
314 if (portEvent != null) {
315 removePort(portEvent);
316 }
317 if (linkEvent != null) {
318 removeLink(linkEvent);
319 }
320 if (hostEvent != null) {
321 removeHost(hostEvent);
322 }
323 break;
324 default:
325 log.error("Unknown topology event {}",
326 event.eventType());
327 }
328 }
Ray Milkey269ffb92014-04-03 14:43:30 -0700329 } finally {
330 //
Jonathan Harte37e4e22014-05-13 19:12:02 -0700331 // Topology modifications completed: Release the lock
Ray Milkey269ffb92014-04-03 14:43:30 -0700332 //
Jonathan Harte37e4e22014-05-13 19:12:02 -0700333 topology.releaseWriteLock();
Ray Milkey269ffb92014-04-03 14:43:30 -0700334 }
Yuta HIGUCHI3aca81a2014-02-23 12:41:19 -0800335
Ray Milkey269ffb92014-04-03 14:43:30 -0700336 //
337 // Dispatch the Topology Notification Events to the applications
338 //
Jonathan Harte37e4e22014-05-13 19:12:02 -0700339 dispatchTopologyEvents();
Ray Milkey269ffb92014-04-03 14:43:30 -0700340 }
Pavlin Radoslavov721a2e02014-02-14 23:40:14 -0800341
Ray Milkey269ffb92014-04-03 14:43:30 -0700342 /**
343 * Receive a notification that an entry is added.
344 *
345 * @param value the value for the entry.
346 */
347 @Override
348 public void entryAdded(TopologyEvent value) {
349 EventEntry<TopologyEvent> eventEntry =
350 new EventEntry<TopologyEvent>(EventEntry.Type.ENTRY_ADD,
351 value);
352 topologyEvents.add(eventEntry);
353 }
Pavlin Radoslavov721a2e02014-02-14 23:40:14 -0800354
Ray Milkey269ffb92014-04-03 14:43:30 -0700355 /**
356 * Receive a notification that an entry is removed.
357 *
358 * @param value the value for the entry.
359 */
360 @Override
361 public void entryRemoved(TopologyEvent value) {
362 EventEntry<TopologyEvent> eventEntry =
363 new EventEntry<TopologyEvent>(EventEntry.Type.ENTRY_REMOVE,
364 value);
365 topologyEvents.add(eventEntry);
366 }
Pavlin Radoslavov721a2e02014-02-14 23:40:14 -0800367
Ray Milkey269ffb92014-04-03 14:43:30 -0700368 /**
369 * Receive a notification that an entry is updated.
370 *
371 * @param value the value for the entry.
372 */
373 @Override
374 public void entryUpdated(TopologyEvent value) {
375 // NOTE: The ADD and UPDATE events are processed in same way
376 entryAdded(value);
377 }
Pavlin Radoslavov721a2e02014-02-14 23:40:14 -0800378 }
379
380 /**
381 * Startup processing.
382 *
383 * @param datagridService the datagrid service to use.
384 */
385 void startup(IDatagridService datagridService) {
Ray Milkey269ffb92014-04-03 14:43:30 -0700386 eventChannel = datagridService.addListener(EVENT_CHANNEL_NAME,
387 eventHandler,
388 byte[].class,
389 TopologyEvent.class);
390 eventHandler.start();
Pavlin Radoslavov721a2e02014-02-14 23:40:14 -0800391 }
392
Pavlin Radoslavov74986ce2014-02-20 13:17:20 -0800393 /**
Jonathan Harte37e4e22014-05-13 19:12:02 -0700394 * Dispatch Topology Events to the listeners.
Pavlin Radoslavov74986ce2014-02-20 13:17:20 -0800395 */
Jonathan Harte37e4e22014-05-13 19:12:02 -0700396 private void dispatchTopologyEvents() {
Pavlin Radoslavovcac157d2014-07-31 13:54:08 -0700397 if (apiAddedMastershipEvents.isEmpty() &&
398 apiRemovedMastershipEvents.isEmpty() &&
399 apiAddedSwitchEvents.isEmpty() &&
Ray Milkey269ffb92014-04-03 14:43:30 -0700400 apiRemovedSwitchEvents.isEmpty() &&
401 apiAddedPortEvents.isEmpty() &&
402 apiRemovedPortEvents.isEmpty() &&
403 apiAddedLinkEvents.isEmpty() &&
404 apiRemovedLinkEvents.isEmpty() &&
Yuta HIGUCHIbfc77f02014-07-14 22:50:25 -0700405 apiAddedHostEvents.isEmpty() &&
406 apiRemovedHostEvents.isEmpty()) {
Ray Milkey269ffb92014-04-03 14:43:30 -0700407 return; // No events to dispatch
408 }
Pavlin Radoslavov74986ce2014-02-20 13:17:20 -0800409
Ray Milkey269ffb92014-04-03 14:43:30 -0700410 if (log.isDebugEnabled()) {
411 //
412 // Debug statements
413 // TODO: Those statements should be removed in the future
414 //
Pavlin Radoslavovcac157d2014-07-31 13:54:08 -0700415 for (MastershipEvent mastershipEvent : apiAddedMastershipEvents) {
416 log.debug("Dispatch Topology Event: ADDED {}",
417 mastershipEvent);
418 }
419 for (MastershipEvent mastershipEvent : apiRemovedMastershipEvents) {
420 log.debug("Dispatch Topology Event: REMOVED {}",
421 mastershipEvent);
422 }
Ray Milkeyb29e6262014-04-09 16:02:14 -0700423 for (SwitchEvent switchEvent : apiAddedSwitchEvents) {
Jonathan Harte37e4e22014-05-13 19:12:02 -0700424 log.debug("Dispatch Topology Event: ADDED {}", switchEvent);
Ray Milkeyb29e6262014-04-09 16:02:14 -0700425 }
426 for (SwitchEvent switchEvent : apiRemovedSwitchEvents) {
Jonathan Harte37e4e22014-05-13 19:12:02 -0700427 log.debug("Dispatch Topology Event: REMOVED {}", switchEvent);
Ray Milkeyb29e6262014-04-09 16:02:14 -0700428 }
429 for (PortEvent portEvent : apiAddedPortEvents) {
Jonathan Harte37e4e22014-05-13 19:12:02 -0700430 log.debug("Dispatch Topology Event: ADDED {}", portEvent);
Ray Milkeyb29e6262014-04-09 16:02:14 -0700431 }
432 for (PortEvent portEvent : apiRemovedPortEvents) {
Jonathan Harte37e4e22014-05-13 19:12:02 -0700433 log.debug("Dispatch Topology Event: REMOVED {}", portEvent);
Ray Milkeyb29e6262014-04-09 16:02:14 -0700434 }
435 for (LinkEvent linkEvent : apiAddedLinkEvents) {
Jonathan Harte37e4e22014-05-13 19:12:02 -0700436 log.debug("Dispatch Topology Event: ADDED {}", linkEvent);
Ray Milkeyb29e6262014-04-09 16:02:14 -0700437 }
438 for (LinkEvent linkEvent : apiRemovedLinkEvents) {
Jonathan Harte37e4e22014-05-13 19:12:02 -0700439 log.debug("Dispatch Topology Event: REMOVED {}", linkEvent);
Ray Milkeyb29e6262014-04-09 16:02:14 -0700440 }
Yuta HIGUCHIbfc77f02014-07-14 22:50:25 -0700441 for (HostEvent hostEvent : apiAddedHostEvents) {
442 log.debug("Dispatch Topology Event: ADDED {}", hostEvent);
Ray Milkeyb29e6262014-04-09 16:02:14 -0700443 }
Yuta HIGUCHIbfc77f02014-07-14 22:50:25 -0700444 for (HostEvent hostEvent : apiRemovedHostEvents) {
445 log.debug("Dispatch Topology Event: REMOVED {}", hostEvent);
Ray Milkeyb29e6262014-04-09 16:02:14 -0700446 }
Ray Milkey269ffb92014-04-03 14:43:30 -0700447 }
adminbc181552014-02-21 18:36:42 -0800448
Pavlin Radoslavovd4f40372014-07-18 16:58:40 -0700449 //
450 // Update the metrics
451 //
452 long totalEvents =
Pavlin Radoslavovcac157d2014-07-31 13:54:08 -0700453 apiAddedMastershipEvents.size() + apiRemovedMastershipEvents.size() +
Pavlin Radoslavovd4f40372014-07-18 16:58:40 -0700454 apiAddedSwitchEvents.size() + apiRemovedSwitchEvents.size() +
455 apiAddedPortEvents.size() + apiRemovedPortEvents.size() +
456 apiAddedLinkEvents.size() + apiRemovedLinkEvents.size() +
457 apiAddedHostEvents.size() + apiRemovedHostEvents.size();
458 this.listenerEventRate.mark(totalEvents);
Pavlin Radoslavovc49917c2014-07-23 12:16:29 -0700459 this.lastEventTimestampEpochMs = System.currentTimeMillis();
Pavlin Radoslavovd4f40372014-07-18 16:58:40 -0700460
461 //
Ray Milkey269ffb92014-04-03 14:43:30 -0700462 // Deliver the events
Pavlin Radoslavovd4f40372014-07-18 16:58:40 -0700463 //
Jonathan Harte37e4e22014-05-13 19:12:02 -0700464 for (ITopologyListener listener : this.topologyListeners) {
Pavlin Radoslavov4eaab992014-07-03 18:39:42 -0700465 TopologyEvents events =
Pavlin Radoslavovcac157d2014-07-31 13:54:08 -0700466 new TopologyEvents(kryo.copy(apiAddedMastershipEvents),
467 kryo.copy(apiRemovedMastershipEvents),
468 kryo.copy(apiAddedSwitchEvents),
Pavlin Radoslavov4eaab992014-07-03 18:39:42 -0700469 kryo.copy(apiRemovedSwitchEvents),
470 kryo.copy(apiAddedPortEvents),
471 kryo.copy(apiRemovedPortEvents),
472 kryo.copy(apiAddedLinkEvents),
473 kryo.copy(apiRemovedLinkEvents),
Yuta HIGUCHIbfc77f02014-07-14 22:50:25 -0700474 kryo.copy(apiAddedHostEvents),
475 kryo.copy(apiRemovedHostEvents));
Pavlin Radoslavov4eaab992014-07-03 18:39:42 -0700476 listener.topologyEvents(events);
Ray Milkey269ffb92014-04-03 14:43:30 -0700477 }
Pavlin Radoslavov74986ce2014-02-20 13:17:20 -0800478
Ray Milkey269ffb92014-04-03 14:43:30 -0700479 //
480 // Cleanup
481 //
Pavlin Radoslavovcac157d2014-07-31 13:54:08 -0700482 apiAddedMastershipEvents.clear();
483 apiRemovedMastershipEvents.clear();
Ray Milkey269ffb92014-04-03 14:43:30 -0700484 apiAddedSwitchEvents.clear();
485 apiRemovedSwitchEvents.clear();
486 apiAddedPortEvents.clear();
487 apiRemovedPortEvents.clear();
488 apiAddedLinkEvents.clear();
489 apiRemovedLinkEvents.clear();
Yuta HIGUCHIbfc77f02014-07-14 22:50:25 -0700490 apiAddedHostEvents.clear();
491 apiRemovedHostEvents.clear();
Pavlin Radoslavov74986ce2014-02-20 13:17:20 -0800492 }
493
494 /**
Pavlin Radoslavovcac157d2014-07-31 13:54:08 -0700495 * Mastership updated event.
496 *
497 * @param mastershipEvent the mastership event.
498 */
499 @Override
500 public void putSwitchMastershipEvent(MastershipEvent mastershipEvent) {
501 // Send out notification
502 TopologyEvent topologyEvent =
503 new TopologyEvent(mastershipEvent,
504 registryService.getOnosInstanceId());
505 eventChannel.addEntry(topologyEvent.getID(), topologyEvent);
506 }
507
508 /**
509 * Mastership removed event.
510 *
511 * @param mastershipEvent the mastership event.
512 */
513 @Override
514 public void removeSwitchMastershipEvent(MastershipEvent mastershipEvent) {
515 // Send out notification
Pavlin Radoslavovbb17de22014-08-06 15:34:37 -0700516 TopologyEvent topologyEvent =
517 new TopologyEvent(mastershipEvent,
518 registryService.getOnosInstanceId());
519 eventChannel.removeEntry(topologyEvent.getID());
Pavlin Radoslavovcac157d2014-07-31 13:54:08 -0700520 }
521
522 /**
Pavlin Radoslavov734ff5a2014-02-26 10:20:43 -0800523 * Switch discovered event.
524 *
525 * @param switchEvent the switch event.
Ray Milkey269ffb92014-04-03 14:43:30 -0700526 * @param portEvents the corresponding port events for the switch.
Pavlin Radoslavov734ff5a2014-02-26 10:20:43 -0800527 */
Pavlin Radoslavovc1cfde52014-02-19 11:35:29 -0800528 @Override
Pavlin Radoslavov018d5332014-02-19 23:08:35 -0800529 public void putSwitchDiscoveryEvent(SwitchEvent switchEvent,
Ray Milkey269ffb92014-04-03 14:43:30 -0700530 Collection<PortEvent> portEvents) {
531 if (datastore.addSwitch(switchEvent, portEvents)) {
Jonathan Hart92c819f2014-05-30 10:53:30 -0700532 log.debug("Sending add switch: {}", switchEvent);
Ray Milkey269ffb92014-04-03 14:43:30 -0700533 // Send out notification
Pavlin Radoslavova5637c02014-07-30 15:55:11 -0700534 TopologyEvent topologyEvent =
535 new TopologyEvent(switchEvent,
536 registryService.getOnosInstanceId());
Ray Milkey269ffb92014-04-03 14:43:30 -0700537 eventChannel.addEntry(topologyEvent.getID(), topologyEvent);
Pavlin Radoslavov26d83402014-02-20 15:24:30 -0800538
Ray Milkey269ffb92014-04-03 14:43:30 -0700539 // Send out notification for each port
540 for (PortEvent portEvent : portEvents) {
Jonathan Hart92c819f2014-05-30 10:53:30 -0700541 log.debug("Sending add port: {}", portEvent);
Pavlin Radoslavova5637c02014-07-30 15:55:11 -0700542 topologyEvent =
543 new TopologyEvent(portEvent,
544 registryService.getOnosInstanceId());
Ray Milkey269ffb92014-04-03 14:43:30 -0700545 eventChannel.addEntry(topologyEvent.getID(), topologyEvent);
546 }
Pavlin Radoslavov26d83402014-02-20 15:24:30 -0800547
Ray Milkey269ffb92014-04-03 14:43:30 -0700548 //
549 // Keep track of the added ports
550 //
551 // Get the old Port Events
552 Map<ByteBuffer, PortEvent> oldPortEvents =
553 discoveredAddedPortEvents.get(switchEvent.getDpid());
Ray Milkeyb29e6262014-04-09 16:02:14 -0700554 if (oldPortEvents == null) {
Ray Milkey269ffb92014-04-03 14:43:30 -0700555 oldPortEvents = new HashMap<>();
Ray Milkeyb29e6262014-04-09 16:02:14 -0700556 }
Pavlin Radoslavov26d83402014-02-20 15:24:30 -0800557
Ray Milkey269ffb92014-04-03 14:43:30 -0700558 // Store the new Port Events in the local cache
559 Map<ByteBuffer, PortEvent> newPortEvents = new HashMap<>();
560 for (PortEvent portEvent : portEvents) {
561 ByteBuffer id = portEvent.getIDasByteBuffer();
562 newPortEvents.put(id, portEvent);
563 }
564 discoveredAddedPortEvents.put(switchEvent.getDpid(),
565 newPortEvents);
Pavlin Radoslavov26d83402014-02-20 15:24:30 -0800566
Ray Milkey269ffb92014-04-03 14:43:30 -0700567 //
568 // Extract the removed ports
569 //
570 List<PortEvent> removedPortEvents = new LinkedList<>();
571 for (Map.Entry<ByteBuffer, PortEvent> entry : oldPortEvents.entrySet()) {
572 ByteBuffer key = entry.getKey();
573 PortEvent portEvent = entry.getValue();
Ray Milkeyb29e6262014-04-09 16:02:14 -0700574 if (!newPortEvents.containsKey(key)) {
Ray Milkey269ffb92014-04-03 14:43:30 -0700575 removedPortEvents.add(portEvent);
Ray Milkeyb29e6262014-04-09 16:02:14 -0700576 }
Ray Milkey269ffb92014-04-03 14:43:30 -0700577 }
578
579 // Cleanup old removed ports
Ray Milkeyb29e6262014-04-09 16:02:14 -0700580 for (PortEvent portEvent : removedPortEvents) {
Ray Milkey269ffb92014-04-03 14:43:30 -0700581 removePortDiscoveryEvent(portEvent);
Ray Milkeyb29e6262014-04-09 16:02:14 -0700582 }
Ray Milkey269ffb92014-04-03 14:43:30 -0700583 }
Pavlin Radoslavovc1cfde52014-02-19 11:35:29 -0800584 }
585
Pavlin Radoslavov734ff5a2014-02-26 10:20:43 -0800586 /**
Yuta HIGUCHIbc67a052014-06-30 10:37:09 -0700587 * {@inheritDoc}
588 * <p/>
589 * Called by {@link TopologyPublisher.SwitchCleanup} thread.
Pavlin Radoslavov734ff5a2014-02-26 10:20:43 -0800590 */
Pavlin Radoslavovc1cfde52014-02-19 11:35:29 -0800591 @Override
Pavlin Radoslavov6ea84a42014-02-19 15:50:01 -0800592 public void removeSwitchDiscoveryEvent(SwitchEvent switchEvent) {
Pavlin Radoslavovbb17de22014-08-06 15:34:37 -0700593 TopologyEvent topologyEvent;
594
Ray Milkey269ffb92014-04-03 14:43:30 -0700595 // Get the old Port Events
596 Map<ByteBuffer, PortEvent> oldPortEvents =
597 discoveredAddedPortEvents.get(switchEvent.getDpid());
Ray Milkeyb29e6262014-04-09 16:02:14 -0700598 if (oldPortEvents == null) {
Ray Milkey269ffb92014-04-03 14:43:30 -0700599 oldPortEvents = new HashMap<>();
Ray Milkeyb29e6262014-04-09 16:02:14 -0700600 }
Pavlin Radoslavov018d5332014-02-19 23:08:35 -0800601
Ray Milkey269ffb92014-04-03 14:43:30 -0700602 if (datastore.deactivateSwitch(switchEvent, oldPortEvents.values())) {
Jonathan Hart92c819f2014-05-30 10:53:30 -0700603 log.debug("Sending remove switch: {}", switchEvent);
Ray Milkey269ffb92014-04-03 14:43:30 -0700604 // Send out notification
Pavlin Radoslavovbb17de22014-08-06 15:34:37 -0700605 topologyEvent =
606 new TopologyEvent(switchEvent,
607 registryService.getOnosInstanceId());
608 eventChannel.removeEntry(topologyEvent.getID());
Pavlin Radoslavov018d5332014-02-19 23:08:35 -0800609
Ray Milkey269ffb92014-04-03 14:43:30 -0700610 //
611 // Send out notification for each port.
612 //
613 // NOTE: We don't use removePortDiscoveryEvent() for the cleanup,
614 // because it will attempt to remove the port from the database,
615 // and the deactiveSwitch() call above already removed all ports.
616 //
Ray Milkeyb29e6262014-04-09 16:02:14 -0700617 for (PortEvent portEvent : oldPortEvents.values()) {
Jonathan Hart92c819f2014-05-30 10:53:30 -0700618 log.debug("Sending remove port:", portEvent);
Pavlin Radoslavovbb17de22014-08-06 15:34:37 -0700619 topologyEvent =
620 new TopologyEvent(portEvent,
621 registryService.getOnosInstanceId());
622 eventChannel.removeEntry(topologyEvent.getID());
Ray Milkeyb29e6262014-04-09 16:02:14 -0700623 }
Ray Milkey269ffb92014-04-03 14:43:30 -0700624 discoveredAddedPortEvents.remove(switchEvent.getDpid());
Pavlin Radoslavov26d83402014-02-20 15:24:30 -0800625
Ray Milkey269ffb92014-04-03 14:43:30 -0700626 // Cleanup for each link
627 Map<ByteBuffer, LinkEvent> oldLinkEvents =
628 discoveredAddedLinkEvents.get(switchEvent.getDpid());
629 if (oldLinkEvents != null) {
630 for (LinkEvent linkEvent : new ArrayList<>(oldLinkEvents.values())) {
631 removeLinkDiscoveryEvent(linkEvent);
632 }
633 discoveredAddedLinkEvents.remove(switchEvent.getDpid());
634 }
Pavlin Radoslavov26d83402014-02-20 15:24:30 -0800635
Yuta HIGUCHIbfc77f02014-07-14 22:50:25 -0700636 // Cleanup for each host
637 Map<ByteBuffer, HostEvent> oldHostEvents =
638 discoveredAddedHostEvents.get(switchEvent.getDpid());
639 if (oldHostEvents != null) {
640 for (HostEvent hostEvent : new ArrayList<>(oldHostEvents.values())) {
641 removeHostDiscoveryEvent(hostEvent);
Ray Milkey269ffb92014-04-03 14:43:30 -0700642 }
Yuta HIGUCHIbfc77f02014-07-14 22:50:25 -0700643 discoveredAddedHostEvents.remove(switchEvent.getDpid());
Ray Milkey269ffb92014-04-03 14:43:30 -0700644 }
645 }
Pavlin Radoslavovc1cfde52014-02-19 11:35:29 -0800646 }
647
Pavlin Radoslavov734ff5a2014-02-26 10:20:43 -0800648 /**
649 * Port discovered event.
650 *
651 * @param portEvent the port event.
652 */
Pavlin Radoslavovc1cfde52014-02-19 11:35:29 -0800653 @Override
Pavlin Radoslavov6ea84a42014-02-19 15:50:01 -0800654 public void putPortDiscoveryEvent(PortEvent portEvent) {
Ray Milkey269ffb92014-04-03 14:43:30 -0700655 if (datastore.addPort(portEvent)) {
Jonathan Hart92c819f2014-05-30 10:53:30 -0700656 log.debug("Sending add port: {}", portEvent);
Ray Milkey269ffb92014-04-03 14:43:30 -0700657 // Send out notification
Pavlin Radoslavova5637c02014-07-30 15:55:11 -0700658 TopologyEvent topologyEvent =
659 new TopologyEvent(portEvent,
660 registryService.getOnosInstanceId());
Ray Milkey269ffb92014-04-03 14:43:30 -0700661 eventChannel.addEntry(topologyEvent.getID(), topologyEvent);
Pavlin Radoslavov26d83402014-02-20 15:24:30 -0800662
Ray Milkey269ffb92014-04-03 14:43:30 -0700663 // Store the new Port Event in the local cache
664 Map<ByteBuffer, PortEvent> oldPortEvents =
665 discoveredAddedPortEvents.get(portEvent.getDpid());
666 if (oldPortEvents == null) {
667 oldPortEvents = new HashMap<>();
668 discoveredAddedPortEvents.put(portEvent.getDpid(),
669 oldPortEvents);
670 }
671 ByteBuffer id = portEvent.getIDasByteBuffer();
672 oldPortEvents.put(id, portEvent);
673 }
Pavlin Radoslavovc1cfde52014-02-19 11:35:29 -0800674 }
675
Pavlin Radoslavov734ff5a2014-02-26 10:20:43 -0800676 /**
677 * Port removed event.
678 *
679 * @param portEvent the port event.
680 */
Pavlin Radoslavovc1cfde52014-02-19 11:35:29 -0800681 @Override
Pavlin Radoslavov6ea84a42014-02-19 15:50:01 -0800682 public void removePortDiscoveryEvent(PortEvent portEvent) {
Ray Milkey269ffb92014-04-03 14:43:30 -0700683 if (datastore.deactivatePort(portEvent)) {
Jonathan Hart92c819f2014-05-30 10:53:30 -0700684 log.debug("Sending remove port: {}", portEvent);
Ray Milkey269ffb92014-04-03 14:43:30 -0700685 // Send out notification
Pavlin Radoslavovbb17de22014-08-06 15:34:37 -0700686 TopologyEvent topologyEvent =
687 new TopologyEvent(portEvent,
688 registryService.getOnosInstanceId());
689 eventChannel.removeEntry(topologyEvent.getID());
Pavlin Radoslavov26d83402014-02-20 15:24:30 -0800690
Ray Milkey269ffb92014-04-03 14:43:30 -0700691 // Cleanup the Port Event from the local cache
692 Map<ByteBuffer, PortEvent> oldPortEvents =
693 discoveredAddedPortEvents.get(portEvent.getDpid());
694 if (oldPortEvents != null) {
695 ByteBuffer id = portEvent.getIDasByteBuffer();
696 oldPortEvents.remove(id);
697 }
Pavlin Radoslavov26d83402014-02-20 15:24:30 -0800698
Ray Milkey269ffb92014-04-03 14:43:30 -0700699 // Cleanup for the incoming link
700 Map<ByteBuffer, LinkEvent> oldLinkEvents =
701 discoveredAddedLinkEvents.get(portEvent.getDpid());
702 if (oldLinkEvents != null) {
703 for (LinkEvent linkEvent : new ArrayList<>(oldLinkEvents.values())) {
Yuta HIGUCHIbf0a8712014-06-30 18:59:46 -0700704 if (linkEvent.getDst().equals(portEvent.getSwitchPort())) {
Ray Milkey269ffb92014-04-03 14:43:30 -0700705 removeLinkDiscoveryEvent(linkEvent);
706 // XXX If we change our model to allow multiple Link on
707 // a Port, this loop must be fixed to allow continuing.
708 break;
709 }
710 }
711 }
Pavlin Radoslavov26d83402014-02-20 15:24:30 -0800712
Yuta HIGUCHIbfc77f02014-07-14 22:50:25 -0700713 // Cleanup for the connected hosts
Ray Milkey269ffb92014-04-03 14:43:30 -0700714 // TODO: The implementation below is probably wrong
Yuta HIGUCHIbfc77f02014-07-14 22:50:25 -0700715 List<HostEvent> removedHostEvents = new LinkedList<>();
716 Map<ByteBuffer, HostEvent> oldHostEvents =
717 discoveredAddedHostEvents.get(portEvent.getDpid());
718 if (oldHostEvents != null) {
719 for (HostEvent hostEvent : new ArrayList<>(oldHostEvents.values())) {
720 for (SwitchPort swp : hostEvent.getAttachmentPoints()) {
Yuta HIGUCHIbf0a8712014-06-30 18:59:46 -0700721 if (swp.equals(portEvent.getSwitchPort())) {
Yuta HIGUCHIbfc77f02014-07-14 22:50:25 -0700722 removedHostEvents.add(hostEvent);
Ray Milkey269ffb92014-04-03 14:43:30 -0700723 }
724 }
725 }
Yuta HIGUCHIbfc77f02014-07-14 22:50:25 -0700726 for (HostEvent hostEvent : removedHostEvents) {
727 removeHostDiscoveryEvent(hostEvent);
Ray Milkeyb29e6262014-04-09 16:02:14 -0700728 }
Ray Milkey269ffb92014-04-03 14:43:30 -0700729 }
730 }
Pavlin Radoslavovc1cfde52014-02-19 11:35:29 -0800731 }
732
Pavlin Radoslavov734ff5a2014-02-26 10:20:43 -0800733 /**
734 * Link discovered event.
735 *
736 * @param linkEvent the link event.
737 */
Pavlin Radoslavovc1cfde52014-02-19 11:35:29 -0800738 @Override
Pavlin Radoslavov6ea84a42014-02-19 15:50:01 -0800739 public void putLinkDiscoveryEvent(LinkEvent linkEvent) {
Ray Milkey269ffb92014-04-03 14:43:30 -0700740 if (datastore.addLink(linkEvent)) {
Jonathan Hart92c819f2014-05-30 10:53:30 -0700741 log.debug("Sending add link: {}", linkEvent);
Ray Milkey269ffb92014-04-03 14:43:30 -0700742 // Send out notification
Pavlin Radoslavova5637c02014-07-30 15:55:11 -0700743 TopologyEvent topologyEvent =
744 new TopologyEvent(linkEvent,
745 registryService.getOnosInstanceId());
Ray Milkey269ffb92014-04-03 14:43:30 -0700746 eventChannel.addEntry(topologyEvent.getID(), topologyEvent);
Pavlin Radoslavov26d83402014-02-20 15:24:30 -0800747
Ray Milkey269ffb92014-04-03 14:43:30 -0700748 // Store the new Link Event in the local cache
749 Map<ByteBuffer, LinkEvent> oldLinkEvents =
750 discoveredAddedLinkEvents.get(linkEvent.getDst().getDpid());
751 if (oldLinkEvents == null) {
752 oldLinkEvents = new HashMap<>();
753 discoveredAddedLinkEvents.put(linkEvent.getDst().getDpid(),
754 oldLinkEvents);
755 }
756 ByteBuffer id = linkEvent.getIDasByteBuffer();
757 oldLinkEvents.put(id, linkEvent);
758 }
Pavlin Radoslavovc1cfde52014-02-19 11:35:29 -0800759 }
760
Pavlin Radoslavov734ff5a2014-02-26 10:20:43 -0800761 /**
762 * Link removed event.
763 *
764 * @param linkEvent the link event.
765 */
Pavlin Radoslavovc1cfde52014-02-19 11:35:29 -0800766 @Override
Pavlin Radoslavov6ea84a42014-02-19 15:50:01 -0800767 public void removeLinkDiscoveryEvent(LinkEvent linkEvent) {
Ray Milkey269ffb92014-04-03 14:43:30 -0700768 if (datastore.removeLink(linkEvent)) {
Jonathan Hart92c819f2014-05-30 10:53:30 -0700769 log.debug("Sending remove link: {}", linkEvent);
Ray Milkey269ffb92014-04-03 14:43:30 -0700770 // Send out notification
Pavlin Radoslavovbb17de22014-08-06 15:34:37 -0700771 TopologyEvent topologyEvent =
772 new TopologyEvent(linkEvent,
773 registryService.getOnosInstanceId());
774 eventChannel.removeEntry(topologyEvent.getID());
Pavlin Radoslavov26d83402014-02-20 15:24:30 -0800775
Ray Milkey269ffb92014-04-03 14:43:30 -0700776 // Cleanup the Link Event from the local cache
777 Map<ByteBuffer, LinkEvent> oldLinkEvents =
778 discoveredAddedLinkEvents.get(linkEvent.getDst().getDpid());
779 if (oldLinkEvents != null) {
780 ByteBuffer id = linkEvent.getIDasByteBuffer();
781 oldLinkEvents.remove(id);
782 }
783 }
Pavlin Radoslavovc1cfde52014-02-19 11:35:29 -0800784 }
Jonathan Hart22eb9882014-02-11 15:52:59 -0800785
Pavlin Radoslavov734ff5a2014-02-26 10:20:43 -0800786 /**
Yuta HIGUCHIbfc77f02014-07-14 22:50:25 -0700787 * Host discovered event.
Pavlin Radoslavov734ff5a2014-02-26 10:20:43 -0800788 *
Yuta HIGUCHIbfc77f02014-07-14 22:50:25 -0700789 * @param hostEvent the host event.
Pavlin Radoslavov734ff5a2014-02-26 10:20:43 -0800790 */
Pavlin Radoslavovc1cfde52014-02-19 11:35:29 -0800791 @Override
Yuta HIGUCHIbfc77f02014-07-14 22:50:25 -0700792 public void putHostDiscoveryEvent(HostEvent hostEvent) {
793 if (datastore.addHost(hostEvent)) {
Ray Milkey269ffb92014-04-03 14:43:30 -0700794 // Send out notification
Pavlin Radoslavova5637c02014-07-30 15:55:11 -0700795 TopologyEvent topologyEvent =
796 new TopologyEvent(hostEvent,
797 registryService.getOnosInstanceId());
Ray Milkey269ffb92014-04-03 14:43:30 -0700798 eventChannel.addEntry(topologyEvent.getID(), topologyEvent);
Yuta HIGUCHIbfc77f02014-07-14 22:50:25 -0700799 log.debug("Put the host info into the cache of the topology. mac {}", hostEvent.getMac());
Ray Milkey269ffb92014-04-03 14:43:30 -0700800
Yuta HIGUCHIbfc77f02014-07-14 22:50:25 -0700801 // Store the new Host Event in the local cache
Ray Milkey269ffb92014-04-03 14:43:30 -0700802 // TODO: The implementation below is probably wrong
Yuta HIGUCHIbfc77f02014-07-14 22:50:25 -0700803 for (SwitchPort swp : hostEvent.getAttachmentPoints()) {
804 Map<ByteBuffer, HostEvent> oldHostEvents =
805 discoveredAddedHostEvents.get(swp.getDpid());
806 if (oldHostEvents == null) {
807 oldHostEvents = new HashMap<>();
808 discoveredAddedHostEvents.put(swp.getDpid(),
809 oldHostEvents);
Ray Milkey269ffb92014-04-03 14:43:30 -0700810 }
Yuta HIGUCHIbfc77f02014-07-14 22:50:25 -0700811 ByteBuffer id = hostEvent.getIDasByteBuffer();
812 oldHostEvents.put(id, hostEvent);
Ray Milkey269ffb92014-04-03 14:43:30 -0700813 }
814 }
Pavlin Radoslavovc1cfde52014-02-19 11:35:29 -0800815 }
Jonathan Hart22eb9882014-02-11 15:52:59 -0800816
Pavlin Radoslavov734ff5a2014-02-26 10:20:43 -0800817 /**
Yuta HIGUCHIbfc77f02014-07-14 22:50:25 -0700818 * Host removed event.
Pavlin Radoslavov734ff5a2014-02-26 10:20:43 -0800819 *
Yuta HIGUCHIbfc77f02014-07-14 22:50:25 -0700820 * @param hostEvent the host event.
Pavlin Radoslavov734ff5a2014-02-26 10:20:43 -0800821 */
Pavlin Radoslavovc1cfde52014-02-19 11:35:29 -0800822 @Override
Yuta HIGUCHIbfc77f02014-07-14 22:50:25 -0700823 public void removeHostDiscoveryEvent(HostEvent hostEvent) {
824 if (datastore.removeHost(hostEvent)) {
Ray Milkey269ffb92014-04-03 14:43:30 -0700825 // Send out notification
Pavlin Radoslavovbb17de22014-08-06 15:34:37 -0700826 TopologyEvent topologyEvent =
827 new TopologyEvent(hostEvent,
828 registryService.getOnosInstanceId());
829 eventChannel.removeEntry(topologyEvent.getID());
Yuta HIGUCHIbfc77f02014-07-14 22:50:25 -0700830 log.debug("Remove the host info into the cache of the topology. mac {}", hostEvent.getMac());
Pavlin Radoslavov26d83402014-02-20 15:24:30 -0800831
Yuta HIGUCHIbfc77f02014-07-14 22:50:25 -0700832 // Cleanup the Host Event from the local cache
Ray Milkey269ffb92014-04-03 14:43:30 -0700833 // TODO: The implementation below is probably wrong
Yuta HIGUCHIbfc77f02014-07-14 22:50:25 -0700834 ByteBuffer id = ByteBuffer.wrap(hostEvent.getID());
835 for (SwitchPort swp : hostEvent.getAttachmentPoints()) {
836 Map<ByteBuffer, HostEvent> oldHostEvents =
837 discoveredAddedHostEvents.get(swp.getDpid());
838 if (oldHostEvents != null) {
839 oldHostEvents.remove(id);
Ray Milkey269ffb92014-04-03 14:43:30 -0700840 }
841 }
842 }
Pavlin Radoslavovc1cfde52014-02-19 11:35:29 -0800843 }
Jonathan Hart22eb9882014-02-11 15:52:59 -0800844
Yuta HIGUCHI8b389a72014-07-18 13:50:00 -0700845 //
846 // Methods to update topology replica
847 //
848
Pavlin Radoslavov734ff5a2014-02-26 10:20:43 -0800849 /**
Pavlin Radoslavovd7b792e2014-08-01 02:47:47 -0700850 * Adds Switch Mastership event.
Pavlin Radoslavov695f8952014-07-23 16:57:01 -0700851 *
Pavlin Radoslavovcac157d2014-07-31 13:54:08 -0700852 * @param mastershipEvent the MastershipEvent to process.
Pavlin Radoslavovd7b792e2014-08-01 02:47:47 -0700853 * @return true if the item was successfully added, otherwise false.
Pavlin Radoslavov695f8952014-07-23 16:57:01 -0700854 */
Pavlin Radoslavovcac157d2014-07-31 13:54:08 -0700855 @GuardedBy("topology.writeLock")
Pavlin Radoslavovd7b792e2014-08-01 02:47:47 -0700856 private boolean addMastershipEvent(MastershipEvent mastershipEvent) {
857 log.debug("Added Mastership event {}", mastershipEvent);
Pavlin Radoslavovcac157d2014-07-31 13:54:08 -0700858 apiAddedMastershipEvents.add(mastershipEvent);
Pavlin Radoslavovd7b792e2014-08-01 02:47:47 -0700859 return true;
Pavlin Radoslavov695f8952014-07-23 16:57:01 -0700860 }
861
862 /**
Pavlin Radoslavovd7b792e2014-08-01 02:47:47 -0700863 * Removes Switch Mastership event.
Pavlin Radoslavov695f8952014-07-23 16:57:01 -0700864 *
Pavlin Radoslavovcac157d2014-07-31 13:54:08 -0700865 * @param mastershipEvent the MastershipEvent to process.
Pavlin Radoslavov695f8952014-07-23 16:57:01 -0700866 */
Pavlin Radoslavovcac157d2014-07-31 13:54:08 -0700867 @GuardedBy("topology.writeLock")
Pavlin Radoslavovd7b792e2014-08-01 02:47:47 -0700868 private void removeMastershipEvent(MastershipEvent mastershipEvent) {
869 log.debug("Removed Mastership event {}", mastershipEvent);
Pavlin Radoslavovcac157d2014-07-31 13:54:08 -0700870 apiRemovedMastershipEvents.add(mastershipEvent);
Pavlin Radoslavov695f8952014-07-23 16:57:01 -0700871 }
872
873 /**
Yuta HIGUCHI7926ba32014-07-09 11:39:32 -0700874 * Adds a switch to the topology replica.
Pavlin Radoslavov734ff5a2014-02-26 10:20:43 -0800875 *
Yuta HIGUCHIbf0a8712014-06-30 18:59:46 -0700876 * @param switchEvent the SwitchEvent with the switch to add.
Pavlin Radoslavovd7b792e2014-08-01 02:47:47 -0700877 * @return true if the item was successfully added, otherwise false.
Pavlin Radoslavov734ff5a2014-02-26 10:20:43 -0800878 */
Yuta HIGUCHIbc67a052014-06-30 10:37:09 -0700879 @GuardedBy("topology.writeLock")
Pavlin Radoslavovd7b792e2014-08-01 02:47:47 -0700880 private boolean addSwitch(SwitchEvent switchEvent) {
Yuta HIGUCHI8b389a72014-07-18 13:50:00 -0700881 if (log.isDebugEnabled()) {
882 SwitchEvent sw = topology.getSwitchEvent(switchEvent.getDpid());
883 if (sw != null) {
884 log.debug("Update {}", switchEvent);
885 } else {
886 log.debug("Added {}", switchEvent);
887 }
Ray Milkey269ffb92014-04-03 14:43:30 -0700888 }
Yuta HIGUCHI8b389a72014-07-18 13:50:00 -0700889 topology.putSwitch(switchEvent.freeze());
Ray Milkey269ffb92014-04-03 14:43:30 -0700890 apiAddedSwitchEvents.add(switchEvent);
Pavlin Radoslavovd7b792e2014-08-01 02:47:47 -0700891 return true;
Pavlin Radoslavov3c9cc552014-02-20 09:58:38 -0800892 }
893
Pavlin Radoslavov734ff5a2014-02-26 10:20:43 -0800894 /**
Yuta HIGUCHI7926ba32014-07-09 11:39:32 -0700895 * Removes a switch from the topology replica.
Yuta HIGUCHIbf0a8712014-06-30 18:59:46 -0700896 * <p/>
Pavlin Radoslavovd7b792e2014-08-01 02:47:47 -0700897 * It will call {@link #removePort(PortEvent)} for each ports on this
898 * switch.
Pavlin Radoslavov734ff5a2014-02-26 10:20:43 -0800899 *
Yuta HIGUCHIbf0a8712014-06-30 18:59:46 -0700900 * @param switchEvent the SwitchEvent with the switch to remove.
Pavlin Radoslavov734ff5a2014-02-26 10:20:43 -0800901 */
Yuta HIGUCHIbc67a052014-06-30 10:37:09 -0700902 @GuardedBy("topology.writeLock")
Pavlin Radoslavov74986ce2014-02-20 13:17:20 -0800903 private void removeSwitch(SwitchEvent switchEvent) {
Yuta HIGUCHI8b389a72014-07-18 13:50:00 -0700904 final Dpid dpid = switchEvent.getDpid();
905
906 SwitchEvent swInTopo = topology.getSwitchEvent(dpid);
907 if (swInTopo == null) {
Ray Milkey269ffb92014-04-03 14:43:30 -0700908 log.warn("Switch {} already removed, ignoring", switchEvent);
909 return;
910 }
Pavlin Radoslavov3c9cc552014-02-20 09:58:38 -0800911
Ray Milkey269ffb92014-04-03 14:43:30 -0700912 //
913 // Remove all Ports on the Switch
914 //
915 ArrayList<PortEvent> portsToRemove = new ArrayList<>();
Yuta HIGUCHI8b389a72014-07-18 13:50:00 -0700916 for (Port port : topology.getPorts(dpid)) {
Ray Milkey269ffb92014-04-03 14:43:30 -0700917 log.warn("Port {} on Switch {} should be removed prior to removing Switch. Removing Port now.",
918 port, switchEvent);
Yuta HIGUCHIcd14dda2014-07-24 09:57:22 -0700919 PortEvent portEvent = new PortEvent(port.getSwitchPort());
Ray Milkey269ffb92014-04-03 14:43:30 -0700920 portsToRemove.add(portEvent);
921 }
Ray Milkeyb29e6262014-04-09 16:02:14 -0700922 for (PortEvent portEvent : portsToRemove) {
Ray Milkey269ffb92014-04-03 14:43:30 -0700923 removePort(portEvent);
Ray Milkeyb29e6262014-04-09 16:02:14 -0700924 }
Pavlin Radoslavov3c9cc552014-02-20 09:58:38 -0800925
Yuta HIGUCHI8b389a72014-07-18 13:50:00 -0700926 log.debug("Removed {}", swInTopo);
927 topology.removeSwitch(dpid);
928 apiRemovedSwitchEvents.add(swInTopo);
Pavlin Radoslavov3c9cc552014-02-20 09:58:38 -0800929 }
930
Pavlin Radoslavov734ff5a2014-02-26 10:20:43 -0800931 /**
Yuta HIGUCHI7926ba32014-07-09 11:39:32 -0700932 * Adds a port to the topology replica.
Pavlin Radoslavov734ff5a2014-02-26 10:20:43 -0800933 *
Yuta HIGUCHIbf0a8712014-06-30 18:59:46 -0700934 * @param portEvent the PortEvent with the port to add.
Pavlin Radoslavovd7b792e2014-08-01 02:47:47 -0700935 * @return true if the item was successfully added, otherwise false.
Pavlin Radoslavov734ff5a2014-02-26 10:20:43 -0800936 */
Yuta HIGUCHIbc67a052014-06-30 10:37:09 -0700937 @GuardedBy("topology.writeLock")
Pavlin Radoslavovd7b792e2014-08-01 02:47:47 -0700938 private boolean addPort(PortEvent portEvent) {
Jonathan Harte37e4e22014-05-13 19:12:02 -0700939 Switch sw = topology.getSwitch(portEvent.getDpid());
Ray Milkey269ffb92014-04-03 14:43:30 -0700940 if (sw == null) {
Pavlin Radoslavovd7b792e2014-08-01 02:47:47 -0700941 // Reordered event
Jonathan Hartf1675202014-05-23 14:59:07 -0700942 log.debug("{} reordered because switch is null", portEvent);
Pavlin Radoslavovd7b792e2014-08-01 02:47:47 -0700943 return false;
Ray Milkey269ffb92014-04-03 14:43:30 -0700944 }
Pavlin Radoslavov3c9cc552014-02-20 09:58:38 -0800945
Yuta HIGUCHI8b389a72014-07-18 13:50:00 -0700946 if (log.isDebugEnabled()) {
947 PortEvent port = topology.getPortEvent(portEvent.getSwitchPort());
948 if (port != null) {
949 log.debug("Update {}", portEvent);
950 } else {
951 log.debug("Added {}", portEvent);
952 }
Ray Milkey269ffb92014-04-03 14:43:30 -0700953 }
Yuta HIGUCHI8b389a72014-07-18 13:50:00 -0700954 topology.putPort(portEvent.freeze());
Ray Milkey269ffb92014-04-03 14:43:30 -0700955 apiAddedPortEvents.add(portEvent);
Pavlin Radoslavovd7b792e2014-08-01 02:47:47 -0700956 return true;
Pavlin Radoslavov3c9cc552014-02-20 09:58:38 -0800957 }
958
Pavlin Radoslavov734ff5a2014-02-26 10:20:43 -0800959 /**
Yuta HIGUCHI7926ba32014-07-09 11:39:32 -0700960 * Removes a port from the topology replica.
Yuta HIGUCHIbf0a8712014-06-30 18:59:46 -0700961 * <p/>
Yuta HIGUCHI8b389a72014-07-18 13:50:00 -0700962 * It will remove attachment points from each hosts on this port
Yuta HIGUCHIbf0a8712014-06-30 18:59:46 -0700963 * and call {@link #removeLink(LinkEvent)} for each links on this port.
Pavlin Radoslavov734ff5a2014-02-26 10:20:43 -0800964 *
Yuta HIGUCHIbf0a8712014-06-30 18:59:46 -0700965 * @param portEvent the PortEvent with the port to remove.
Pavlin Radoslavov734ff5a2014-02-26 10:20:43 -0800966 */
Yuta HIGUCHIbc67a052014-06-30 10:37:09 -0700967 @GuardedBy("topology.writeLock")
Pavlin Radoslavov3c9cc552014-02-20 09:58:38 -0800968 private void removePort(PortEvent portEvent) {
Yuta HIGUCHI8b389a72014-07-18 13:50:00 -0700969 SwitchEvent sw = topology.getSwitchEvent(portEvent.getDpid());
Ray Milkey269ffb92014-04-03 14:43:30 -0700970 if (sw == null) {
971 log.warn("Parent Switch for Port {} already removed, ignoring",
972 portEvent);
973 return;
974 }
Pavlin Radoslavov3c9cc552014-02-20 09:58:38 -0800975
Yuta HIGUCHI8b389a72014-07-18 13:50:00 -0700976 final SwitchPort switchPort = portEvent.getSwitchPort();
977 PortEvent portInTopo = topology.getPortEvent(switchPort);
978 if (portInTopo == null) {
Ray Milkey269ffb92014-04-03 14:43:30 -0700979 log.warn("Port {} already removed, ignoring", portEvent);
980 return;
981 }
Pavlin Radoslavov3c9cc552014-02-20 09:58:38 -0800982
Ray Milkey269ffb92014-04-03 14:43:30 -0700983 //
Yuta HIGUCHI8b389a72014-07-18 13:50:00 -0700984 // Remove all Host attachment points bound to this Port
Ray Milkey269ffb92014-04-03 14:43:30 -0700985 //
Yuta HIGUCHI8b389a72014-07-18 13:50:00 -0700986 List<HostEvent> hostsToUpdate = new ArrayList<>();
987 for (Host host : topology.getHosts(switchPort)) {
988 log.debug("Removing Host {} on Port {}", host, portInTopo);
989 HostEvent hostEvent = topology.getHostEvent(host.getMacAddress());
990 hostsToUpdate.add(hostEvent);
Ray Milkey269ffb92014-04-03 14:43:30 -0700991 }
Yuta HIGUCHI8b389a72014-07-18 13:50:00 -0700992 for (HostEvent hostEvent : hostsToUpdate) {
993 HostEvent newHostEvent = new HostEvent(hostEvent);
994 newHostEvent.removeAttachmentPoint(switchPort);
995 newHostEvent.freeze();
996
997 // TODO should this event be fired inside #addHost?
998 if (newHostEvent.getAttachmentPoints().isEmpty()) {
999 // No more attachment point left -> remove Host
1000 removeHost(hostEvent);
1001 } else {
1002 // Update Host
1003 addHost(newHostEvent);
1004 }
Ray Milkeyb29e6262014-04-09 16:02:14 -07001005 }
Pavlin Radoslavov3c9cc552014-02-20 09:58:38 -08001006
Ray Milkey269ffb92014-04-03 14:43:30 -07001007 //
1008 // Remove all Links connected to the Port
1009 //
1010 Set<Link> links = new HashSet<>();
Yuta HIGUCHI8b389a72014-07-18 13:50:00 -07001011 links.addAll(topology.getOutgoingLinks(switchPort));
1012 links.addAll(topology.getIncomingLinks(switchPort));
Ray Milkey269ffb92014-04-03 14:43:30 -07001013 for (Link link : links) {
Ray Milkeyb29e6262014-04-09 16:02:14 -07001014 if (link == null) {
Ray Milkey269ffb92014-04-03 14:43:30 -07001015 continue;
Ray Milkeyb29e6262014-04-09 16:02:14 -07001016 }
Yuta HIGUCHI8b389a72014-07-18 13:50:00 -07001017 LinkEvent linkEvent = topology.getLinkEvent(link.getLinkTuple());
1018 if (linkEvent != null) {
1019 log.debug("Removing Link {} on Port {}", link, portInTopo);
1020 removeLink(linkEvent);
1021 }
Ray Milkeyb29e6262014-04-09 16:02:14 -07001022 }
Pavlin Radoslavov3c9cc552014-02-20 09:58:38 -08001023
Yuta HIGUCHI8b389a72014-07-18 13:50:00 -07001024 // Remove the Port from Topology
1025 log.debug("Removed {}", portInTopo);
1026 topology.removePort(switchPort);
Pavlin Radoslavov74986ce2014-02-20 13:17:20 -08001027
Yuta HIGUCHI8b389a72014-07-18 13:50:00 -07001028 apiRemovedPortEvents.add(portInTopo);
Pavlin Radoslavov3c9cc552014-02-20 09:58:38 -08001029 }
1030
Pavlin Radoslavov734ff5a2014-02-26 10:20:43 -08001031 /**
Yuta HIGUCHI7926ba32014-07-09 11:39:32 -07001032 * Adds a link to the topology replica.
Yuta HIGUCHIbf0a8712014-06-30 18:59:46 -07001033 * <p/>
Yuta HIGUCHI8b389a72014-07-18 13:50:00 -07001034 * It will remove attachment points from each hosts using the same ports.
Pavlin Radoslavov734ff5a2014-02-26 10:20:43 -08001035 *
Yuta HIGUCHIbf0a8712014-06-30 18:59:46 -07001036 * @param linkEvent the LinkEvent with the link to add.
Pavlin Radoslavovd7b792e2014-08-01 02:47:47 -07001037 * @return true if the item was successfully added, otherwise false.
Pavlin Radoslavov734ff5a2014-02-26 10:20:43 -08001038 */
Yuta HIGUCHIbc67a052014-06-30 10:37:09 -07001039 @GuardedBy("topology.writeLock")
Pavlin Radoslavovd7b792e2014-08-01 02:47:47 -07001040 private boolean addLink(LinkEvent linkEvent) {
Yuta HIGUCHI8b389a72014-07-18 13:50:00 -07001041 PortEvent srcPort = topology.getPortEvent(linkEvent.getSrc());
1042 PortEvent dstPort = topology.getPortEvent(linkEvent.getDst());
Ray Milkey269ffb92014-04-03 14:43:30 -07001043 if ((srcPort == null) || (dstPort == null)) {
Pavlin Radoslavovd7b792e2014-08-01 02:47:47 -07001044 // Reordered event
Jonathan Hartf1675202014-05-23 14:59:07 -07001045 log.debug("{} reordered because {} port is null", linkEvent,
1046 (srcPort == null) ? "src" : "dst");
Pavlin Radoslavovd7b792e2014-08-01 02:47:47 -07001047 return false;
Ray Milkey269ffb92014-04-03 14:43:30 -07001048 }
Pavlin Radoslavov3c9cc552014-02-20 09:58:38 -08001049
Pavlin Radoslavovd7b792e2014-08-01 02:47:47 -07001050 //
1051 // XXX domain knowledge: Sanity check: Port cannot have both Link and
1052 // Host.
1053 //
1054 // FIXME: Potentially local replica may not be up-to-date yet due to
1055 // Hazelcast delay.
1056 // FIXME: May need to manage local truth and use them instead.
1057 //
Yuta HIGUCHI8b389a72014-07-18 13:50:00 -07001058 if (topology.getLinkEvent(linkEvent.getLinkTuple()) == null) {
1059 // Only check for existing Host when adding new Link.
Yuta HIGUCHI8b389a72014-07-18 13:50:00 -07001060 // Remove all Hosts attached to the ports on both ends
1061
Pavlin Radoslavovd7b792e2014-08-01 02:47:47 -07001062 Set<HostEvent> hostsToUpdate =
1063 new TreeSet<>(new Comparator<HostEvent>() {
1064 // Comparison only using ID(=MAC)
Yuta HIGUCHI8b389a72014-07-18 13:50:00 -07001065 @Override
1066 public int compare(HostEvent o1, HostEvent o2) {
1067 return Long.compare(o1.getMac().toLong(), o2.getMac().toLong());
1068 }
1069 });
1070
1071 List<SwitchPort> portsToCheck = Arrays.asList(
1072 srcPort.getSwitchPort(),
1073 dstPort.getSwitchPort());
1074
1075 // Enumerate Host which needs to be updated by this Link add event
1076 for (SwitchPort port : portsToCheck) {
1077 for (Host host : topology.getHosts(port)) {
Yuta HIGUCHIbfc77f02014-07-14 22:50:25 -07001078 log.error("Host {} on Port {} should have been removed prior to adding Link {}",
1079 host, port, linkEvent);
Yuta HIGUCHI8b389a72014-07-18 13:50:00 -07001080
1081 HostEvent hostEvent = topology.getHostEvent(host.getMacAddress());
1082 hostsToUpdate.add(hostEvent);
Ray Milkey269ffb92014-04-03 14:43:30 -07001083 }
1084 }
Pavlin Radoslavovd7b792e2014-08-01 02:47:47 -07001085 // Remove attachment point from them
Yuta HIGUCHI8b389a72014-07-18 13:50:00 -07001086 for (HostEvent hostEvent : hostsToUpdate) {
Pavlin Radoslavovd7b792e2014-08-01 02:47:47 -07001087 // Remove port from attachment point and update
Yuta HIGUCHI8b389a72014-07-18 13:50:00 -07001088 HostEvent newHostEvent = new HostEvent(hostEvent);
1089 newHostEvent.removeAttachmentPoint(srcPort.getSwitchPort());
1090 newHostEvent.removeAttachmentPoint(dstPort.getSwitchPort());
1091 newHostEvent.freeze();
1092
1093 // TODO should this event be fired inside #addHost?
1094 if (newHostEvent.getAttachmentPoints().isEmpty()) {
1095 // No more attachment point left -> remove Host
1096 removeHost(hostEvent);
1097 } else {
1098 // Update Host
1099 addHost(newHostEvent);
1100 }
Ray Milkeyb29e6262014-04-09 16:02:14 -07001101 }
Ray Milkey269ffb92014-04-03 14:43:30 -07001102 }
Pavlin Radoslavov74986ce2014-02-20 13:17:20 -08001103
Yuta HIGUCHI8b389a72014-07-18 13:50:00 -07001104 if (log.isDebugEnabled()) {
1105 LinkEvent link = topology.getLinkEvent(linkEvent.getLinkTuple());
1106 if (link != null) {
1107 log.debug("Update {}", linkEvent);
1108 } else {
1109 log.debug("Added {}", linkEvent);
1110 }
1111 }
1112 topology.putLink(linkEvent.freeze());
Ray Milkey269ffb92014-04-03 14:43:30 -07001113 apiAddedLinkEvents.add(linkEvent);
Pavlin Radoslavovd7b792e2014-08-01 02:47:47 -07001114 return true;
Pavlin Radoslavov3c9cc552014-02-20 09:58:38 -08001115 }
1116
Pavlin Radoslavov734ff5a2014-02-26 10:20:43 -08001117 /**
Yuta HIGUCHI7926ba32014-07-09 11:39:32 -07001118 * Removes a link from the topology replica.
Pavlin Radoslavov734ff5a2014-02-26 10:20:43 -08001119 *
Yuta HIGUCHIbf0a8712014-06-30 18:59:46 -07001120 * @param linkEvent the LinkEvent with the link to remove.
Pavlin Radoslavov734ff5a2014-02-26 10:20:43 -08001121 */
Yuta HIGUCHIbc67a052014-06-30 10:37:09 -07001122 @GuardedBy("topology.writeLock")
Pavlin Radoslavov3c9cc552014-02-20 09:58:38 -08001123 private void removeLink(LinkEvent linkEvent) {
Yuta HIGUCHI8f3dfa32014-06-25 00:14:25 -07001124 Port srcPort = topology.getPort(linkEvent.getSrc().getDpid(),
Yuta HIGUCHIb1e2ab72014-06-30 11:01:31 -07001125 linkEvent.getSrc().getPortNumber());
Ray Milkey269ffb92014-04-03 14:43:30 -07001126 if (srcPort == null) {
1127 log.warn("Src Port for Link {} already removed, ignoring",
1128 linkEvent);
1129 return;
1130 }
Pavlin Radoslavov3c9cc552014-02-20 09:58:38 -08001131
Yuta HIGUCHI8f3dfa32014-06-25 00:14:25 -07001132 Port dstPort = topology.getPort(linkEvent.getDst().getDpid(),
Yuta HIGUCHIb1e2ab72014-06-30 11:01:31 -07001133 linkEvent.getDst().getPortNumber());
Ray Milkey269ffb92014-04-03 14:43:30 -07001134 if (dstPort == null) {
1135 log.warn("Dst Port for Link {} already removed, ignoring",
1136 linkEvent);
1137 return;
1138 }
Pavlin Radoslavov3c9cc552014-02-20 09:58:38 -08001139
Yuta HIGUCHI8b389a72014-07-18 13:50:00 -07001140 LinkEvent linkInTopo = topology.getLinkEvent(linkEvent.getLinkTuple(),
1141 linkEvent.getType());
1142 if (linkInTopo == null) {
1143 log.warn("Link {} already removed, ignoring", linkEvent);
1144 return;
Ray Milkey269ffb92014-04-03 14:43:30 -07001145 }
Jonathan Hart25bd53e2014-04-30 23:44:09 -07001146
Yuta HIGUCHI8b389a72014-07-18 13:50:00 -07001147 if (log.isDebugEnabled()) {
1148 // only do sanity check on debug level
1149
1150 Link linkIn = dstPort.getIncomingLink(linkEvent.getType());
1151 if (linkIn == null) {
1152 log.warn("Link {} already removed on destination Port", linkEvent);
1153 }
1154 Link linkOut = srcPort.getOutgoingLink(linkEvent.getType());
1155 if (linkOut == null) {
1156 log.warn("Link {} already removed on src Port", linkEvent);
1157 }
Jonathan Hart25bd53e2014-04-30 23:44:09 -07001158 }
Pavlin Radoslavov74986ce2014-02-20 13:17:20 -08001159
Yuta HIGUCHI8b389a72014-07-18 13:50:00 -07001160 log.debug("Removed {}", linkInTopo);
1161 topology.removeLink(linkEvent.getLinkTuple(), linkEvent.getType());
1162 apiRemovedLinkEvents.add(linkInTopo);
Pavlin Radoslavov3c9cc552014-02-20 09:58:38 -08001163 }
1164
Pavlin Radoslavov734ff5a2014-02-26 10:20:43 -08001165 /**
Yuta HIGUCHIbfc77f02014-07-14 22:50:25 -07001166 * Adds a host to the topology replica.
Ray Milkey269ffb92014-04-03 14:43:30 -07001167 * <p/>
Yuta HIGUCHIbfc77f02014-07-14 22:50:25 -07001168 * TODO: Host-related work is incomplete.
Pavlin Radoslavov734ff5a2014-02-26 10:20:43 -08001169 * TODO: Eventually, we might need to consider reordering
Pavlin Radoslavovd7b792e2014-08-01 02:47:47 -07001170 * or {@link #addLink(LinkEvent)} and {@link #addHost(HostEvent)} events
1171 * on the same port.
Pavlin Radoslavov734ff5a2014-02-26 10:20:43 -08001172 *
Yuta HIGUCHIbfc77f02014-07-14 22:50:25 -07001173 * @param hostEvent the HostEvent with the host to add.
Pavlin Radoslavovd7b792e2014-08-01 02:47:47 -07001174 * @return true if the item was successfully added, otherwise false.
Pavlin Radoslavov734ff5a2014-02-26 10:20:43 -08001175 */
Yuta HIGUCHIbc67a052014-06-30 10:37:09 -07001176 @GuardedBy("topology.writeLock")
Pavlin Radoslavovd7b792e2014-08-01 02:47:47 -07001177 private boolean addHost(HostEvent hostEvent) {
Pavlin Radoslavov3c9cc552014-02-20 09:58:38 -08001178
Yuta HIGUCHI8b389a72014-07-18 13:50:00 -07001179 // TODO Decide how to handle update scenario.
1180 // If the new HostEvent has less attachment point compared to
1181 // existing HostEvent, what should the event be?
1182 // - AddHostEvent with some attachment point removed? (current behavior)
Pavlin Radoslavov3c9cc552014-02-20 09:58:38 -08001183
Yuta HIGUCHI8b389a72014-07-18 13:50:00 -07001184 // create unfrozen copy
1185 // for removing attachment points which already has a link
1186 HostEvent modifiedHostEvent = new HostEvent(hostEvent);
Pavlin Radoslavov3c9cc552014-02-20 09:58:38 -08001187
Yuta HIGUCHI8b389a72014-07-18 13:50:00 -07001188 // Verify each attachment point
Ray Milkey269ffb92014-04-03 14:43:30 -07001189 boolean attachmentFound = false;
Yuta HIGUCHIbfc77f02014-07-14 22:50:25 -07001190 for (SwitchPort swp : hostEvent.getAttachmentPoints()) {
1191 // XXX domain knowledge: Port must exist before Host
Yuta HIGUCHIbf0a8712014-06-30 18:59:46 -07001192 // but this knowledge cannot be pushed down to driver.
1193
Ray Milkey269ffb92014-04-03 14:43:30 -07001194 // Attached Ports must exist
Yuta HIGUCHIb1e2ab72014-06-30 11:01:31 -07001195 Port port = topology.getPort(swp.getDpid(), swp.getPortNumber());
Ray Milkey269ffb92014-04-03 14:43:30 -07001196 if (port == null) {
Yuta HIGUCHI8b389a72014-07-18 13:50:00 -07001197 log.debug("{} reordered because port {} was not there", hostEvent, swp);
Pavlin Radoslavovd7b792e2014-08-01 02:47:47 -07001198 // Reordered event
1199 return false; // should not continue if re-applying later
Ray Milkey269ffb92014-04-03 14:43:30 -07001200 }
1201 // Attached Ports must not have Link
1202 if (port.getOutgoingLink() != null ||
1203 port.getIncomingLink() != null) {
Yuta HIGUCHI8b389a72014-07-18 13:50:00 -07001204 log.warn("Link (Out:{},In:{}) exist on the attachment point. "
1205 + "Ignoring this attachmentpoint ({}) from {}.",
1206 port.getOutgoingLink(), port.getIncomingLink(),
1207 swp, modifiedHostEvent);
1208 // FIXME Should either reject, reorder this HostEvent,
1209 // or remove attachment point from given HostEvent
1210 // Removing attachment point from given HostEvent for now.
1211 modifiedHostEvent.removeAttachmentPoint(swp);
Ray Milkey269ffb92014-04-03 14:43:30 -07001212 continue;
1213 }
1214
Ray Milkey269ffb92014-04-03 14:43:30 -07001215 attachmentFound = true;
1216 }
1217
Yuta HIGUCHIbfc77f02014-07-14 22:50:25 -07001218 // Update the host in the topology
Ray Milkey269ffb92014-04-03 14:43:30 -07001219 if (attachmentFound) {
Yuta HIGUCHI8b389a72014-07-18 13:50:00 -07001220 if (modifiedHostEvent.getAttachmentPoints().isEmpty()) {
1221 log.warn("No valid attachment point left. Ignoring."
1222 + "original: {}, modified: {}", hostEvent, modifiedHostEvent);
1223 // TODO Should we call #removeHost to trigger remove event?
1224 // only if this call is update.
Pavlin Radoslavovd7b792e2014-08-01 02:47:47 -07001225 return false;
Yuta HIGUCHI8b389a72014-07-18 13:50:00 -07001226 }
1227
1228 if (log.isDebugEnabled()) {
1229 HostEvent host = topology.getHostEvent(hostEvent.getMac());
1230 if (host != null) {
1231 log.debug("Update {}", modifiedHostEvent);
1232 } else {
1233 log.debug("Added {}", modifiedHostEvent);
1234 }
1235 }
1236 topology.putHost(modifiedHostEvent.freeze());
1237 apiAddedHostEvents.add(modifiedHostEvent);
Pavlin Radoslavovd7b792e2014-08-01 02:47:47 -07001238 return true;
Ray Milkey269ffb92014-04-03 14:43:30 -07001239 }
Pavlin Radoslavovd7b792e2014-08-01 02:47:47 -07001240 return false;
Pavlin Radoslavov3c9cc552014-02-20 09:58:38 -08001241 }
1242
Pavlin Radoslavov734ff5a2014-02-26 10:20:43 -08001243 /**
Yuta HIGUCHIbfc77f02014-07-14 22:50:25 -07001244 * Removes a host from the topology replica.
Ray Milkey269ffb92014-04-03 14:43:30 -07001245 * <p/>
Yuta HIGUCHIbfc77f02014-07-14 22:50:25 -07001246 * TODO: Host-related work is incomplete.
Pavlin Radoslavov734ff5a2014-02-26 10:20:43 -08001247 *
Yuta HIGUCHIbfc77f02014-07-14 22:50:25 -07001248 * @param hostEvent the Host Event with the host to remove.
Pavlin Radoslavov734ff5a2014-02-26 10:20:43 -08001249 */
Yuta HIGUCHIbc67a052014-06-30 10:37:09 -07001250 @GuardedBy("topology.writeLock")
Yuta HIGUCHIbfc77f02014-07-14 22:50:25 -07001251 private void removeHost(HostEvent hostEvent) {
Yuta HIGUCHI8b389a72014-07-18 13:50:00 -07001252
1253 final MACAddress mac = hostEvent.getMac();
1254 HostEvent hostInTopo = topology.getHostEvent(mac);
1255 if (hostInTopo == null) {
Yuta HIGUCHIbfc77f02014-07-14 22:50:25 -07001256 log.warn("Host {} already removed, ignoring", hostEvent);
Ray Milkey269ffb92014-04-03 14:43:30 -07001257 return;
1258 }
Pavlin Radoslavov3c9cc552014-02-20 09:58:38 -08001259
Yuta HIGUCHI8b389a72014-07-18 13:50:00 -07001260 log.debug("Removed {}", hostInTopo);
1261 topology.removeHost(mac);
1262 apiRemovedHostEvents.add(hostInTopo);
Pavlin Radoslavov3c9cc552014-02-20 09:58:38 -08001263 }
Jonathan Hart22eb9882014-02-11 15:52:59 -08001264
Pavlin Radoslavovc1cfde52014-02-19 11:35:29 -08001265 /**
Pavlin Radoslavov734ff5a2014-02-26 10:20:43 -08001266 * Read the whole topology from the database.
1267 *
Pavlin Radoslavovd7b792e2014-08-01 02:47:47 -07001268 * @return a list of EventEntry-encapsulated Topology Events for
Pavlin Radoslavov734ff5a2014-02-26 10:20:43 -08001269 * the whole topology.
1270 */
Pavlin Radoslavovd7b792e2014-08-01 02:47:47 -07001271 private List<EventEntry<TopologyEvent>> readWholeTopologyFromDB() {
1272 List<EventEntry<TopologyEvent>> events =
Ray Milkey269ffb92014-04-03 14:43:30 -07001273 new LinkedList<EventEntry<TopologyEvent>>();
Pavlin Radoslavov018d5332014-02-19 23:08:35 -08001274
Ray Milkey269ffb92014-04-03 14:43:30 -07001275 // XXX May need to clear whole topology first, depending on
1276 // how we initially subscribe to replication events
Pavlin Radoslavovc1cfde52014-02-19 11:35:29 -08001277
Ray Milkey269ffb92014-04-03 14:43:30 -07001278 // Add all active switches
1279 for (KVSwitch sw : KVSwitch.getAllSwitches()) {
1280 if (sw.getStatus() != KVSwitch.STATUS.ACTIVE) {
1281 continue;
1282 }
Pavlin Radoslavov018d5332014-02-19 23:08:35 -08001283
Pavlin Radoslavova5637c02014-07-30 15:55:11 -07001284 //
1285 // TODO: Using the local ONOS Instance ID below is incorrect.
1286 // Currently, this code is not used, and it might go away in the
1287 // future.
1288 //
Yuta HIGUCHIe2a4e172014-07-03 10:50:39 -07001289 SwitchEvent switchEvent = new SwitchEvent(new Dpid(sw.getDpid()));
Pavlin Radoslavova5637c02014-07-30 15:55:11 -07001290 TopologyEvent topologyEvent =
1291 new TopologyEvent(switchEvent,
1292 registryService.getOnosInstanceId());
Ray Milkey269ffb92014-04-03 14:43:30 -07001293 EventEntry<TopologyEvent> eventEntry =
1294 new EventEntry<TopologyEvent>(EventEntry.Type.ENTRY_ADD,
1295 topologyEvent);
Pavlin Radoslavovd7b792e2014-08-01 02:47:47 -07001296 events.add(eventEntry);
Ray Milkey269ffb92014-04-03 14:43:30 -07001297 }
Yuta HIGUCHIa536e762014-02-17 21:47:28 -08001298
Ray Milkey269ffb92014-04-03 14:43:30 -07001299 // Add all active ports
1300 for (KVPort p : KVPort.getAllPorts()) {
1301 if (p.getStatus() != KVPort.STATUS.ACTIVE) {
1302 continue;
1303 }
Pavlin Radoslavov018d5332014-02-19 23:08:35 -08001304
Pavlin Radoslavova5637c02014-07-30 15:55:11 -07001305 //
1306 // TODO: Using the local ONOS Instance ID below is incorrect.
1307 // Currently, this code is not used, and it might go away in the
1308 // future.
1309 //
1310 PortEvent portEvent =
1311 new PortEvent(new Dpid(p.getDpid()),
1312 new PortNumber(p.getNumber().shortValue()));
1313 TopologyEvent topologyEvent =
1314 new TopologyEvent(portEvent,
1315 registryService.getOnosInstanceId());
Ray Milkey269ffb92014-04-03 14:43:30 -07001316 EventEntry<TopologyEvent> eventEntry =
1317 new EventEntry<TopologyEvent>(EventEntry.Type.ENTRY_ADD,
1318 topologyEvent);
Pavlin Radoslavovd7b792e2014-08-01 02:47:47 -07001319 events.add(eventEntry);
Ray Milkey269ffb92014-04-03 14:43:30 -07001320 }
Yuta HIGUCHIa536e762014-02-17 21:47:28 -08001321
Pavlin Radoslavova5637c02014-07-30 15:55:11 -07001322 for (KVDevice d : KVDevice.getAllDevices()) {
1323 //
1324 // TODO: Using the local ONOS Instance ID below is incorrect.
1325 // Currently, this code is not used, and it might go away in the
1326 // future.
1327 //
1328 HostEvent devEvent = new HostEvent(MACAddress.valueOf(d.getMac()));
1329 for (byte[] portId : d.getAllPortIds()) {
1330 devEvent.addAttachmentPoint(
1331 new SwitchPort(KVPort.getDpidFromKey(portId),
1332 KVPort.getNumberFromKey(portId)));
1333 }
1334 }
Pavlin Radoslavovc1cfde52014-02-19 11:35:29 -08001335
Ray Milkey269ffb92014-04-03 14:43:30 -07001336 for (KVLink l : KVLink.getAllLinks()) {
Pavlin Radoslavova5637c02014-07-30 15:55:11 -07001337 //
1338 // TODO: Using the local ONOS Instance ID below is incorrect.
1339 // Currently, this code is not used, and it might go away in the
1340 // future.
1341 //
Yuta HIGUCHIe2a4e172014-07-03 10:50:39 -07001342 LinkEvent linkEvent = new LinkEvent(
Pavlin Radoslavova5637c02014-07-30 15:55:11 -07001343 new SwitchPort(l.getSrc().dpid, l.getSrc().number),
1344 new SwitchPort(l.getDst().dpid, l.getDst().number));
1345 TopologyEvent topologyEvent =
1346 new TopologyEvent(linkEvent,
1347 registryService.getOnosInstanceId());
Ray Milkey269ffb92014-04-03 14:43:30 -07001348 EventEntry<TopologyEvent> eventEntry =
1349 new EventEntry<TopologyEvent>(EventEntry.Type.ENTRY_ADD,
1350 topologyEvent);
Pavlin Radoslavovd7b792e2014-08-01 02:47:47 -07001351 events.add(eventEntry);
Ray Milkey269ffb92014-04-03 14:43:30 -07001352 }
Pavlin Radoslavov018d5332014-02-19 23:08:35 -08001353
Pavlin Radoslavovd7b792e2014-08-01 02:47:47 -07001354 return events;
Pavlin Radoslavovc1cfde52014-02-19 11:35:29 -08001355 }
Jonathan Hart062a2e82014-02-03 09:41:57 -08001356}