blob: 28c23dac6295ac8a1fef539a76410c5ef02d7566 [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
516 eventChannel.removeEntry(mastershipEvent.getID());
517 }
518
519 /**
Pavlin Radoslavov734ff5a2014-02-26 10:20:43 -0800520 * Switch discovered event.
521 *
522 * @param switchEvent the switch event.
Ray Milkey269ffb92014-04-03 14:43:30 -0700523 * @param portEvents the corresponding port events for the switch.
Pavlin Radoslavov734ff5a2014-02-26 10:20:43 -0800524 */
Pavlin Radoslavovc1cfde52014-02-19 11:35:29 -0800525 @Override
Pavlin Radoslavov018d5332014-02-19 23:08:35 -0800526 public void putSwitchDiscoveryEvent(SwitchEvent switchEvent,
Ray Milkey269ffb92014-04-03 14:43:30 -0700527 Collection<PortEvent> portEvents) {
528 if (datastore.addSwitch(switchEvent, portEvents)) {
Jonathan Hart92c819f2014-05-30 10:53:30 -0700529 log.debug("Sending add switch: {}", switchEvent);
Ray Milkey269ffb92014-04-03 14:43:30 -0700530 // Send out notification
Pavlin Radoslavova5637c02014-07-30 15:55:11 -0700531 TopologyEvent topologyEvent =
532 new TopologyEvent(switchEvent,
533 registryService.getOnosInstanceId());
Ray Milkey269ffb92014-04-03 14:43:30 -0700534 eventChannel.addEntry(topologyEvent.getID(), topologyEvent);
Pavlin Radoslavov26d83402014-02-20 15:24:30 -0800535
Ray Milkey269ffb92014-04-03 14:43:30 -0700536 // Send out notification for each port
537 for (PortEvent portEvent : portEvents) {
Jonathan Hart92c819f2014-05-30 10:53:30 -0700538 log.debug("Sending add port: {}", portEvent);
Pavlin Radoslavova5637c02014-07-30 15:55:11 -0700539 topologyEvent =
540 new TopologyEvent(portEvent,
541 registryService.getOnosInstanceId());
Ray Milkey269ffb92014-04-03 14:43:30 -0700542 eventChannel.addEntry(topologyEvent.getID(), topologyEvent);
543 }
Pavlin Radoslavov26d83402014-02-20 15:24:30 -0800544
Ray Milkey269ffb92014-04-03 14:43:30 -0700545 //
546 // Keep track of the added ports
547 //
548 // Get the old Port Events
549 Map<ByteBuffer, PortEvent> oldPortEvents =
550 discoveredAddedPortEvents.get(switchEvent.getDpid());
Ray Milkeyb29e6262014-04-09 16:02:14 -0700551 if (oldPortEvents == null) {
Ray Milkey269ffb92014-04-03 14:43:30 -0700552 oldPortEvents = new HashMap<>();
Ray Milkeyb29e6262014-04-09 16:02:14 -0700553 }
Pavlin Radoslavov26d83402014-02-20 15:24:30 -0800554
Ray Milkey269ffb92014-04-03 14:43:30 -0700555 // Store the new Port Events in the local cache
556 Map<ByteBuffer, PortEvent> newPortEvents = new HashMap<>();
557 for (PortEvent portEvent : portEvents) {
558 ByteBuffer id = portEvent.getIDasByteBuffer();
559 newPortEvents.put(id, portEvent);
560 }
561 discoveredAddedPortEvents.put(switchEvent.getDpid(),
562 newPortEvents);
Pavlin Radoslavov26d83402014-02-20 15:24:30 -0800563
Ray Milkey269ffb92014-04-03 14:43:30 -0700564 //
565 // Extract the removed ports
566 //
567 List<PortEvent> removedPortEvents = new LinkedList<>();
568 for (Map.Entry<ByteBuffer, PortEvent> entry : oldPortEvents.entrySet()) {
569 ByteBuffer key = entry.getKey();
570 PortEvent portEvent = entry.getValue();
Ray Milkeyb29e6262014-04-09 16:02:14 -0700571 if (!newPortEvents.containsKey(key)) {
Ray Milkey269ffb92014-04-03 14:43:30 -0700572 removedPortEvents.add(portEvent);
Ray Milkeyb29e6262014-04-09 16:02:14 -0700573 }
Ray Milkey269ffb92014-04-03 14:43:30 -0700574 }
575
576 // Cleanup old removed ports
Ray Milkeyb29e6262014-04-09 16:02:14 -0700577 for (PortEvent portEvent : removedPortEvents) {
Ray Milkey269ffb92014-04-03 14:43:30 -0700578 removePortDiscoveryEvent(portEvent);
Ray Milkeyb29e6262014-04-09 16:02:14 -0700579 }
Ray Milkey269ffb92014-04-03 14:43:30 -0700580 }
Pavlin Radoslavovc1cfde52014-02-19 11:35:29 -0800581 }
582
Pavlin Radoslavov734ff5a2014-02-26 10:20:43 -0800583 /**
Yuta HIGUCHIbc67a052014-06-30 10:37:09 -0700584 * {@inheritDoc}
585 * <p/>
586 * Called by {@link TopologyPublisher.SwitchCleanup} thread.
Pavlin Radoslavov734ff5a2014-02-26 10:20:43 -0800587 */
Pavlin Radoslavovc1cfde52014-02-19 11:35:29 -0800588 @Override
Pavlin Radoslavov6ea84a42014-02-19 15:50:01 -0800589 public void removeSwitchDiscoveryEvent(SwitchEvent switchEvent) {
Ray Milkey269ffb92014-04-03 14:43:30 -0700590 // Get the old Port Events
591 Map<ByteBuffer, PortEvent> oldPortEvents =
592 discoveredAddedPortEvents.get(switchEvent.getDpid());
Ray Milkeyb29e6262014-04-09 16:02:14 -0700593 if (oldPortEvents == null) {
Ray Milkey269ffb92014-04-03 14:43:30 -0700594 oldPortEvents = new HashMap<>();
Ray Milkeyb29e6262014-04-09 16:02:14 -0700595 }
Pavlin Radoslavov018d5332014-02-19 23:08:35 -0800596
Ray Milkey269ffb92014-04-03 14:43:30 -0700597 if (datastore.deactivateSwitch(switchEvent, oldPortEvents.values())) {
Jonathan Hart92c819f2014-05-30 10:53:30 -0700598 log.debug("Sending remove switch: {}", switchEvent);
Ray Milkey269ffb92014-04-03 14:43:30 -0700599 // Send out notification
600 eventChannel.removeEntry(switchEvent.getID());
Pavlin Radoslavov018d5332014-02-19 23:08:35 -0800601
Ray Milkey269ffb92014-04-03 14:43:30 -0700602 //
603 // Send out notification for each port.
604 //
605 // NOTE: We don't use removePortDiscoveryEvent() for the cleanup,
606 // because it will attempt to remove the port from the database,
607 // and the deactiveSwitch() call above already removed all ports.
608 //
Ray Milkeyb29e6262014-04-09 16:02:14 -0700609 for (PortEvent portEvent : oldPortEvents.values()) {
Jonathan Hart92c819f2014-05-30 10:53:30 -0700610 log.debug("Sending remove port:", portEvent);
Ray Milkey269ffb92014-04-03 14:43:30 -0700611 eventChannel.removeEntry(portEvent.getID());
Ray Milkeyb29e6262014-04-09 16:02:14 -0700612 }
Ray Milkey269ffb92014-04-03 14:43:30 -0700613 discoveredAddedPortEvents.remove(switchEvent.getDpid());
Pavlin Radoslavov26d83402014-02-20 15:24:30 -0800614
Ray Milkey269ffb92014-04-03 14:43:30 -0700615 // Cleanup for each link
616 Map<ByteBuffer, LinkEvent> oldLinkEvents =
617 discoveredAddedLinkEvents.get(switchEvent.getDpid());
618 if (oldLinkEvents != null) {
619 for (LinkEvent linkEvent : new ArrayList<>(oldLinkEvents.values())) {
620 removeLinkDiscoveryEvent(linkEvent);
621 }
622 discoveredAddedLinkEvents.remove(switchEvent.getDpid());
623 }
Pavlin Radoslavov26d83402014-02-20 15:24:30 -0800624
Yuta HIGUCHIbfc77f02014-07-14 22:50:25 -0700625 // Cleanup for each host
626 Map<ByteBuffer, HostEvent> oldHostEvents =
627 discoveredAddedHostEvents.get(switchEvent.getDpid());
628 if (oldHostEvents != null) {
629 for (HostEvent hostEvent : new ArrayList<>(oldHostEvents.values())) {
630 removeHostDiscoveryEvent(hostEvent);
Ray Milkey269ffb92014-04-03 14:43:30 -0700631 }
Yuta HIGUCHIbfc77f02014-07-14 22:50:25 -0700632 discoveredAddedHostEvents.remove(switchEvent.getDpid());
Ray Milkey269ffb92014-04-03 14:43:30 -0700633 }
634 }
Pavlin Radoslavovc1cfde52014-02-19 11:35:29 -0800635 }
636
Pavlin Radoslavov734ff5a2014-02-26 10:20:43 -0800637 /**
638 * Port discovered event.
639 *
640 * @param portEvent the port event.
641 */
Pavlin Radoslavovc1cfde52014-02-19 11:35:29 -0800642 @Override
Pavlin Radoslavov6ea84a42014-02-19 15:50:01 -0800643 public void putPortDiscoveryEvent(PortEvent portEvent) {
Ray Milkey269ffb92014-04-03 14:43:30 -0700644 if (datastore.addPort(portEvent)) {
Jonathan Hart92c819f2014-05-30 10:53:30 -0700645 log.debug("Sending add port: {}", portEvent);
Ray Milkey269ffb92014-04-03 14:43:30 -0700646 // Send out notification
Pavlin Radoslavova5637c02014-07-30 15:55:11 -0700647 TopologyEvent topologyEvent =
648 new TopologyEvent(portEvent,
649 registryService.getOnosInstanceId());
Ray Milkey269ffb92014-04-03 14:43:30 -0700650 eventChannel.addEntry(topologyEvent.getID(), topologyEvent);
Pavlin Radoslavov26d83402014-02-20 15:24:30 -0800651
Ray Milkey269ffb92014-04-03 14:43:30 -0700652 // Store the new Port Event in the local cache
653 Map<ByteBuffer, PortEvent> oldPortEvents =
654 discoveredAddedPortEvents.get(portEvent.getDpid());
655 if (oldPortEvents == null) {
656 oldPortEvents = new HashMap<>();
657 discoveredAddedPortEvents.put(portEvent.getDpid(),
658 oldPortEvents);
659 }
660 ByteBuffer id = portEvent.getIDasByteBuffer();
661 oldPortEvents.put(id, portEvent);
662 }
Pavlin Radoslavovc1cfde52014-02-19 11:35:29 -0800663 }
664
Pavlin Radoslavov734ff5a2014-02-26 10:20:43 -0800665 /**
666 * Port removed event.
667 *
668 * @param portEvent the port event.
669 */
Pavlin Radoslavovc1cfde52014-02-19 11:35:29 -0800670 @Override
Pavlin Radoslavov6ea84a42014-02-19 15:50:01 -0800671 public void removePortDiscoveryEvent(PortEvent portEvent) {
Ray Milkey269ffb92014-04-03 14:43:30 -0700672 if (datastore.deactivatePort(portEvent)) {
Jonathan Hart92c819f2014-05-30 10:53:30 -0700673 log.debug("Sending remove port: {}", portEvent);
Ray Milkey269ffb92014-04-03 14:43:30 -0700674 // Send out notification
675 eventChannel.removeEntry(portEvent.getID());
Pavlin Radoslavov26d83402014-02-20 15:24:30 -0800676
Ray Milkey269ffb92014-04-03 14:43:30 -0700677 // Cleanup the Port Event from the local cache
678 Map<ByteBuffer, PortEvent> oldPortEvents =
679 discoveredAddedPortEvents.get(portEvent.getDpid());
680 if (oldPortEvents != null) {
681 ByteBuffer id = portEvent.getIDasByteBuffer();
682 oldPortEvents.remove(id);
683 }
Pavlin Radoslavov26d83402014-02-20 15:24:30 -0800684
Ray Milkey269ffb92014-04-03 14:43:30 -0700685 // Cleanup for the incoming link
686 Map<ByteBuffer, LinkEvent> oldLinkEvents =
687 discoveredAddedLinkEvents.get(portEvent.getDpid());
688 if (oldLinkEvents != null) {
689 for (LinkEvent linkEvent : new ArrayList<>(oldLinkEvents.values())) {
Yuta HIGUCHIbf0a8712014-06-30 18:59:46 -0700690 if (linkEvent.getDst().equals(portEvent.getSwitchPort())) {
Ray Milkey269ffb92014-04-03 14:43:30 -0700691 removeLinkDiscoveryEvent(linkEvent);
692 // XXX If we change our model to allow multiple Link on
693 // a Port, this loop must be fixed to allow continuing.
694 break;
695 }
696 }
697 }
Pavlin Radoslavov26d83402014-02-20 15:24:30 -0800698
Yuta HIGUCHIbfc77f02014-07-14 22:50:25 -0700699 // Cleanup for the connected hosts
Ray Milkey269ffb92014-04-03 14:43:30 -0700700 // TODO: The implementation below is probably wrong
Yuta HIGUCHIbfc77f02014-07-14 22:50:25 -0700701 List<HostEvent> removedHostEvents = new LinkedList<>();
702 Map<ByteBuffer, HostEvent> oldHostEvents =
703 discoveredAddedHostEvents.get(portEvent.getDpid());
704 if (oldHostEvents != null) {
705 for (HostEvent hostEvent : new ArrayList<>(oldHostEvents.values())) {
706 for (SwitchPort swp : hostEvent.getAttachmentPoints()) {
Yuta HIGUCHIbf0a8712014-06-30 18:59:46 -0700707 if (swp.equals(portEvent.getSwitchPort())) {
Yuta HIGUCHIbfc77f02014-07-14 22:50:25 -0700708 removedHostEvents.add(hostEvent);
Ray Milkey269ffb92014-04-03 14:43:30 -0700709 }
710 }
711 }
Yuta HIGUCHIbfc77f02014-07-14 22:50:25 -0700712 for (HostEvent hostEvent : removedHostEvents) {
713 removeHostDiscoveryEvent(hostEvent);
Ray Milkeyb29e6262014-04-09 16:02:14 -0700714 }
Ray Milkey269ffb92014-04-03 14:43:30 -0700715 }
716 }
Pavlin Radoslavovc1cfde52014-02-19 11:35:29 -0800717 }
718
Pavlin Radoslavov734ff5a2014-02-26 10:20:43 -0800719 /**
720 * Link discovered event.
721 *
722 * @param linkEvent the link event.
723 */
Pavlin Radoslavovc1cfde52014-02-19 11:35:29 -0800724 @Override
Pavlin Radoslavov6ea84a42014-02-19 15:50:01 -0800725 public void putLinkDiscoveryEvent(LinkEvent linkEvent) {
Ray Milkey269ffb92014-04-03 14:43:30 -0700726 if (datastore.addLink(linkEvent)) {
Jonathan Hart92c819f2014-05-30 10:53:30 -0700727 log.debug("Sending add link: {}", linkEvent);
Ray Milkey269ffb92014-04-03 14:43:30 -0700728 // Send out notification
Pavlin Radoslavova5637c02014-07-30 15:55:11 -0700729 TopologyEvent topologyEvent =
730 new TopologyEvent(linkEvent,
731 registryService.getOnosInstanceId());
Ray Milkey269ffb92014-04-03 14:43:30 -0700732 eventChannel.addEntry(topologyEvent.getID(), topologyEvent);
Pavlin Radoslavov26d83402014-02-20 15:24:30 -0800733
Ray Milkey269ffb92014-04-03 14:43:30 -0700734 // Store the new Link Event in the local cache
735 Map<ByteBuffer, LinkEvent> oldLinkEvents =
736 discoveredAddedLinkEvents.get(linkEvent.getDst().getDpid());
737 if (oldLinkEvents == null) {
738 oldLinkEvents = new HashMap<>();
739 discoveredAddedLinkEvents.put(linkEvent.getDst().getDpid(),
740 oldLinkEvents);
741 }
742 ByteBuffer id = linkEvent.getIDasByteBuffer();
743 oldLinkEvents.put(id, linkEvent);
744 }
Pavlin Radoslavovc1cfde52014-02-19 11:35:29 -0800745 }
746
Pavlin Radoslavov734ff5a2014-02-26 10:20:43 -0800747 /**
748 * Link removed event.
749 *
750 * @param linkEvent the link event.
751 */
Pavlin Radoslavovc1cfde52014-02-19 11:35:29 -0800752 @Override
Pavlin Radoslavov6ea84a42014-02-19 15:50:01 -0800753 public void removeLinkDiscoveryEvent(LinkEvent linkEvent) {
Ray Milkey269ffb92014-04-03 14:43:30 -0700754 if (datastore.removeLink(linkEvent)) {
Jonathan Hart92c819f2014-05-30 10:53:30 -0700755 log.debug("Sending remove link: {}", linkEvent);
Ray Milkey269ffb92014-04-03 14:43:30 -0700756 // Send out notification
757 eventChannel.removeEntry(linkEvent.getID());
Pavlin Radoslavov26d83402014-02-20 15:24:30 -0800758
Ray Milkey269ffb92014-04-03 14:43:30 -0700759 // Cleanup the Link Event from the local cache
760 Map<ByteBuffer, LinkEvent> oldLinkEvents =
761 discoveredAddedLinkEvents.get(linkEvent.getDst().getDpid());
762 if (oldLinkEvents != null) {
763 ByteBuffer id = linkEvent.getIDasByteBuffer();
764 oldLinkEvents.remove(id);
765 }
766 }
Pavlin Radoslavovc1cfde52014-02-19 11:35:29 -0800767 }
Jonathan Hart22eb9882014-02-11 15:52:59 -0800768
Pavlin Radoslavov734ff5a2014-02-26 10:20:43 -0800769 /**
Yuta HIGUCHIbfc77f02014-07-14 22:50:25 -0700770 * Host discovered event.
Pavlin Radoslavov734ff5a2014-02-26 10:20:43 -0800771 *
Yuta HIGUCHIbfc77f02014-07-14 22:50:25 -0700772 * @param hostEvent the host event.
Pavlin Radoslavov734ff5a2014-02-26 10:20:43 -0800773 */
Pavlin Radoslavovc1cfde52014-02-19 11:35:29 -0800774 @Override
Yuta HIGUCHIbfc77f02014-07-14 22:50:25 -0700775 public void putHostDiscoveryEvent(HostEvent hostEvent) {
776 if (datastore.addHost(hostEvent)) {
Ray Milkey269ffb92014-04-03 14:43:30 -0700777 // Send out notification
Pavlin Radoslavova5637c02014-07-30 15:55:11 -0700778 TopologyEvent topologyEvent =
779 new TopologyEvent(hostEvent,
780 registryService.getOnosInstanceId());
Ray Milkey269ffb92014-04-03 14:43:30 -0700781 eventChannel.addEntry(topologyEvent.getID(), topologyEvent);
Yuta HIGUCHIbfc77f02014-07-14 22:50:25 -0700782 log.debug("Put the host info into the cache of the topology. mac {}", hostEvent.getMac());
Ray Milkey269ffb92014-04-03 14:43:30 -0700783
Yuta HIGUCHIbfc77f02014-07-14 22:50:25 -0700784 // Store the new Host Event in the local cache
Ray Milkey269ffb92014-04-03 14:43:30 -0700785 // TODO: The implementation below is probably wrong
Yuta HIGUCHIbfc77f02014-07-14 22:50:25 -0700786 for (SwitchPort swp : hostEvent.getAttachmentPoints()) {
787 Map<ByteBuffer, HostEvent> oldHostEvents =
788 discoveredAddedHostEvents.get(swp.getDpid());
789 if (oldHostEvents == null) {
790 oldHostEvents = new HashMap<>();
791 discoveredAddedHostEvents.put(swp.getDpid(),
792 oldHostEvents);
Ray Milkey269ffb92014-04-03 14:43:30 -0700793 }
Yuta HIGUCHIbfc77f02014-07-14 22:50:25 -0700794 ByteBuffer id = hostEvent.getIDasByteBuffer();
795 oldHostEvents.put(id, hostEvent);
Ray Milkey269ffb92014-04-03 14:43:30 -0700796 }
797 }
Pavlin Radoslavovc1cfde52014-02-19 11:35:29 -0800798 }
Jonathan Hart22eb9882014-02-11 15:52:59 -0800799
Pavlin Radoslavov734ff5a2014-02-26 10:20:43 -0800800 /**
Yuta HIGUCHIbfc77f02014-07-14 22:50:25 -0700801 * Host removed event.
Pavlin Radoslavov734ff5a2014-02-26 10:20:43 -0800802 *
Yuta HIGUCHIbfc77f02014-07-14 22:50:25 -0700803 * @param hostEvent the host event.
Pavlin Radoslavov734ff5a2014-02-26 10:20:43 -0800804 */
Pavlin Radoslavovc1cfde52014-02-19 11:35:29 -0800805 @Override
Yuta HIGUCHIbfc77f02014-07-14 22:50:25 -0700806 public void removeHostDiscoveryEvent(HostEvent hostEvent) {
807 if (datastore.removeHost(hostEvent)) {
Ray Milkey269ffb92014-04-03 14:43:30 -0700808 // Send out notification
Yuta HIGUCHIbfc77f02014-07-14 22:50:25 -0700809 eventChannel.removeEntry(hostEvent.getID());
810 log.debug("Remove the host info into the cache of the topology. mac {}", hostEvent.getMac());
Pavlin Radoslavov26d83402014-02-20 15:24:30 -0800811
Yuta HIGUCHIbfc77f02014-07-14 22:50:25 -0700812 // Cleanup the Host Event from the local cache
Ray Milkey269ffb92014-04-03 14:43:30 -0700813 // TODO: The implementation below is probably wrong
Yuta HIGUCHIbfc77f02014-07-14 22:50:25 -0700814 ByteBuffer id = ByteBuffer.wrap(hostEvent.getID());
815 for (SwitchPort swp : hostEvent.getAttachmentPoints()) {
816 Map<ByteBuffer, HostEvent> oldHostEvents =
817 discoveredAddedHostEvents.get(swp.getDpid());
818 if (oldHostEvents != null) {
819 oldHostEvents.remove(id);
Ray Milkey269ffb92014-04-03 14:43:30 -0700820 }
821 }
822 }
Pavlin Radoslavovc1cfde52014-02-19 11:35:29 -0800823 }
Jonathan Hart22eb9882014-02-11 15:52:59 -0800824
Yuta HIGUCHI8b389a72014-07-18 13:50:00 -0700825 //
826 // Methods to update topology replica
827 //
828
Pavlin Radoslavov734ff5a2014-02-26 10:20:43 -0800829 /**
Pavlin Radoslavovd7b792e2014-08-01 02:47:47 -0700830 * Adds Switch Mastership event.
Pavlin Radoslavov695f8952014-07-23 16:57:01 -0700831 *
Pavlin Radoslavovcac157d2014-07-31 13:54:08 -0700832 * @param mastershipEvent the MastershipEvent to process.
Pavlin Radoslavovd7b792e2014-08-01 02:47:47 -0700833 * @return true if the item was successfully added, otherwise false.
Pavlin Radoslavov695f8952014-07-23 16:57:01 -0700834 */
Pavlin Radoslavovcac157d2014-07-31 13:54:08 -0700835 @GuardedBy("topology.writeLock")
Pavlin Radoslavovd7b792e2014-08-01 02:47:47 -0700836 private boolean addMastershipEvent(MastershipEvent mastershipEvent) {
837 log.debug("Added Mastership event {}", mastershipEvent);
Pavlin Radoslavovcac157d2014-07-31 13:54:08 -0700838 apiAddedMastershipEvents.add(mastershipEvent);
Pavlin Radoslavovd7b792e2014-08-01 02:47:47 -0700839 return true;
Pavlin Radoslavov695f8952014-07-23 16:57:01 -0700840 }
841
842 /**
Pavlin Radoslavovd7b792e2014-08-01 02:47:47 -0700843 * Removes Switch Mastership event.
Pavlin Radoslavov695f8952014-07-23 16:57:01 -0700844 *
Pavlin Radoslavovcac157d2014-07-31 13:54:08 -0700845 * @param mastershipEvent the MastershipEvent to process.
Pavlin Radoslavov695f8952014-07-23 16:57:01 -0700846 */
Pavlin Radoslavovcac157d2014-07-31 13:54:08 -0700847 @GuardedBy("topology.writeLock")
Pavlin Radoslavovd7b792e2014-08-01 02:47:47 -0700848 private void removeMastershipEvent(MastershipEvent mastershipEvent) {
849 log.debug("Removed Mastership event {}", mastershipEvent);
Pavlin Radoslavovcac157d2014-07-31 13:54:08 -0700850 apiRemovedMastershipEvents.add(mastershipEvent);
Pavlin Radoslavov695f8952014-07-23 16:57:01 -0700851 }
852
853 /**
Yuta HIGUCHI7926ba32014-07-09 11:39:32 -0700854 * Adds a switch to the topology replica.
Pavlin Radoslavov734ff5a2014-02-26 10:20:43 -0800855 *
Yuta HIGUCHIbf0a8712014-06-30 18:59:46 -0700856 * @param switchEvent the SwitchEvent with the switch to add.
Pavlin Radoslavovd7b792e2014-08-01 02:47:47 -0700857 * @return true if the item was successfully added, otherwise false.
Pavlin Radoslavov734ff5a2014-02-26 10:20:43 -0800858 */
Yuta HIGUCHIbc67a052014-06-30 10:37:09 -0700859 @GuardedBy("topology.writeLock")
Pavlin Radoslavovd7b792e2014-08-01 02:47:47 -0700860 private boolean addSwitch(SwitchEvent switchEvent) {
Yuta HIGUCHI8b389a72014-07-18 13:50:00 -0700861 if (log.isDebugEnabled()) {
862 SwitchEvent sw = topology.getSwitchEvent(switchEvent.getDpid());
863 if (sw != null) {
864 log.debug("Update {}", switchEvent);
865 } else {
866 log.debug("Added {}", switchEvent);
867 }
Ray Milkey269ffb92014-04-03 14:43:30 -0700868 }
Yuta HIGUCHI8b389a72014-07-18 13:50:00 -0700869 topology.putSwitch(switchEvent.freeze());
Ray Milkey269ffb92014-04-03 14:43:30 -0700870 apiAddedSwitchEvents.add(switchEvent);
Pavlin Radoslavovd7b792e2014-08-01 02:47:47 -0700871 return true;
Pavlin Radoslavov3c9cc552014-02-20 09:58:38 -0800872 }
873
Pavlin Radoslavov734ff5a2014-02-26 10:20:43 -0800874 /**
Yuta HIGUCHI7926ba32014-07-09 11:39:32 -0700875 * Removes a switch from the topology replica.
Yuta HIGUCHIbf0a8712014-06-30 18:59:46 -0700876 * <p/>
Pavlin Radoslavovd7b792e2014-08-01 02:47:47 -0700877 * It will call {@link #removePort(PortEvent)} for each ports on this
878 * switch.
Pavlin Radoslavov734ff5a2014-02-26 10:20:43 -0800879 *
Yuta HIGUCHIbf0a8712014-06-30 18:59:46 -0700880 * @param switchEvent the SwitchEvent with the switch to remove.
Pavlin Radoslavov734ff5a2014-02-26 10:20:43 -0800881 */
Yuta HIGUCHIbc67a052014-06-30 10:37:09 -0700882 @GuardedBy("topology.writeLock")
Pavlin Radoslavov74986ce2014-02-20 13:17:20 -0800883 private void removeSwitch(SwitchEvent switchEvent) {
Yuta HIGUCHI8b389a72014-07-18 13:50:00 -0700884 final Dpid dpid = switchEvent.getDpid();
885
886 SwitchEvent swInTopo = topology.getSwitchEvent(dpid);
887 if (swInTopo == null) {
Ray Milkey269ffb92014-04-03 14:43:30 -0700888 log.warn("Switch {} already removed, ignoring", switchEvent);
889 return;
890 }
Pavlin Radoslavov3c9cc552014-02-20 09:58:38 -0800891
Ray Milkey269ffb92014-04-03 14:43:30 -0700892 //
893 // Remove all Ports on the Switch
894 //
895 ArrayList<PortEvent> portsToRemove = new ArrayList<>();
Yuta HIGUCHI8b389a72014-07-18 13:50:00 -0700896 for (Port port : topology.getPorts(dpid)) {
Ray Milkey269ffb92014-04-03 14:43:30 -0700897 log.warn("Port {} on Switch {} should be removed prior to removing Switch. Removing Port now.",
898 port, switchEvent);
Yuta HIGUCHIcd14dda2014-07-24 09:57:22 -0700899 PortEvent portEvent = new PortEvent(port.getSwitchPort());
Ray Milkey269ffb92014-04-03 14:43:30 -0700900 portsToRemove.add(portEvent);
901 }
Ray Milkeyb29e6262014-04-09 16:02:14 -0700902 for (PortEvent portEvent : portsToRemove) {
Ray Milkey269ffb92014-04-03 14:43:30 -0700903 removePort(portEvent);
Ray Milkeyb29e6262014-04-09 16:02:14 -0700904 }
Pavlin Radoslavov3c9cc552014-02-20 09:58:38 -0800905
Yuta HIGUCHI8b389a72014-07-18 13:50:00 -0700906 log.debug("Removed {}", swInTopo);
907 topology.removeSwitch(dpid);
908 apiRemovedSwitchEvents.add(swInTopo);
Pavlin Radoslavov3c9cc552014-02-20 09:58:38 -0800909 }
910
Pavlin Radoslavov734ff5a2014-02-26 10:20:43 -0800911 /**
Yuta HIGUCHI7926ba32014-07-09 11:39:32 -0700912 * Adds a port to the topology replica.
Pavlin Radoslavov734ff5a2014-02-26 10:20:43 -0800913 *
Yuta HIGUCHIbf0a8712014-06-30 18:59:46 -0700914 * @param portEvent the PortEvent with the port to add.
Pavlin Radoslavovd7b792e2014-08-01 02:47:47 -0700915 * @return true if the item was successfully added, otherwise false.
Pavlin Radoslavov734ff5a2014-02-26 10:20:43 -0800916 */
Yuta HIGUCHIbc67a052014-06-30 10:37:09 -0700917 @GuardedBy("topology.writeLock")
Pavlin Radoslavovd7b792e2014-08-01 02:47:47 -0700918 private boolean addPort(PortEvent portEvent) {
Jonathan Harte37e4e22014-05-13 19:12:02 -0700919 Switch sw = topology.getSwitch(portEvent.getDpid());
Ray Milkey269ffb92014-04-03 14:43:30 -0700920 if (sw == null) {
Pavlin Radoslavovd7b792e2014-08-01 02:47:47 -0700921 // Reordered event
Jonathan Hartf1675202014-05-23 14:59:07 -0700922 log.debug("{} reordered because switch is null", portEvent);
Pavlin Radoslavovd7b792e2014-08-01 02:47:47 -0700923 return false;
Ray Milkey269ffb92014-04-03 14:43:30 -0700924 }
Pavlin Radoslavov3c9cc552014-02-20 09:58:38 -0800925
Yuta HIGUCHI8b389a72014-07-18 13:50:00 -0700926 if (log.isDebugEnabled()) {
927 PortEvent port = topology.getPortEvent(portEvent.getSwitchPort());
928 if (port != null) {
929 log.debug("Update {}", portEvent);
930 } else {
931 log.debug("Added {}", portEvent);
932 }
Ray Milkey269ffb92014-04-03 14:43:30 -0700933 }
Yuta HIGUCHI8b389a72014-07-18 13:50:00 -0700934 topology.putPort(portEvent.freeze());
Ray Milkey269ffb92014-04-03 14:43:30 -0700935 apiAddedPortEvents.add(portEvent);
Pavlin Radoslavovd7b792e2014-08-01 02:47:47 -0700936 return true;
Pavlin Radoslavov3c9cc552014-02-20 09:58:38 -0800937 }
938
Pavlin Radoslavov734ff5a2014-02-26 10:20:43 -0800939 /**
Yuta HIGUCHI7926ba32014-07-09 11:39:32 -0700940 * Removes a port from the topology replica.
Yuta HIGUCHIbf0a8712014-06-30 18:59:46 -0700941 * <p/>
Yuta HIGUCHI8b389a72014-07-18 13:50:00 -0700942 * It will remove attachment points from each hosts on this port
Yuta HIGUCHIbf0a8712014-06-30 18:59:46 -0700943 * and call {@link #removeLink(LinkEvent)} for each links on this port.
Pavlin Radoslavov734ff5a2014-02-26 10:20:43 -0800944 *
Yuta HIGUCHIbf0a8712014-06-30 18:59:46 -0700945 * @param portEvent the PortEvent with the port to remove.
Pavlin Radoslavov734ff5a2014-02-26 10:20:43 -0800946 */
Yuta HIGUCHIbc67a052014-06-30 10:37:09 -0700947 @GuardedBy("topology.writeLock")
Pavlin Radoslavov3c9cc552014-02-20 09:58:38 -0800948 private void removePort(PortEvent portEvent) {
Yuta HIGUCHI8b389a72014-07-18 13:50:00 -0700949 SwitchEvent sw = topology.getSwitchEvent(portEvent.getDpid());
Ray Milkey269ffb92014-04-03 14:43:30 -0700950 if (sw == null) {
951 log.warn("Parent Switch for Port {} already removed, ignoring",
952 portEvent);
953 return;
954 }
Pavlin Radoslavov3c9cc552014-02-20 09:58:38 -0800955
Yuta HIGUCHI8b389a72014-07-18 13:50:00 -0700956 final SwitchPort switchPort = portEvent.getSwitchPort();
957 PortEvent portInTopo = topology.getPortEvent(switchPort);
958 if (portInTopo == null) {
Ray Milkey269ffb92014-04-03 14:43:30 -0700959 log.warn("Port {} already removed, ignoring", portEvent);
960 return;
961 }
Pavlin Radoslavov3c9cc552014-02-20 09:58:38 -0800962
Ray Milkey269ffb92014-04-03 14:43:30 -0700963 //
Yuta HIGUCHI8b389a72014-07-18 13:50:00 -0700964 // Remove all Host attachment points bound to this Port
Ray Milkey269ffb92014-04-03 14:43:30 -0700965 //
Yuta HIGUCHI8b389a72014-07-18 13:50:00 -0700966 List<HostEvent> hostsToUpdate = new ArrayList<>();
967 for (Host host : topology.getHosts(switchPort)) {
968 log.debug("Removing Host {} on Port {}", host, portInTopo);
969 HostEvent hostEvent = topology.getHostEvent(host.getMacAddress());
970 hostsToUpdate.add(hostEvent);
Ray Milkey269ffb92014-04-03 14:43:30 -0700971 }
Yuta HIGUCHI8b389a72014-07-18 13:50:00 -0700972 for (HostEvent hostEvent : hostsToUpdate) {
973 HostEvent newHostEvent = new HostEvent(hostEvent);
974 newHostEvent.removeAttachmentPoint(switchPort);
975 newHostEvent.freeze();
976
977 // TODO should this event be fired inside #addHost?
978 if (newHostEvent.getAttachmentPoints().isEmpty()) {
979 // No more attachment point left -> remove Host
980 removeHost(hostEvent);
981 } else {
982 // Update Host
983 addHost(newHostEvent);
984 }
Ray Milkeyb29e6262014-04-09 16:02:14 -0700985 }
Pavlin Radoslavov3c9cc552014-02-20 09:58:38 -0800986
Ray Milkey269ffb92014-04-03 14:43:30 -0700987 //
988 // Remove all Links connected to the Port
989 //
990 Set<Link> links = new HashSet<>();
Yuta HIGUCHI8b389a72014-07-18 13:50:00 -0700991 links.addAll(topology.getOutgoingLinks(switchPort));
992 links.addAll(topology.getIncomingLinks(switchPort));
Ray Milkey269ffb92014-04-03 14:43:30 -0700993 for (Link link : links) {
Ray Milkeyb29e6262014-04-09 16:02:14 -0700994 if (link == null) {
Ray Milkey269ffb92014-04-03 14:43:30 -0700995 continue;
Ray Milkeyb29e6262014-04-09 16:02:14 -0700996 }
Yuta HIGUCHI8b389a72014-07-18 13:50:00 -0700997 LinkEvent linkEvent = topology.getLinkEvent(link.getLinkTuple());
998 if (linkEvent != null) {
999 log.debug("Removing Link {} on Port {}", link, portInTopo);
1000 removeLink(linkEvent);
1001 }
Ray Milkeyb29e6262014-04-09 16:02:14 -07001002 }
Pavlin Radoslavov3c9cc552014-02-20 09:58:38 -08001003
Yuta HIGUCHI8b389a72014-07-18 13:50:00 -07001004 // Remove the Port from Topology
1005 log.debug("Removed {}", portInTopo);
1006 topology.removePort(switchPort);
Pavlin Radoslavov74986ce2014-02-20 13:17:20 -08001007
Yuta HIGUCHI8b389a72014-07-18 13:50:00 -07001008 apiRemovedPortEvents.add(portInTopo);
Pavlin Radoslavov3c9cc552014-02-20 09:58:38 -08001009 }
1010
Pavlin Radoslavov734ff5a2014-02-26 10:20:43 -08001011 /**
Yuta HIGUCHI7926ba32014-07-09 11:39:32 -07001012 * Adds a link to the topology replica.
Yuta HIGUCHIbf0a8712014-06-30 18:59:46 -07001013 * <p/>
Yuta HIGUCHI8b389a72014-07-18 13:50:00 -07001014 * It will remove attachment points from each hosts using the same ports.
Pavlin Radoslavov734ff5a2014-02-26 10:20:43 -08001015 *
Yuta HIGUCHIbf0a8712014-06-30 18:59:46 -07001016 * @param linkEvent the LinkEvent with the link to add.
Pavlin Radoslavovd7b792e2014-08-01 02:47:47 -07001017 * @return true if the item was successfully added, otherwise false.
Pavlin Radoslavov734ff5a2014-02-26 10:20:43 -08001018 */
Yuta HIGUCHIbc67a052014-06-30 10:37:09 -07001019 @GuardedBy("topology.writeLock")
Pavlin Radoslavovd7b792e2014-08-01 02:47:47 -07001020 private boolean addLink(LinkEvent linkEvent) {
Yuta HIGUCHI8b389a72014-07-18 13:50:00 -07001021 PortEvent srcPort = topology.getPortEvent(linkEvent.getSrc());
1022 PortEvent dstPort = topology.getPortEvent(linkEvent.getDst());
Ray Milkey269ffb92014-04-03 14:43:30 -07001023 if ((srcPort == null) || (dstPort == null)) {
Pavlin Radoslavovd7b792e2014-08-01 02:47:47 -07001024 // Reordered event
Jonathan Hartf1675202014-05-23 14:59:07 -07001025 log.debug("{} reordered because {} port is null", linkEvent,
1026 (srcPort == null) ? "src" : "dst");
Pavlin Radoslavovd7b792e2014-08-01 02:47:47 -07001027 return false;
Ray Milkey269ffb92014-04-03 14:43:30 -07001028 }
Pavlin Radoslavov3c9cc552014-02-20 09:58:38 -08001029
Pavlin Radoslavovd7b792e2014-08-01 02:47:47 -07001030 //
1031 // XXX domain knowledge: Sanity check: Port cannot have both Link and
1032 // Host.
1033 //
1034 // FIXME: Potentially local replica may not be up-to-date yet due to
1035 // Hazelcast delay.
1036 // FIXME: May need to manage local truth and use them instead.
1037 //
Yuta HIGUCHI8b389a72014-07-18 13:50:00 -07001038 if (topology.getLinkEvent(linkEvent.getLinkTuple()) == null) {
1039 // Only check for existing Host when adding new Link.
Yuta HIGUCHI8b389a72014-07-18 13:50:00 -07001040 // Remove all Hosts attached to the ports on both ends
1041
Pavlin Radoslavovd7b792e2014-08-01 02:47:47 -07001042 Set<HostEvent> hostsToUpdate =
1043 new TreeSet<>(new Comparator<HostEvent>() {
1044 // Comparison only using ID(=MAC)
Yuta HIGUCHI8b389a72014-07-18 13:50:00 -07001045 @Override
1046 public int compare(HostEvent o1, HostEvent o2) {
1047 return Long.compare(o1.getMac().toLong(), o2.getMac().toLong());
1048 }
1049 });
1050
1051 List<SwitchPort> portsToCheck = Arrays.asList(
1052 srcPort.getSwitchPort(),
1053 dstPort.getSwitchPort());
1054
1055 // Enumerate Host which needs to be updated by this Link add event
1056 for (SwitchPort port : portsToCheck) {
1057 for (Host host : topology.getHosts(port)) {
Yuta HIGUCHIbfc77f02014-07-14 22:50:25 -07001058 log.error("Host {} on Port {} should have been removed prior to adding Link {}",
1059 host, port, linkEvent);
Yuta HIGUCHI8b389a72014-07-18 13:50:00 -07001060
1061 HostEvent hostEvent = topology.getHostEvent(host.getMacAddress());
1062 hostsToUpdate.add(hostEvent);
Ray Milkey269ffb92014-04-03 14:43:30 -07001063 }
1064 }
Pavlin Radoslavovd7b792e2014-08-01 02:47:47 -07001065 // Remove attachment point from them
Yuta HIGUCHI8b389a72014-07-18 13:50:00 -07001066 for (HostEvent hostEvent : hostsToUpdate) {
Pavlin Radoslavovd7b792e2014-08-01 02:47:47 -07001067 // Remove port from attachment point and update
Yuta HIGUCHI8b389a72014-07-18 13:50:00 -07001068 HostEvent newHostEvent = new HostEvent(hostEvent);
1069 newHostEvent.removeAttachmentPoint(srcPort.getSwitchPort());
1070 newHostEvent.removeAttachmentPoint(dstPort.getSwitchPort());
1071 newHostEvent.freeze();
1072
1073 // TODO should this event be fired inside #addHost?
1074 if (newHostEvent.getAttachmentPoints().isEmpty()) {
1075 // No more attachment point left -> remove Host
1076 removeHost(hostEvent);
1077 } else {
1078 // Update Host
1079 addHost(newHostEvent);
1080 }
Ray Milkeyb29e6262014-04-09 16:02:14 -07001081 }
Ray Milkey269ffb92014-04-03 14:43:30 -07001082 }
Pavlin Radoslavov74986ce2014-02-20 13:17:20 -08001083
Yuta HIGUCHI8b389a72014-07-18 13:50:00 -07001084 if (log.isDebugEnabled()) {
1085 LinkEvent link = topology.getLinkEvent(linkEvent.getLinkTuple());
1086 if (link != null) {
1087 log.debug("Update {}", linkEvent);
1088 } else {
1089 log.debug("Added {}", linkEvent);
1090 }
1091 }
1092 topology.putLink(linkEvent.freeze());
Ray Milkey269ffb92014-04-03 14:43:30 -07001093 apiAddedLinkEvents.add(linkEvent);
Pavlin Radoslavovd7b792e2014-08-01 02:47:47 -07001094 return true;
Pavlin Radoslavov3c9cc552014-02-20 09:58:38 -08001095 }
1096
Pavlin Radoslavov734ff5a2014-02-26 10:20:43 -08001097 /**
Yuta HIGUCHI7926ba32014-07-09 11:39:32 -07001098 * Removes a link from the topology replica.
Pavlin Radoslavov734ff5a2014-02-26 10:20:43 -08001099 *
Yuta HIGUCHIbf0a8712014-06-30 18:59:46 -07001100 * @param linkEvent the LinkEvent with the link to remove.
Pavlin Radoslavov734ff5a2014-02-26 10:20:43 -08001101 */
Yuta HIGUCHIbc67a052014-06-30 10:37:09 -07001102 @GuardedBy("topology.writeLock")
Pavlin Radoslavov3c9cc552014-02-20 09:58:38 -08001103 private void removeLink(LinkEvent linkEvent) {
Yuta HIGUCHI8f3dfa32014-06-25 00:14:25 -07001104 Port srcPort = topology.getPort(linkEvent.getSrc().getDpid(),
Yuta HIGUCHIb1e2ab72014-06-30 11:01:31 -07001105 linkEvent.getSrc().getPortNumber());
Ray Milkey269ffb92014-04-03 14:43:30 -07001106 if (srcPort == null) {
1107 log.warn("Src Port for Link {} already removed, ignoring",
1108 linkEvent);
1109 return;
1110 }
Pavlin Radoslavov3c9cc552014-02-20 09:58:38 -08001111
Yuta HIGUCHI8f3dfa32014-06-25 00:14:25 -07001112 Port dstPort = topology.getPort(linkEvent.getDst().getDpid(),
Yuta HIGUCHIb1e2ab72014-06-30 11:01:31 -07001113 linkEvent.getDst().getPortNumber());
Ray Milkey269ffb92014-04-03 14:43:30 -07001114 if (dstPort == null) {
1115 log.warn("Dst Port for Link {} already removed, ignoring",
1116 linkEvent);
1117 return;
1118 }
Pavlin Radoslavov3c9cc552014-02-20 09:58:38 -08001119
Yuta HIGUCHI8b389a72014-07-18 13:50:00 -07001120 LinkEvent linkInTopo = topology.getLinkEvent(linkEvent.getLinkTuple(),
1121 linkEvent.getType());
1122 if (linkInTopo == null) {
1123 log.warn("Link {} already removed, ignoring", linkEvent);
1124 return;
Ray Milkey269ffb92014-04-03 14:43:30 -07001125 }
Jonathan Hart25bd53e2014-04-30 23:44:09 -07001126
Yuta HIGUCHI8b389a72014-07-18 13:50:00 -07001127 if (log.isDebugEnabled()) {
1128 // only do sanity check on debug level
1129
1130 Link linkIn = dstPort.getIncomingLink(linkEvent.getType());
1131 if (linkIn == null) {
1132 log.warn("Link {} already removed on destination Port", linkEvent);
1133 }
1134 Link linkOut = srcPort.getOutgoingLink(linkEvent.getType());
1135 if (linkOut == null) {
1136 log.warn("Link {} already removed on src Port", linkEvent);
1137 }
Jonathan Hart25bd53e2014-04-30 23:44:09 -07001138 }
Pavlin Radoslavov74986ce2014-02-20 13:17:20 -08001139
Yuta HIGUCHI8b389a72014-07-18 13:50:00 -07001140 log.debug("Removed {}", linkInTopo);
1141 topology.removeLink(linkEvent.getLinkTuple(), linkEvent.getType());
1142 apiRemovedLinkEvents.add(linkInTopo);
Pavlin Radoslavov3c9cc552014-02-20 09:58:38 -08001143 }
1144
Pavlin Radoslavov734ff5a2014-02-26 10:20:43 -08001145 /**
Yuta HIGUCHIbfc77f02014-07-14 22:50:25 -07001146 * Adds a host to the topology replica.
Ray Milkey269ffb92014-04-03 14:43:30 -07001147 * <p/>
Yuta HIGUCHIbfc77f02014-07-14 22:50:25 -07001148 * TODO: Host-related work is incomplete.
Pavlin Radoslavov734ff5a2014-02-26 10:20:43 -08001149 * TODO: Eventually, we might need to consider reordering
Pavlin Radoslavovd7b792e2014-08-01 02:47:47 -07001150 * or {@link #addLink(LinkEvent)} and {@link #addHost(HostEvent)} events
1151 * on the same port.
Pavlin Radoslavov734ff5a2014-02-26 10:20:43 -08001152 *
Yuta HIGUCHIbfc77f02014-07-14 22:50:25 -07001153 * @param hostEvent the HostEvent with the host to add.
Pavlin Radoslavovd7b792e2014-08-01 02:47:47 -07001154 * @return true if the item was successfully added, otherwise false.
Pavlin Radoslavov734ff5a2014-02-26 10:20:43 -08001155 */
Yuta HIGUCHIbc67a052014-06-30 10:37:09 -07001156 @GuardedBy("topology.writeLock")
Pavlin Radoslavovd7b792e2014-08-01 02:47:47 -07001157 private boolean addHost(HostEvent hostEvent) {
Pavlin Radoslavov3c9cc552014-02-20 09:58:38 -08001158
Yuta HIGUCHI8b389a72014-07-18 13:50:00 -07001159 // TODO Decide how to handle update scenario.
1160 // If the new HostEvent has less attachment point compared to
1161 // existing HostEvent, what should the event be?
1162 // - AddHostEvent with some attachment point removed? (current behavior)
Pavlin Radoslavov3c9cc552014-02-20 09:58:38 -08001163
Yuta HIGUCHI8b389a72014-07-18 13:50:00 -07001164 // create unfrozen copy
1165 // for removing attachment points which already has a link
1166 HostEvent modifiedHostEvent = new HostEvent(hostEvent);
Pavlin Radoslavov3c9cc552014-02-20 09:58:38 -08001167
Yuta HIGUCHI8b389a72014-07-18 13:50:00 -07001168 // Verify each attachment point
Ray Milkey269ffb92014-04-03 14:43:30 -07001169 boolean attachmentFound = false;
Yuta HIGUCHIbfc77f02014-07-14 22:50:25 -07001170 for (SwitchPort swp : hostEvent.getAttachmentPoints()) {
1171 // XXX domain knowledge: Port must exist before Host
Yuta HIGUCHIbf0a8712014-06-30 18:59:46 -07001172 // but this knowledge cannot be pushed down to driver.
1173
Ray Milkey269ffb92014-04-03 14:43:30 -07001174 // Attached Ports must exist
Yuta HIGUCHIb1e2ab72014-06-30 11:01:31 -07001175 Port port = topology.getPort(swp.getDpid(), swp.getPortNumber());
Ray Milkey269ffb92014-04-03 14:43:30 -07001176 if (port == null) {
Yuta HIGUCHI8b389a72014-07-18 13:50:00 -07001177 log.debug("{} reordered because port {} was not there", hostEvent, swp);
Pavlin Radoslavovd7b792e2014-08-01 02:47:47 -07001178 // Reordered event
1179 return false; // should not continue if re-applying later
Ray Milkey269ffb92014-04-03 14:43:30 -07001180 }
1181 // Attached Ports must not have Link
1182 if (port.getOutgoingLink() != null ||
1183 port.getIncomingLink() != null) {
Yuta HIGUCHI8b389a72014-07-18 13:50:00 -07001184 log.warn("Link (Out:{},In:{}) exist on the attachment point. "
1185 + "Ignoring this attachmentpoint ({}) from {}.",
1186 port.getOutgoingLink(), port.getIncomingLink(),
1187 swp, modifiedHostEvent);
1188 // FIXME Should either reject, reorder this HostEvent,
1189 // or remove attachment point from given HostEvent
1190 // Removing attachment point from given HostEvent for now.
1191 modifiedHostEvent.removeAttachmentPoint(swp);
Ray Milkey269ffb92014-04-03 14:43:30 -07001192 continue;
1193 }
1194
Ray Milkey269ffb92014-04-03 14:43:30 -07001195 attachmentFound = true;
1196 }
1197
Yuta HIGUCHIbfc77f02014-07-14 22:50:25 -07001198 // Update the host in the topology
Ray Milkey269ffb92014-04-03 14:43:30 -07001199 if (attachmentFound) {
Yuta HIGUCHI8b389a72014-07-18 13:50:00 -07001200 if (modifiedHostEvent.getAttachmentPoints().isEmpty()) {
1201 log.warn("No valid attachment point left. Ignoring."
1202 + "original: {}, modified: {}", hostEvent, modifiedHostEvent);
1203 // TODO Should we call #removeHost to trigger remove event?
1204 // only if this call is update.
Pavlin Radoslavovd7b792e2014-08-01 02:47:47 -07001205 return false;
Yuta HIGUCHI8b389a72014-07-18 13:50:00 -07001206 }
1207
1208 if (log.isDebugEnabled()) {
1209 HostEvent host = topology.getHostEvent(hostEvent.getMac());
1210 if (host != null) {
1211 log.debug("Update {}", modifiedHostEvent);
1212 } else {
1213 log.debug("Added {}", modifiedHostEvent);
1214 }
1215 }
1216 topology.putHost(modifiedHostEvent.freeze());
1217 apiAddedHostEvents.add(modifiedHostEvent);
Pavlin Radoslavovd7b792e2014-08-01 02:47:47 -07001218 return true;
Ray Milkey269ffb92014-04-03 14:43:30 -07001219 }
Pavlin Radoslavovd7b792e2014-08-01 02:47:47 -07001220 return false;
Pavlin Radoslavov3c9cc552014-02-20 09:58:38 -08001221 }
1222
Pavlin Radoslavov734ff5a2014-02-26 10:20:43 -08001223 /**
Yuta HIGUCHIbfc77f02014-07-14 22:50:25 -07001224 * Removes a host from the topology replica.
Ray Milkey269ffb92014-04-03 14:43:30 -07001225 * <p/>
Yuta HIGUCHIbfc77f02014-07-14 22:50:25 -07001226 * TODO: Host-related work is incomplete.
Pavlin Radoslavov734ff5a2014-02-26 10:20:43 -08001227 *
Yuta HIGUCHIbfc77f02014-07-14 22:50:25 -07001228 * @param hostEvent the Host Event with the host to remove.
Pavlin Radoslavov734ff5a2014-02-26 10:20:43 -08001229 */
Yuta HIGUCHIbc67a052014-06-30 10:37:09 -07001230 @GuardedBy("topology.writeLock")
Yuta HIGUCHIbfc77f02014-07-14 22:50:25 -07001231 private void removeHost(HostEvent hostEvent) {
Yuta HIGUCHI8b389a72014-07-18 13:50:00 -07001232
1233 final MACAddress mac = hostEvent.getMac();
1234 HostEvent hostInTopo = topology.getHostEvent(mac);
1235 if (hostInTopo == null) {
Yuta HIGUCHIbfc77f02014-07-14 22:50:25 -07001236 log.warn("Host {} already removed, ignoring", hostEvent);
Ray Milkey269ffb92014-04-03 14:43:30 -07001237 return;
1238 }
Pavlin Radoslavov3c9cc552014-02-20 09:58:38 -08001239
Yuta HIGUCHI8b389a72014-07-18 13:50:00 -07001240 log.debug("Removed {}", hostInTopo);
1241 topology.removeHost(mac);
1242 apiRemovedHostEvents.add(hostInTopo);
Pavlin Radoslavov3c9cc552014-02-20 09:58:38 -08001243 }
Jonathan Hart22eb9882014-02-11 15:52:59 -08001244
Pavlin Radoslavovc1cfde52014-02-19 11:35:29 -08001245 /**
Pavlin Radoslavov734ff5a2014-02-26 10:20:43 -08001246 * Read the whole topology from the database.
1247 *
Pavlin Radoslavovd7b792e2014-08-01 02:47:47 -07001248 * @return a list of EventEntry-encapsulated Topology Events for
Pavlin Radoslavov734ff5a2014-02-26 10:20:43 -08001249 * the whole topology.
1250 */
Pavlin Radoslavovd7b792e2014-08-01 02:47:47 -07001251 private List<EventEntry<TopologyEvent>> readWholeTopologyFromDB() {
1252 List<EventEntry<TopologyEvent>> events =
Ray Milkey269ffb92014-04-03 14:43:30 -07001253 new LinkedList<EventEntry<TopologyEvent>>();
Pavlin Radoslavov018d5332014-02-19 23:08:35 -08001254
Ray Milkey269ffb92014-04-03 14:43:30 -07001255 // XXX May need to clear whole topology first, depending on
1256 // how we initially subscribe to replication events
Pavlin Radoslavovc1cfde52014-02-19 11:35:29 -08001257
Ray Milkey269ffb92014-04-03 14:43:30 -07001258 // Add all active switches
1259 for (KVSwitch sw : KVSwitch.getAllSwitches()) {
1260 if (sw.getStatus() != KVSwitch.STATUS.ACTIVE) {
1261 continue;
1262 }
Pavlin Radoslavov018d5332014-02-19 23:08:35 -08001263
Pavlin Radoslavova5637c02014-07-30 15:55:11 -07001264 //
1265 // TODO: Using the local ONOS Instance ID below is incorrect.
1266 // Currently, this code is not used, and it might go away in the
1267 // future.
1268 //
Yuta HIGUCHIe2a4e172014-07-03 10:50:39 -07001269 SwitchEvent switchEvent = new SwitchEvent(new Dpid(sw.getDpid()));
Pavlin Radoslavova5637c02014-07-30 15:55:11 -07001270 TopologyEvent topologyEvent =
1271 new TopologyEvent(switchEvent,
1272 registryService.getOnosInstanceId());
Ray Milkey269ffb92014-04-03 14:43:30 -07001273 EventEntry<TopologyEvent> eventEntry =
1274 new EventEntry<TopologyEvent>(EventEntry.Type.ENTRY_ADD,
1275 topologyEvent);
Pavlin Radoslavovd7b792e2014-08-01 02:47:47 -07001276 events.add(eventEntry);
Ray Milkey269ffb92014-04-03 14:43:30 -07001277 }
Yuta HIGUCHIa536e762014-02-17 21:47:28 -08001278
Ray Milkey269ffb92014-04-03 14:43:30 -07001279 // Add all active ports
1280 for (KVPort p : KVPort.getAllPorts()) {
1281 if (p.getStatus() != KVPort.STATUS.ACTIVE) {
1282 continue;
1283 }
Pavlin Radoslavov018d5332014-02-19 23:08:35 -08001284
Pavlin Radoslavova5637c02014-07-30 15:55:11 -07001285 //
1286 // TODO: Using the local ONOS Instance ID below is incorrect.
1287 // Currently, this code is not used, and it might go away in the
1288 // future.
1289 //
1290 PortEvent portEvent =
1291 new PortEvent(new Dpid(p.getDpid()),
1292 new PortNumber(p.getNumber().shortValue()));
1293 TopologyEvent topologyEvent =
1294 new TopologyEvent(portEvent,
1295 registryService.getOnosInstanceId());
Ray Milkey269ffb92014-04-03 14:43:30 -07001296 EventEntry<TopologyEvent> eventEntry =
1297 new EventEntry<TopologyEvent>(EventEntry.Type.ENTRY_ADD,
1298 topologyEvent);
Pavlin Radoslavovd7b792e2014-08-01 02:47:47 -07001299 events.add(eventEntry);
Ray Milkey269ffb92014-04-03 14:43:30 -07001300 }
Yuta HIGUCHIa536e762014-02-17 21:47:28 -08001301
Pavlin Radoslavova5637c02014-07-30 15:55:11 -07001302 for (KVDevice d : KVDevice.getAllDevices()) {
1303 //
1304 // TODO: Using the local ONOS Instance ID below is incorrect.
1305 // Currently, this code is not used, and it might go away in the
1306 // future.
1307 //
1308 HostEvent devEvent = new HostEvent(MACAddress.valueOf(d.getMac()));
1309 for (byte[] portId : d.getAllPortIds()) {
1310 devEvent.addAttachmentPoint(
1311 new SwitchPort(KVPort.getDpidFromKey(portId),
1312 KVPort.getNumberFromKey(portId)));
1313 }
1314 }
Pavlin Radoslavovc1cfde52014-02-19 11:35:29 -08001315
Ray Milkey269ffb92014-04-03 14:43:30 -07001316 for (KVLink l : KVLink.getAllLinks()) {
Pavlin Radoslavova5637c02014-07-30 15:55:11 -07001317 //
1318 // TODO: Using the local ONOS Instance ID below is incorrect.
1319 // Currently, this code is not used, and it might go away in the
1320 // future.
1321 //
Yuta HIGUCHIe2a4e172014-07-03 10:50:39 -07001322 LinkEvent linkEvent = new LinkEvent(
Pavlin Radoslavova5637c02014-07-30 15:55:11 -07001323 new SwitchPort(l.getSrc().dpid, l.getSrc().number),
1324 new SwitchPort(l.getDst().dpid, l.getDst().number));
1325 TopologyEvent topologyEvent =
1326 new TopologyEvent(linkEvent,
1327 registryService.getOnosInstanceId());
Ray Milkey269ffb92014-04-03 14:43:30 -07001328 EventEntry<TopologyEvent> eventEntry =
1329 new EventEntry<TopologyEvent>(EventEntry.Type.ENTRY_ADD,
1330 topologyEvent);
Pavlin Radoslavovd7b792e2014-08-01 02:47:47 -07001331 events.add(eventEntry);
Ray Milkey269ffb92014-04-03 14:43:30 -07001332 }
Pavlin Radoslavov018d5332014-02-19 23:08:35 -08001333
Pavlin Radoslavovd7b792e2014-08-01 02:47:47 -07001334 return events;
Pavlin Radoslavovc1cfde52014-02-19 11:35:29 -08001335 }
Jonathan Hart062a2e82014-02-03 09:41:57 -08001336}