blob: 532ad8db835458bff55298cdb8e0c7fc8525aa0b [file] [log] [blame]
Jonathan Hart062a2e82014-02-03 09:41:57 -08001package net.onrc.onos.ofcontroller.networkgraph;
2
Yuta HIGUCHI1c700102014-02-12 16:30:52 -08003import java.net.InetAddress;
Yuta HIGUCHI8d762e92014-02-12 14:10:25 -08004import java.util.ArrayList;
Pavlin Radoslavov721a2e02014-02-14 23:40:14 -08005import java.util.Collection;
Yuta HIGUCHI8d762e92014-02-12 14:10:25 -08006import java.util.HashSet;
Pavlin Radoslavov721a2e02014-02-14 23:40:14 -08007import java.util.LinkedList;
Yuta HIGUCHI8d762e92014-02-12 14:10:25 -08008import java.util.List;
9import java.util.Set;
Pavlin Radoslavov721a2e02014-02-14 23:40:14 -080010import java.util.concurrent.BlockingQueue;
Yuta HIGUCHIa536e762014-02-17 21:47:28 -080011import java.util.concurrent.CopyOnWriteArrayList;
Pavlin Radoslavov721a2e02014-02-14 23:40:14 -080012import java.util.concurrent.LinkedBlockingQueue;
Yuta HIGUCHI8d762e92014-02-12 14:10:25 -080013
Pavlin Radoslavov721a2e02014-02-14 23:40:14 -080014import net.onrc.onos.datagrid.IDatagridService;
15import net.onrc.onos.datagrid.IEventChannel;
16import net.onrc.onos.datagrid.IEventChannelListener;
Yuta HIGUCHI765cd0d2014-02-06 12:46:41 -080017import net.onrc.onos.datastore.topology.RCLink;
Jonathan Hart062a2e82014-02-03 09:41:57 -080018import net.onrc.onos.datastore.topology.RCPort;
19import net.onrc.onos.datastore.topology.RCSwitch;
Yuta HIGUCHI8d762e92014-02-12 14:10:25 -080020import net.onrc.onos.ofcontroller.networkgraph.PortEvent.SwitchPort;
Pavlin Radoslavov721a2e02014-02-14 23:40:14 -080021import net.onrc.onos.ofcontroller.util.EventEntry;
Yuta HIGUCHI765cd0d2014-02-06 12:46:41 -080022import net.onrc.onos.ofcontroller.util.Dpid;
Yuta HIGUCHI170229f2014-02-17 15:47:54 -080023import net.onrc.onos.registry.controller.IControllerRegistryService;
Jonathan Hart062a2e82014-02-03 09:41:57 -080024
25import org.slf4j.Logger;
26import org.slf4j.LoggerFactory;
27
Yuta HIGUCHI181d34d2014-02-05 15:05:46 -080028/**
29 * The "NB" read-only Network Map.
30 *
Yuta HIGUCHI4bfdd532014-02-07 13:47:36 -080031 * - Maintain Invariant/Relationships between Topology Objects.
32 *
Yuta HIGUCHI765cd0d2014-02-06 12:46:41 -080033 * TODO To be synchronized based on TopologyEvent Notification.
Yuta HIGUCHI181d34d2014-02-05 15:05:46 -080034 *
Yuta HIGUCHIcb951982014-02-11 13:31:44 -080035 * TODO TBD: Caller is expected to maintain parent/child calling order. Parent
Yuta HIGUCHI1c700102014-02-12 16:30:52 -080036 * Object must exist before adding sub component(Add Switch -> Port).
Yuta HIGUCHIcb951982014-02-11 13:31:44 -080037 *
Yuta HIGUCHI4bfdd532014-02-07 13:47:36 -080038 * TODO TBD: This class may delay the requested change to handle event
39 * re-ordering. e.g.) Link Add came in, but Switch was not there.
Yuta HIGUCHIcb951982014-02-11 13:31:44 -080040 *
Yuta HIGUCHI181d34d2014-02-05 15:05:46 -080041 */
Pavlin Radoslavovdb7dbb22014-02-18 14:45:10 -080042public class TopologyManager extends AbstractNetworkGraph implements
Yuta HIGUCHI928fa682014-02-11 19:07:57 -080043 NetworkGraphDiscoveryInterface, NetworkGraphReplicationInterface {
Jonathan Hart062a2e82014-02-03 09:41:57 -080044
Yuta HIGUCHI80829d12014-02-05 20:16:56 -080045 private static final Logger log = LoggerFactory
Pavlin Radoslavovdb7dbb22014-02-18 14:45:10 -080046 .getLogger(TopologyManager.class);
Yuta HIGUCHIcd922f42014-02-11 18:59:11 -080047
Pavlin Radoslavov721a2e02014-02-14 23:40:14 -080048 private IEventChannel<byte[], TopologyEvent> eventChannel;
49 private static final String EVENT_CHANNEL_NAME = "onos.topology";
50 private EventHandler eventHandler = new EventHandler();
51
Jonathan Hart22eb9882014-02-11 15:52:59 -080052 private final NetworkGraphDatastore datastore;
Yuta HIGUCHI170229f2014-02-17 15:47:54 -080053 private final IControllerRegistryService registryService;
Yuta HIGUCHIa536e762014-02-17 21:47:28 -080054 private CopyOnWriteArrayList<INetworkGraphListener> networkGraphListeners;
Yuta HIGUCHI181d34d2014-02-05 15:05:46 -080055
Pavlin Radoslavovdb7dbb22014-02-18 14:45:10 -080056 public TopologyManager(IControllerRegistryService registryService, CopyOnWriteArrayList<INetworkGraphListener> networkGraphListeners) {
Yuta HIGUCHI80829d12014-02-05 20:16:56 -080057 super();
Jonathan Hart22eb9882014-02-11 15:52:59 -080058 datastore = new NetworkGraphDatastore(this);
Yuta HIGUCHI170229f2014-02-17 15:47:54 -080059 this.registryService = registryService;
Yuta HIGUCHIa536e762014-02-17 21:47:28 -080060 this.networkGraphListeners = networkGraphListeners;
Yuta HIGUCHI80829d12014-02-05 20:16:56 -080061 }
Yuta HIGUCHI181d34d2014-02-05 15:05:46 -080062
Yuta HIGUCHI4bfdd532014-02-07 13:47:36 -080063 /**
Pavlin Radoslavov721a2e02014-02-14 23:40:14 -080064 * Event handler class.
65 */
66 private class EventHandler extends Thread implements
67 IEventChannelListener<byte[], TopologyEvent> {
68 private BlockingQueue<EventEntry<TopologyEvent>> topologyEvents =
69 new LinkedBlockingQueue<EventEntry<TopologyEvent>>();
70
71 /**
72 * Startup processing.
73 */
74 private void startup() {
75 //
76 // TODO: Read all state from the database
77 // For now, as a shortcut we read it from the datagrid
78 //
79 Collection<TopologyEvent> topologyEvents =
80 eventChannel.getAllEntries();
81 Collection<EventEntry<TopologyEvent>> collection =
82 new LinkedList<EventEntry<TopologyEvent>>();
83
84 for (TopologyEvent topologyEvent : topologyEvents) {
85 EventEntry<TopologyEvent> eventEntry =
86 new EventEntry<TopologyEvent>(EventEntry.Type.ENTRY_ADD,
87 topologyEvent);
88 collection.add(eventEntry);
89 }
90 processEvents(collection);
91 }
92
93 /**
94 * Run the thread.
95 */
Yuta HIGUCHI240bf072014-02-17 10:55:21 -080096 @Override
Pavlin Radoslavov721a2e02014-02-14 23:40:14 -080097 public void run() {
98 Collection<EventEntry<TopologyEvent>> collection =
99 new LinkedList<EventEntry<TopologyEvent>>();
100
Pavlin Radoslavovdb7dbb22014-02-18 14:45:10 -0800101 this.setName("TopologyManager.EventHandler " + this.getId());
Pavlin Radoslavov721a2e02014-02-14 23:40:14 -0800102 startup();
103
104 //
105 // The main loop
106 //
107 try {
108 while (true) {
109 EventEntry<TopologyEvent> eventEntry = topologyEvents.take();
110 collection.add(eventEntry);
111 topologyEvents.drainTo(collection);
112
113 processEvents(collection);
114 collection.clear();
115 }
116 } catch (Exception exception) {
117 log.debug("Exception processing Topology Events: ", exception);
118 }
119 }
120
121 /**
122 * Process all topology events.
123 *
124 * @param events the events to process.
125 */
126 private void processEvents(Collection<EventEntry<TopologyEvent>> events) {
127 for (EventEntry<TopologyEvent> event : events) {
Yuta HIGUCHI170229f2014-02-17 15:47:54 -0800128 if (event.eventData().getOriginID().equals(registryService.getControllerId())) {
129 // ignore event triggered by myself
130 continue;
131 }
Pavlin Radoslavov721a2e02014-02-14 23:40:14 -0800132 TopologyEvent topologyEvent = event.eventData();
133 switch (event.eventType()) {
134 case ENTRY_ADD:
135 log.debug("Topology event ENTRY_ADD: {}", topologyEvent);
136 if (topologyEvent.switchEvent != null)
137 putSwitchReplicationEvent(topologyEvent.switchEvent);
138 if (topologyEvent.portEvent != null)
139 putPortReplicationEvent(topologyEvent.portEvent);
140 if (topologyEvent.linkEvent != null)
141 putLinkReplicationEvent(topologyEvent.linkEvent);
142 if (topologyEvent.deviceEvent != null)
143 putDeviceReplicationEvent(topologyEvent.deviceEvent);
144 break;
145 case ENTRY_REMOVE:
146 log.debug("Topology event ENTRY_REMOVE: {}", topologyEvent);
147 if (topologyEvent.switchEvent != null)
148 removeSwitchReplicationEvent(topologyEvent.switchEvent);
149 if (topologyEvent.portEvent != null)
150 removePortReplicationEvent(topologyEvent.portEvent);
151 if (topologyEvent.linkEvent != null)
152 removeLinkReplicationEvent(topologyEvent.linkEvent);
153 if (topologyEvent.deviceEvent != null)
154 removeDeviceReplicationEvent(topologyEvent.deviceEvent);
155 break;
156 }
157 }
158 }
159
160 /**
161 * Receive a notification that an entry is added.
162 *
163 * @param value the value for the entry.
164 */
165 @Override
166 public void entryAdded(TopologyEvent value) {
167 EventEntry<TopologyEvent> eventEntry =
168 new EventEntry<TopologyEvent>(EventEntry.Type.ENTRY_ADD,
169 value);
170 topologyEvents.add(eventEntry);
171 }
172
173 /**
174 * Receive a notification that an entry is removed.
175 *
176 * @param value the value for the entry.
177 */
178 @Override
179 public void entryRemoved(TopologyEvent value) {
180 EventEntry<TopologyEvent> eventEntry =
181 new EventEntry<TopologyEvent>(EventEntry.Type.ENTRY_REMOVE,
182 value);
183 topologyEvents.add(eventEntry);
184 }
185
186 /**
187 * Receive a notification that an entry is updated.
188 *
189 * @param value the value for the entry.
190 */
191 @Override
192 public void entryUpdated(TopologyEvent value) {
193 // NOTE: The ADD and UPDATE events are processed in same way
194 entryAdded(value);
195 }
196 }
197
198 /**
199 * Startup processing.
200 *
201 * @param datagridService the datagrid service to use.
202 */
203 void startup(IDatagridService datagridService) {
204 eventChannel = datagridService.addListener(EVENT_CHANNEL_NAME,
205 eventHandler,
206 byte[].class,
207 TopologyEvent.class);
208 eventHandler.start();
209 }
210
211 /**
Yuta HIGUCHIcb951982014-02-11 13:31:44 -0800212 * Exception to be thrown when Modification to the Network Graph cannot be continued due to broken invariant.
213 *
214 * XXX Should this be checked exception or RuntimeException
215 */
216 public static class BrokenInvariantException extends RuntimeException {
217 private static final long serialVersionUID = 1L;
218
219 public BrokenInvariantException() {
220 super();
221 }
222
223 public BrokenInvariantException(String message) {
224 super(message);
225 }
226 }
Jonathan Hart22eb9882014-02-11 15:52:59 -0800227
228 /* ******************************
229 * NetworkGraphDiscoveryInterface methods
230 * ******************************/
Yuta HIGUCHIcd922f42014-02-11 18:59:11 -0800231
Jonathan Hart22eb9882014-02-11 15:52:59 -0800232 @Override
233 public void putSwitchEvent(SwitchEvent switchEvent) {
Yuta HIGUCHId02e9282014-02-12 09:24:41 -0800234 if (prepareForAddSwitchEvent(switchEvent)) {
Jonathan Hart22eb9882014-02-11 15:52:59 -0800235 datastore.addSwitch(switchEvent);
236 putSwitch(switchEvent);
Pavlin Radoslavov721a2e02014-02-14 23:40:14 -0800237 // Send out notification
238 TopologyEvent topologyEvent =
Yuta HIGUCHI170229f2014-02-17 15:47:54 -0800239 new TopologyEvent(switchEvent, registryService.getControllerId());
Pavlin Radoslavov721a2e02014-02-14 23:40:14 -0800240 eventChannel.addEntry(topologyEvent.getID(),
241 topologyEvent);
Jonathan Hart22eb9882014-02-11 15:52:59 -0800242 }
243 // TODO handle invariant violation
244 }
245
246 @Override
247 public void removeSwitchEvent(SwitchEvent switchEvent) {
Yuta HIGUCHId02e9282014-02-12 09:24:41 -0800248 if (prepareForRemoveSwitchEvent(switchEvent)) {
Jonathan Hart22eb9882014-02-11 15:52:59 -0800249 datastore.deactivateSwitch(switchEvent);
250 removeSwitch(switchEvent);
Pavlin Radoslavov721a2e02014-02-14 23:40:14 -0800251 // Send out notification
252 eventChannel.removeEntry(switchEvent.getID());
Jonathan Hart22eb9882014-02-11 15:52:59 -0800253 }
254 // TODO handle invariant violation
255 }
256
257 @Override
258 public void putPortEvent(PortEvent portEvent) {
Jonathan Hart4c263272014-02-13 17:41:05 -0800259 if (prepareForAddPortEvent(portEvent)) {
260 datastore.addPort(portEvent);
261 putPort(portEvent);
Pavlin Radoslavov721a2e02014-02-14 23:40:14 -0800262 // Send out notification
263 TopologyEvent topologyEvent =
Yuta HIGUCHI170229f2014-02-17 15:47:54 -0800264 new TopologyEvent(portEvent, registryService.getControllerId());
Pavlin Radoslavov721a2e02014-02-14 23:40:14 -0800265 eventChannel.addEntry(topologyEvent.getID(),
266 topologyEvent);
Jonathan Hart4c263272014-02-13 17:41:05 -0800267 }
Yuta HIGUCHI75c51ed2014-02-13 17:02:26 -0800268 // TODO handle invariant violation
Jonathan Hart22eb9882014-02-11 15:52:59 -0800269 }
270
271 @Override
272 public void removePortEvent(PortEvent portEvent) {
Jonathan Hart4c263272014-02-13 17:41:05 -0800273 if (prepareForRemovePortEvent(portEvent)) {
274 datastore.deactivatePort(portEvent);
275 removePort(portEvent);
Pavlin Radoslavov721a2e02014-02-14 23:40:14 -0800276 // Send out notification
277 eventChannel.removeEntry(portEvent.getID());
Jonathan Hart4c263272014-02-13 17:41:05 -0800278 }
Yuta HIGUCHI75c51ed2014-02-13 17:02:26 -0800279 // TODO handle invariant violation
Jonathan Hart22eb9882014-02-11 15:52:59 -0800280 }
281
282 @Override
283 public void putLinkEvent(LinkEvent linkEvent) {
Yuta HIGUCHId02e9282014-02-12 09:24:41 -0800284 if (prepareForAddLinkEvent(linkEvent)) {
Jonathan Hart22eb9882014-02-11 15:52:59 -0800285 datastore.addLink(linkEvent);
286 putLink(linkEvent);
Pavlin Radoslavov721a2e02014-02-14 23:40:14 -0800287 // Send out notification
288 TopologyEvent topologyEvent =
Yuta HIGUCHI170229f2014-02-17 15:47:54 -0800289 new TopologyEvent(linkEvent, registryService.getControllerId());
Pavlin Radoslavov721a2e02014-02-14 23:40:14 -0800290 eventChannel.addEntry(topologyEvent.getID(),
291 topologyEvent);
Jonathan Hart22eb9882014-02-11 15:52:59 -0800292 }
293 // TODO handle invariant violation
294 }
295
296 @Override
297 public void removeLinkEvent(LinkEvent linkEvent) {
Yuta HIGUCHI71e7a052014-02-17 22:14:15 -0800298 removeLinkEvent(linkEvent, false);
299
300 }
301
302 private void removeLinkEvent(LinkEvent linkEvent, boolean dstCheckBeforeDBmodify) {
Yuta HIGUCHId02e9282014-02-12 09:24:41 -0800303 if (prepareForRemoveLinkEvent(linkEvent)) {
Yuta HIGUCHI71e7a052014-02-17 22:14:15 -0800304 if (dstCheckBeforeDBmodify) {
305 // write to DB only if it is owner of the dst dpid
306 if (registryService.hasControl(linkEvent.getDst().dpid)) {
307 datastore.removeLink(linkEvent);
308 }
309 } else {
310 datastore.removeLink(linkEvent);
311 }
Jonathan Hart22eb9882014-02-11 15:52:59 -0800312 removeLink(linkEvent);
Pavlin Radoslavov721a2e02014-02-14 23:40:14 -0800313 // Send out notification
314 eventChannel.removeEntry(linkEvent.getID());
Jonathan Hart22eb9882014-02-11 15:52:59 -0800315 }
316 // TODO handle invariant violation
317 }
318
319 @Override
Yuta HIGUCHI586d33e2014-02-13 17:05:08 -0800320 public void putDeviceEvent(DeviceEvent deviceEvent) {
321 if (prepareForAddDeviceEvent(deviceEvent)) {
322// datastore.addDevice(deviceEvent);
Yuta HIGUCHId457c052014-02-14 18:33:04 -0800323// putDevice(deviceEvent);
Pavlin Radoslavov721a2e02014-02-14 23:40:14 -0800324 // Send out notification
325 TopologyEvent topologyEvent =
Yuta HIGUCHI170229f2014-02-17 15:47:54 -0800326 new TopologyEvent(deviceEvent, registryService.getControllerId());
Pavlin Radoslavov721a2e02014-02-14 23:40:14 -0800327 eventChannel.addEntry(topologyEvent.getID(),
328 topologyEvent);
Yuta HIGUCHI586d33e2014-02-13 17:05:08 -0800329 }
330 // TODO handle invariant violation
331 // XXX if prepareFor~ method returned false, event should be dropped
Jonathan Hart22eb9882014-02-11 15:52:59 -0800332 }
333
334 @Override
335 public void removeDeviceEvent(DeviceEvent deviceEvent) {
Yuta HIGUCHI586d33e2014-02-13 17:05:08 -0800336 if (prepareForRemoveDeviceEvent(deviceEvent)) {
337// datastore.removeDevice(deviceEvent);
Yuta HIGUCHId457c052014-02-14 18:33:04 -0800338// removeDevice(deviceEvent);
Pavlin Radoslavov721a2e02014-02-14 23:40:14 -0800339 // Send out notification
340 eventChannel.removeEntry(deviceEvent.getID());
Yuta HIGUCHI586d33e2014-02-13 17:05:08 -0800341 }
342 // TODO handle invariant violation
343 // XXX if prepareFor~ method returned false, event should be dropped
Jonathan Hart22eb9882014-02-11 15:52:59 -0800344 }
Yuta HIGUCHIcd922f42014-02-11 18:59:11 -0800345
Jonathan Hart22eb9882014-02-11 15:52:59 -0800346 /* *****************
Yuta HIGUCHId02e9282014-02-12 09:24:41 -0800347 * Internal methods to maintain invariants of the network graph
Jonathan Hart22eb9882014-02-11 15:52:59 -0800348 * *****************/
Yuta HIGUCHIcd922f42014-02-11 18:59:11 -0800349
Yuta HIGUCHId02e9282014-02-12 09:24:41 -0800350 /**
351 *
352 * @param swEvt
353 * @return true if ready to accept event.
354 */
355 private boolean prepareForAddSwitchEvent(SwitchEvent swEvt) {
Yuta HIGUCHI76df2472014-02-12 22:36:51 -0800356 // No show stopping precondition
Yuta HIGUCHI8d762e92014-02-12 14:10:25 -0800357 // Prep: remove(deactivate) Ports on Switch, which is not on event
358 removePortsNotOnEvent(swEvt);
359 return true;
Jonathan Hart22eb9882014-02-11 15:52:59 -0800360 }
Yuta HIGUCHIcd922f42014-02-11 18:59:11 -0800361
Yuta HIGUCHId02e9282014-02-12 09:24:41 -0800362 private boolean prepareForRemoveSwitchEvent(SwitchEvent swEvt) {
Yuta HIGUCHI76df2472014-02-12 22:36:51 -0800363 // No show stopping precondition
Yuta HIGUCHI8d762e92014-02-12 14:10:25 -0800364 // Prep: remove(deactivate) Ports on Switch, which is not on event
365 // XXX may be remove switch should imply wipe all ports
366 removePortsNotOnEvent(swEvt);
367 return true;
368 }
Yuta HIGUCHId02e9282014-02-12 09:24:41 -0800369
Yuta HIGUCHI8d762e92014-02-12 14:10:25 -0800370 private void removePortsNotOnEvent(SwitchEvent swEvt) {
371 Switch sw = switches.get( swEvt.getDpid() );
372 if ( sw != null ) {
373 Set<Long> port_noOnEvent = new HashSet<>();
374 for( PortEvent portEvent : swEvt.getPorts()) {
375 port_noOnEvent.add(portEvent.getNumber());
376 }
377 // Existing ports not on event should be removed.
378 // TODO Should batch eventually for performance?
Jonathan Hart480c5572014-02-14 18:28:16 -0800379 List<Port> portsToRemove = new ArrayList<Port>();
Yuta HIGUCHI8d762e92014-02-12 14:10:25 -0800380 for( Port p : sw.getPorts() ) {
381 if ( !port_noOnEvent.contains(p.getNumber()) ) {
Jonathan Hart480c5572014-02-14 18:28:16 -0800382 //PortEvent rmEvent = new PortEvent(p.getSwitch().getDpid(), p.getNumber());
383 // calling Discovery removePort() API to wipe from DB, etc.
384 //removePortEvent(rmEvent);
Yuta HIGUCHI240bf072014-02-17 10:55:21 -0800385
Jonathan Hart480c5572014-02-14 18:28:16 -0800386 // We can't remove ports here because this will trigger a remove
387 // from the switch's port list, which we are currently iterating
388 // over.
389 portsToRemove.add(p);
390 }
391 }
392 for (Port p : portsToRemove) {
Yuta HIGUCHI8d762e92014-02-12 14:10:25 -0800393 PortEvent rmEvent = new PortEvent(p.getSwitch().getDpid(), p.getNumber());
394 // calling Discovery removePort() API to wipe from DB, etc.
395 removePortEvent(rmEvent);
Yuta HIGUCHI8d762e92014-02-12 14:10:25 -0800396 }
397 }
Jonathan Hart22eb9882014-02-11 15:52:59 -0800398 }
Yuta HIGUCHIcd922f42014-02-11 18:59:11 -0800399
Yuta HIGUCHId02e9282014-02-12 09:24:41 -0800400 private boolean prepareForAddPortEvent(PortEvent portEvt) {
Yuta HIGUCHId02e9282014-02-12 09:24:41 -0800401 // Parent Switch must exist
402 if ( getSwitch(portEvt.getDpid()) == null) {
Jonathan Hart0a4846e2014-02-18 11:03:40 -0800403 log.warn("Dropping add port event because switch doesn't exist: {}",
404 portEvt);
Yuta HIGUCHId02e9282014-02-12 09:24:41 -0800405 return false;
406 }
407 // Prep: None
Jonathan Hart22eb9882014-02-11 15:52:59 -0800408 return true;
409 }
Yuta HIGUCHIcd922f42014-02-11 18:59:11 -0800410
Yuta HIGUCHId02e9282014-02-12 09:24:41 -0800411 private boolean prepareForRemovePortEvent(PortEvent portEvt) {
Yuta HIGUCHId5315c42014-02-18 09:35:48 -0800412 Port port = getPort(portEvt.getDpid(), portEvt.getNumber());
Yuta HIGUCHI8d762e92014-02-12 14:10:25 -0800413 if ( port == null ) {
414 log.debug("Port already removed? {}", portEvt);
415 // let it pass
416 return true;
417 }
418
419 // Prep: Remove Link and Device Attachment
Yuta HIGUCHI240bf072014-02-17 10:55:21 -0800420 ArrayList<DeviceEvent> deviceEvts = new ArrayList<>();
Yuta HIGUCHI8d762e92014-02-12 14:10:25 -0800421 for (Device device : port.getDevices()) {
Yuta HIGUCHI88be0f22014-02-14 17:20:43 -0800422 log.debug("Removing Device {} on Port {}", device, portEvt);
Yuta HIGUCHI8d762e92014-02-12 14:10:25 -0800423 DeviceEvent devEvt = new DeviceEvent(device.getMacAddress());
424 devEvt.addAttachmentPoint(new SwitchPort(port.getSwitch().getDpid(), port.getNumber()));
Yuta HIGUCHI240bf072014-02-17 10:55:21 -0800425 deviceEvts.add(devEvt);
426 }
427 for (DeviceEvent devEvt : deviceEvts) {
Yuta HIGUCHI8d762e92014-02-12 14:10:25 -0800428 // calling Discovery API to wipe from DB, etc.
429 removeDeviceEvent(devEvt);
430 }
Yuta HIGUCHI240bf072014-02-17 10:55:21 -0800431
Yuta HIGUCHI8d762e92014-02-12 14:10:25 -0800432 Set<Link> links = new HashSet<>();
433 links.add(port.getOutgoingLink());
434 links.add(port.getIncomingLink());
435 for ( Link link : links) {
436 if (link == null ) {
437 continue;
438 }
Yuta HIGUCHI88be0f22014-02-14 17:20:43 -0800439 log.debug("Removing Link {} on Port {}", link, portEvt);
Yuta HIGUCHI8d762e92014-02-12 14:10:25 -0800440 LinkEvent linkEvent = new LinkEvent(link.getSourceSwitchDpid(), link.getSourcePortNumber(), link.getDestinationSwitchDpid(), link.getDestinationPortNumber());
441 // calling Discovery API to wipe from DB, etc.
Yuta HIGUCHI71e7a052014-02-17 22:14:15 -0800442
443 // Call internal remove Link, which will check
444 // ownership of DST dpid and modify DB only if it is the owner
445 removeLinkEvent(linkEvent, true);
Yuta HIGUCHI8d762e92014-02-12 14:10:25 -0800446 }
Jonathan Hart22eb9882014-02-11 15:52:59 -0800447 return true;
448 }
Yuta HIGUCHIcd922f42014-02-11 18:59:11 -0800449
Yuta HIGUCHId02e9282014-02-12 09:24:41 -0800450 private boolean prepareForAddLinkEvent(LinkEvent linkEvt) {
Yuta HIGUCHI8d762e92014-02-12 14:10:25 -0800451 // Src/Dst Port must exist
Yuta HIGUCHId5315c42014-02-18 09:35:48 -0800452 Port srcPort = getPort(linkEvt.getSrc().dpid, linkEvt.getSrc().number);
453 Port dstPort = getPort(linkEvt.getDst().dpid, linkEvt.getDst().number);
Yuta HIGUCHI8d762e92014-02-12 14:10:25 -0800454 if ( srcPort == null || dstPort == null ) {
Jonathan Hart0a4846e2014-02-18 11:03:40 -0800455 log.warn("Dropping add link event because port doesn't exist: {}",
456 linkEvt);
Yuta HIGUCHI8d762e92014-02-12 14:10:25 -0800457 return false;
458 }
459
460 // Prep: remove Device attachment on both Ports
Yuta HIGUCHI240bf072014-02-17 10:55:21 -0800461 ArrayList<DeviceEvent> deviceEvents = new ArrayList<>();
Yuta HIGUCHI8d762e92014-02-12 14:10:25 -0800462 for (Device device : srcPort.getDevices()) {
463 DeviceEvent devEvt = new DeviceEvent(device.getMacAddress());
464 devEvt.addAttachmentPoint(new SwitchPort(srcPort.getSwitch().getDpid(), srcPort.getNumber()));
Yuta HIGUCHI240bf072014-02-17 10:55:21 -0800465 deviceEvents.add(devEvt);
Yuta HIGUCHI8d762e92014-02-12 14:10:25 -0800466 }
467 for (Device device : dstPort.getDevices()) {
468 DeviceEvent devEvt = new DeviceEvent(device.getMacAddress());
469 devEvt.addAttachmentPoint(new SwitchPort(dstPort.getSwitch().getDpid(), dstPort.getNumber()));
Yuta HIGUCHI240bf072014-02-17 10:55:21 -0800470 deviceEvents.add(devEvt);
471 }
472 for (DeviceEvent devEvt : deviceEvents) {
Yuta HIGUCHI8d762e92014-02-12 14:10:25 -0800473 // calling Discovery API to wipe from DB, etc.
474 removeDeviceEvent(devEvt);
475 }
476
477 return true;
Jonathan Hart22eb9882014-02-11 15:52:59 -0800478 }
Yuta HIGUCHIcd922f42014-02-11 18:59:11 -0800479
Yuta HIGUCHId02e9282014-02-12 09:24:41 -0800480 private boolean prepareForRemoveLinkEvent(LinkEvent linkEvt) {
Yuta HIGUCHI8d762e92014-02-12 14:10:25 -0800481 // Src/Dst Port must exist
Yuta HIGUCHId5315c42014-02-18 09:35:48 -0800482 Port srcPort = getPort(linkEvt.getSrc().dpid, linkEvt.getSrc().number);
483 Port dstPort = getPort(linkEvt.getDst().dpid, linkEvt.getDst().number);
Yuta HIGUCHI8d762e92014-02-12 14:10:25 -0800484 if ( srcPort == null || dstPort == null ) {
Jonathan Hart0a4846e2014-02-18 11:03:40 -0800485 log.warn("Dropping remove link event because port doesn't exist {}", linkEvt);
Yuta HIGUCHI8d762e92014-02-12 14:10:25 -0800486 return false;
487 }
488
Yuta HIGUCHI125c7df2014-02-14 12:28:10 -0800489 Link link = srcPort.getOutgoingLink();
490
491 // Link is already gone, or different Link exist in memory
492 // XXX Check if we should reject or just accept these cases.
493 // it should be harmless to remove the Link on event from DB anyways
494 if (link == null ||
495 !link.getDestinationPortNumber().equals(linkEvt.getDst().number)
496 || !link.getDestinationSwitchDpid().equals(linkEvt.getDst().dpid)) {
Jonathan Hart0a4846e2014-02-18 11:03:40 -0800497 log.warn("Dropping remove link event because link doesn't exist: {}", linkEvt);
Yuta HIGUCHI125c7df2014-02-14 12:28:10 -0800498 return false;
499 }
Yuta HIGUCHI8d762e92014-02-12 14:10:25 -0800500 // Prep: None
501 return true;
Jonathan Hart22eb9882014-02-11 15:52:59 -0800502 }
Yuta HIGUCHIcd922f42014-02-11 18:59:11 -0800503
Yuta HIGUCHI8d762e92014-02-12 14:10:25 -0800504 /**
505 *
506 * @param deviceEvt Event will be modified to remove inapplicable attachemntPoints/ipAddress
507 * @return false if this event should be dropped.
508 */
Yuta HIGUCHId02e9282014-02-12 09:24:41 -0800509 private boolean prepareForAddDeviceEvent(DeviceEvent deviceEvt) {
Yuta HIGUCHI8d762e92014-02-12 14:10:25 -0800510 boolean preconditionBroken = false;
511 ArrayList<PortEvent.SwitchPort> failedSwitchPort = new ArrayList<>();
512 for ( PortEvent.SwitchPort swp : deviceEvt.getAttachmentPoints() ) {
Yuta HIGUCHId02e9282014-02-12 09:24:41 -0800513 // Attached Ports must exist
Yuta HIGUCHId5315c42014-02-18 09:35:48 -0800514 Port port = getPort(swp.dpid, swp.number);
Yuta HIGUCHI8d762e92014-02-12 14:10:25 -0800515 if ( port == null ) {
516 preconditionBroken = true;
517 failedSwitchPort.add(swp);
518 continue;
519 }
Yuta HIGUCHId02e9282014-02-12 09:24:41 -0800520 // Attached Ports must not have Link
Yuta HIGUCHI8d762e92014-02-12 14:10:25 -0800521 if ( port.getOutgoingLink() != null || port.getIncomingLink() != null ) {
522 preconditionBroken = true;
523 failedSwitchPort.add(swp);
524 continue;
525 }
526 }
Yuta HIGUCHId02e9282014-02-12 09:24:41 -0800527
Yuta HIGUCHI8d762e92014-02-12 14:10:25 -0800528 // Rewriting event to exclude failed attachmentPoint
529 // XXX Assumption behind this is that inapplicable device event should
530 // be dropped, not deferred. If we decide to defer Device event,
531 // rewriting can become a problem
532 List<SwitchPort> attachmentPoints = deviceEvt.getAttachmentPoints();
533 attachmentPoints.removeAll(failedSwitchPort);
534 deviceEvt.setAttachmentPoints(attachmentPoints);
535
536 if ( deviceEvt.getAttachmentPoints().isEmpty() && deviceEvt.getIpAddresses().isEmpty() ) {
Yuta HIGUCHI125c7df2014-02-14 12:28:10 -0800537 // return false to represent: Nothing left to do for this event. Caller should drop event
Yuta HIGUCHI8d762e92014-02-12 14:10:25 -0800538 return false;
539 }
540
541 // Should we return false to tell caller that the event was trimmed?
542 // if ( preconditionBroken ) {
543 // return false;
544 // }
545
546 return true;
Jonathan Hart22eb9882014-02-11 15:52:59 -0800547 }
Yuta HIGUCHIcd922f42014-02-11 18:59:11 -0800548
Yuta HIGUCHId02e9282014-02-12 09:24:41 -0800549 private boolean prepareForRemoveDeviceEvent(DeviceEvent deviceEvt) {
Yuta HIGUCHId02e9282014-02-12 09:24:41 -0800550 // No show stopping precondition?
551 // Prep: none
Jonathan Hart22eb9882014-02-11 15:52:59 -0800552 return true;
553 }
Yuta HIGUCHI928fa682014-02-11 19:07:57 -0800554
Yuta HIGUCHI76df2472014-02-12 22:36:51 -0800555 /* ******************************
556 * NetworkGraphReplicationInterface methods
557 * ******************************/
558
Yuta HIGUCHI928fa682014-02-11 19:07:57 -0800559 @Override
560 public void putSwitchReplicationEvent(SwitchEvent switchEvent) {
Yuta HIGUCHI9fc10ac2014-02-12 17:18:57 -0800561 if (prepareForAddSwitchEvent(switchEvent)) {
562 putSwitch(switchEvent);
563 }
564 // TODO handle invariant violation
Yuta HIGUCHIa536e762014-02-17 21:47:28 -0800565 // trigger instance local topology event handler
566 dispatchPutSwitchEvent(switchEvent);
Yuta HIGUCHI928fa682014-02-11 19:07:57 -0800567 }
568
569 @Override
570 public void removeSwitchReplicationEvent(SwitchEvent switchEvent) {
Yuta HIGUCHI9fc10ac2014-02-12 17:18:57 -0800571 if (prepareForRemoveSwitchEvent(switchEvent)) {
572 removeSwitch(switchEvent);
573 }
Yuta HIGUCHI125c7df2014-02-14 12:28:10 -0800574 // TODO handle invariant violation
Yuta HIGUCHIa536e762014-02-17 21:47:28 -0800575 // trigger instance local topology event handler
576 dispatchRemoveSwitchEvent(switchEvent);
Yuta HIGUCHI928fa682014-02-11 19:07:57 -0800577 }
578
579 @Override
580 public void putPortReplicationEvent(PortEvent portEvent) {
Yuta HIGUCHI9fc10ac2014-02-12 17:18:57 -0800581 if (prepareForAddPortEvent(portEvent)) {
582 putPort(portEvent);
583 }
Yuta HIGUCHI125c7df2014-02-14 12:28:10 -0800584 // TODO handle invariant violation
Yuta HIGUCHIa536e762014-02-17 21:47:28 -0800585 // trigger instance local topology event handler
586 dispatchPutPortEvent(portEvent);
Yuta HIGUCHI928fa682014-02-11 19:07:57 -0800587 }
588
589 @Override
590 public void removePortReplicationEvent(PortEvent portEvent) {
Yuta HIGUCHI9fc10ac2014-02-12 17:18:57 -0800591 if (prepareForRemovePortEvent(portEvent)) {
592 removePort(portEvent);
593 }
Yuta HIGUCHI125c7df2014-02-14 12:28:10 -0800594 // TODO handle invariant violation
Yuta HIGUCHIa536e762014-02-17 21:47:28 -0800595 // trigger instance local topology event handler
596 dispatchRemovePortEvent(portEvent);
Yuta HIGUCHI928fa682014-02-11 19:07:57 -0800597 }
598
599 @Override
600 public void putLinkReplicationEvent(LinkEvent linkEvent) {
Yuta HIGUCHI9fc10ac2014-02-12 17:18:57 -0800601 if (prepareForAddLinkEvent(linkEvent)) {
602 putLink(linkEvent);
603 }
Yuta HIGUCHI125c7df2014-02-14 12:28:10 -0800604 // TODO handle invariant violation
Yuta HIGUCHIa536e762014-02-17 21:47:28 -0800605 // trigger instance local topology event handler
606 dispatchPutLinkEvent(linkEvent);
Yuta HIGUCHI928fa682014-02-11 19:07:57 -0800607 }
608
609 @Override
610 public void removeLinkReplicationEvent(LinkEvent linkEvent) {
Yuta HIGUCHI9fc10ac2014-02-12 17:18:57 -0800611 if (prepareForRemoveLinkEvent(linkEvent)) {
612 removeLink(linkEvent);
613 }
Yuta HIGUCHI125c7df2014-02-14 12:28:10 -0800614 // TODO handle invariant violation
Yuta HIGUCHIa536e762014-02-17 21:47:28 -0800615 // trigger instance local topology event handler
616 dispatchRemoveLinkEvent(linkEvent);
Yuta HIGUCHI928fa682014-02-11 19:07:57 -0800617 }
618
619 @Override
620 public void putDeviceReplicationEvent(DeviceEvent deviceEvent) {
Yuta HIGUCHI9fc10ac2014-02-12 17:18:57 -0800621 if (prepareForAddDeviceEvent(deviceEvent)) {
622 putDevice(deviceEvent);
623 }
Yuta HIGUCHI125c7df2014-02-14 12:28:10 -0800624 // TODO handle invariant violation
Yuta HIGUCHIa536e762014-02-17 21:47:28 -0800625 // trigger instance local topology event handler
626 dispatchPutDeviceEvent(deviceEvent);
Yuta HIGUCHI928fa682014-02-11 19:07:57 -0800627 }
628
629 @Override
630 public void removeDeviceReplicationEvent(DeviceEvent deviceEvent) {
Yuta HIGUCHI9fc10ac2014-02-12 17:18:57 -0800631 if (prepareForRemoveDeviceEvent(deviceEvent)) {
632 removeDevice(deviceEvent);
633 }
Yuta HIGUCHI125c7df2014-02-14 12:28:10 -0800634 // TODO handle invariant violation
Yuta HIGUCHIa536e762014-02-17 21:47:28 -0800635 // trigger instance local topology event handler
636 dispatchRemoveDeviceEvent(deviceEvent);
Yuta HIGUCHI928fa682014-02-11 19:07:57 -0800637 }
Yuta HIGUCHI76df2472014-02-12 22:36:51 -0800638
639 /* ************************************************
640 * Internal In-memory object mutation methods.
641 * ************************************************/
642
643 void putSwitch(SwitchEvent swEvt) {
644 if (swEvt == null) {
645 throw new IllegalArgumentException("Switch cannot be null");
646 }
647
648 Switch sw = switches.get(swEvt.getDpid());
649
650 if (sw == null) {
651 sw = new SwitchImpl(this, swEvt.getDpid());
652 Switch existing = switches.putIfAbsent(swEvt.getDpid(), sw);
653 if (existing != null) {
654 log.warn(
655 "Concurrent putSwitch not expected. Continuing updating {}",
656 existing);
657 sw = existing;
658 }
659 }
660
661 // Update when more attributes are added to Event object
662 // no attribute to update for now
663
664 // TODO handle child Port event properly for performance
665 for (PortEvent portEvt : swEvt.getPorts() ) {
666 putPort(portEvt);
667 }
668
669 }
670
671 void removeSwitch(SwitchEvent swEvt) {
672 if (swEvt == null) {
673 throw new IllegalArgumentException("Switch cannot be null");
674 }
675
676 // TODO handle child Port event properly for performance
677 for (PortEvent portEvt : swEvt.getPorts() ) {
678 removePort(portEvt);
679 }
680
681 Switch sw = switches.get(swEvt.getDpid());
682
683 if (sw == null) {
684 log.warn("Switch {} already removed, ignoring", swEvt);
685 return;
686 }
687
Yuta HIGUCHI317bf542014-02-17 11:02:39 -0800688 // remove all ports if there still exist
689 ArrayList<PortEvent> portsToRemove = new ArrayList<>();
690 for (Port port : sw.getPorts()) {
Yuta HIGUCHI76df2472014-02-12 22:36:51 -0800691 log.warn(
Yuta HIGUCHI317bf542014-02-17 11:02:39 -0800692 "Port {} on Switch {} should be removed prior to removing Switch. Removing Port now",
693 port, swEvt);
694 PortEvent portEvt = new PortEvent(port.getDpid(), port.getNumber());
695 portsToRemove.add(portEvt);
Yuta HIGUCHI76df2472014-02-12 22:36:51 -0800696 }
Yuta HIGUCHI0a4bd192014-02-17 13:52:34 -0800697 for (PortEvent portEvt : portsToRemove) {
Yuta HIGUCHI317bf542014-02-17 11:02:39 -0800698 // XXX calling removePortEvent() may trigger duplicate event, once at prepare phase, second time here
699 // If event can be squashed, ignored etc. at receiver side it shouldn't be a problem, but if not
700 // need to re-visit this issue.
701
702 // Note: removePortEvent() implies removal of attached Device, etc.
703 // if we decide not to call removePortEvent(), Device needs to be handled properly
704 removePortEvent(portEvt);
Yuta HIGUCHI76df2472014-02-12 22:36:51 -0800705 }
706
707 boolean removed = switches.remove(swEvt.getDpid(), sw);
708 if (removed) {
709 log.warn(
710 "Switch instance was replaced concurrently while removing {}. Something is not right.",
711 sw);
712 }
713 }
714
715 void putPort(PortEvent portEvt) {
716 if (portEvt == null) {
717 throw new IllegalArgumentException("Port cannot be null");
718 }
719 Switch sw = switches.get(portEvt.getDpid());
720 if (sw == null) {
721 throw new BrokenInvariantException(String.format(
722 "Switch with dpid %s did not exist.",
723 new Dpid(portEvt.getDpid())));
724 }
725 Port p = sw.getPort(portEvt.getNumber());
726 PortImpl port = null;
727 if (p != null) {
728 port = getPortImpl(p);
729 }
730
731 if (port == null) {
732 port = new PortImpl(this, sw, portEvt.getNumber());
733 }
734
735 // TODO update attributes
736
737 SwitchImpl s = getSwitchImpl(sw);
738 s.addPort(port);
739 }
740
741 void removePort(PortEvent portEvt) {
742 if (portEvt == null) {
743 throw new IllegalArgumentException("Port cannot be null");
744 }
745
746 Switch sw = switches.get(portEvt.getDpid());
747 if (sw == null) {
748 log.warn("Parent Switch for Port {} already removed, ignoring", portEvt);
749 return;
750 }
751
752 Port p = sw.getPort(portEvt.getNumber());
753 if (p == null) {
754 log.warn("Port {} already removed, ignoring", portEvt);
755 return;
756 }
757
Yuta HIGUCHIde040642014-02-17 11:03:39 -0800758 // Remove Link and Device Attachment
759 for (Device device : p.getDevices()) {
760 log.debug("Removing Device {} on Port {}", device, portEvt);
761 DeviceEvent devEvt = new DeviceEvent(device.getMacAddress());
762 devEvt.addAttachmentPoint(new SwitchPort(p.getSwitch().getDpid(), p.getNumber()));
Yuta HIGUCHI76df2472014-02-12 22:36:51 -0800763
Yuta HIGUCHIde040642014-02-17 11:03:39 -0800764 // XXX calling removeDeviceEvent() may trigger duplicate event, once at prepare phase, second time here
765 // If event can be squashed, ignored etc. at receiver side it shouldn't be a problem, but if not
766 // need to re-visit
767
768 // calling Discovery API to wipe from DB, etc.
769 removeDeviceEvent(devEvt);
Yuta HIGUCHI76df2472014-02-12 22:36:51 -0800770 }
Yuta HIGUCHIde040642014-02-17 11:03:39 -0800771 Set<Link> links = new HashSet<>();
772 links.add(p.getOutgoingLink());
773 links.add(p.getIncomingLink());
774 ArrayList<LinkEvent> linksToRemove = new ArrayList<>();
775 for (Link link : links) {
776 if (link == null) {
777 continue;
778 }
779 log.debug("Removing Link {} on Port {}", link, portEvt);
780 LinkEvent linkEvent = new LinkEvent(link.getSourceSwitchDpid(), link.getSourcePortNumber(), link.getDestinationSwitchDpid(), link.getDestinationPortNumber());
781 linksToRemove.add(linkEvent);
Yuta HIGUCHI76df2472014-02-12 22:36:51 -0800782 }
Yuta HIGUCHIde040642014-02-17 11:03:39 -0800783 for (LinkEvent linkEvent : linksToRemove) {
784 // XXX calling removeLinkEvent() may trigger duplicate event, once at prepare phase, second time here
785 // If event can be squashed, ignored etc. at receiver side it shouldn't be a problem, but if not
786 // need to re-visit
787
788 // calling Discovery API to wipe from DB, etc.
789 removeLinkEvent(linkEvent);
Yuta HIGUCHI76df2472014-02-12 22:36:51 -0800790 }
791
792 // remove Port from Switch
793 SwitchImpl s = getSwitchImpl(sw);
794 s.removePort(p);
795 }
796
797 void putLink(LinkEvent linkEvt) {
798 if (linkEvt == null) {
799 throw new IllegalArgumentException("Link cannot be null");
800 }
801
Yuta HIGUCHId5315c42014-02-18 09:35:48 -0800802 Port srcPort = getPort(linkEvt.getSrc().dpid, linkEvt.getSrc().number);
Yuta HIGUCHI76df2472014-02-12 22:36:51 -0800803 if (srcPort == null) {
804 throw new BrokenInvariantException(
805 String.format(
806 "Src Port %s of a Link did not exist.",
807 linkEvt.getSrc() ));
808 }
809
Yuta HIGUCHId5315c42014-02-18 09:35:48 -0800810 Port dstPort = getPort(linkEvt.getDst().dpid, linkEvt.getDst().number);
Yuta HIGUCHI76df2472014-02-12 22:36:51 -0800811 if (dstPort == null) {
812 throw new BrokenInvariantException(
813 String.format(
814 "Dst Port %s of a Link did not exist.",
815 linkEvt.getDst() ));
816 }
817
818 // getting Link instance from destination port incoming Link
819 Link l = dstPort.getIncomingLink();
820 LinkImpl link = null;
821 assert( l == srcPort.getOutgoingLink() );
822 if (l != null) {
823 link = getLinkImpl(l);
824 }
825
826 if (link == null) {
827 link = new LinkImpl(this, srcPort, dstPort);
828 }
829
830
831 PortImpl dstPortMem = getPortImpl(dstPort);
832 PortImpl srcPortMem = getPortImpl(srcPort);
833
834 // Add Link first to avoid further Device addition
835
836 // add Link to Port
837 dstPortMem.setIncomingLink(link);
838 srcPortMem.setOutgoingLink(link);
839
840 // remove Device Pointing to Port if any
841 for(Device d : dstPortMem.getDevices() ) {
842 log.error("Device {} on Port {} should have been removed prior to adding Link {}", d, dstPort, linkEvt);
843 DeviceImpl dev = getDeviceImpl(d);
844 dev.removeAttachmentPoint(dstPort);
Yuta HIGUCHI407261a2014-02-13 16:34:06 -0800845 // This implies that change is made to Device Object.
846 // sending Device attachment point removed event
847 DeviceEvent rmEvent = new DeviceEvent(d.getMacAddress());
848 rmEvent.addAttachmentPoint(new SwitchPort(dstPort.getDpid(), dstPort.getNumber()));
849 removeDeviceEvent(rmEvent);
Yuta HIGUCHI76df2472014-02-12 22:36:51 -0800850 }
851 dstPortMem.removeAllDevice();
852 for(Device d : srcPortMem.getDevices() ) {
853 log.error("Device {} on Port {} should have been removed prior to adding Link {}", d, srcPort, linkEvt);
854 DeviceImpl dev = getDeviceImpl(d);
855 dev.removeAttachmentPoint(srcPort);
Yuta HIGUCHI407261a2014-02-13 16:34:06 -0800856 // This implies that change is made to Device Object.
857 // sending Device attachment point removed event
858 DeviceEvent rmEvent = new DeviceEvent(d.getMacAddress());
859 rmEvent.addAttachmentPoint(new SwitchPort(dstPort.getDpid(), dstPort.getNumber()));
860 removeDeviceEvent(rmEvent);
Yuta HIGUCHI76df2472014-02-12 22:36:51 -0800861 }
862 srcPortMem.removeAllDevice();
863
864 }
865
866 void removeLink(LinkEvent linkEvt) {
867 if (linkEvt == null) {
868 throw new IllegalArgumentException("Link cannot be null");
869 }
870
Yuta HIGUCHId5315c42014-02-18 09:35:48 -0800871 Port srcPort = getPort(linkEvt.getSrc().dpid, linkEvt.getSrc().number);
Yuta HIGUCHI76df2472014-02-12 22:36:51 -0800872 if (srcPort == null) {
873 log.warn("Src Port for Link {} already removed, ignoring", linkEvt);
874 return;
875 }
876
Yuta HIGUCHId5315c42014-02-18 09:35:48 -0800877 Port dstPort = getPort(linkEvt.getDst().dpid, linkEvt.getDst().number);
Yuta HIGUCHI76df2472014-02-12 22:36:51 -0800878 if (dstPort == null) {
879 log.warn("Dst Port for Link {} already removed, ignoring", linkEvt);
880 return;
881 }
882
883 Link l = dstPort.getIncomingLink();
884 if ( l == null ) {
885 log.warn("Link {} already removed on destination Port", linkEvt);
886 }
887 l = srcPort.getOutgoingLink();
888 if ( l == null ) {
889 log.warn("Link {} already removed on src Port", linkEvt);
890 }
891
892 getPortImpl(dstPort).setIncomingLink(null);
893 getPortImpl(srcPort).setOutgoingLink(null);
894 }
895
896 // XXX Need to rework Device related
897 void putDevice(DeviceEvent deviceEvt) {
898 if (deviceEvt == null) {
899 throw new IllegalArgumentException("Device cannot be null");
900 }
901
902 Device device = getDeviceByMac(deviceEvt.getMac());
903 if ( device == null ) {
904 device = new DeviceImpl(this, deviceEvt.getMac());
905 Device existing = mac2Device.putIfAbsent(deviceEvt.getMac(), device);
906 if (existing != null) {
907 log.warn(
908 "Concurrent putDevice seems to be in action. Continuing updating {}",
909 existing);
910 device = existing;
911 }
912 }
913 DeviceImpl memDevice = getDeviceImpl(device);
914
915 // for each attachment point
916 for (SwitchPort swp : deviceEvt.getAttachmentPoints() ) {
Yuta HIGUCHI76df2472014-02-12 22:36:51 -0800917 // Attached Ports must exist
Yuta HIGUCHId5315c42014-02-18 09:35:48 -0800918 Port port = getPort(swp.dpid, swp.number);
Yuta HIGUCHI76df2472014-02-12 22:36:51 -0800919 if ( port == null ) {
Yuta HIGUCHI25719052014-02-13 14:42:06 -0800920 log.warn("Port for the attachment point {} did not exist. skipping mutation", swp);
Yuta HIGUCHI76df2472014-02-12 22:36:51 -0800921 continue;
922 }
923 // Attached Ports must not have Link
924 if ( port.getOutgoingLink() != null || port.getIncomingLink() != null ) {
925 log.warn("Link (Out:{},In:{}) exist on the attachment point, skipping mutation.", port.getOutgoingLink(), port.getIncomingLink());
926 continue;
927 }
928
929 // finally add Device <-> Port on In-memory structure
930 PortImpl memPort = getPortImpl(port);
931 memPort.addDevice(device);
932 memDevice.addAttachmentPoint(port);
933 }
934
935 // for each IP address
936 for( InetAddress ipAddr : deviceEvt.getIpAddresses() ) {
937 // Add Device -> IP
938 memDevice.addIpAddress(ipAddr);
939
940 // Add IP -> Set<Device>
941 boolean updated = false;
942 do {
943 Set<Device> devices = this.addr2Device.get(ipAddr);
944 if ( devices == null ) {
945 devices = new HashSet<>();
946 Set<Device> existing = this.addr2Device.putIfAbsent(ipAddr, devices);
947 if ( existing == null ) {
948 // success
949 updated = true;
950 }
951 } else {
952 Set<Device> updateDevices = new HashSet<>(devices);
953 updateDevices.add(device);
954 updated = this.addr2Device.replace(ipAddr, devices, updateDevices);
955 }
956 if (!updated) {
957 log.debug("Collision detected, updating IP to Device mapping retrying.");
958 }
959 } while( !updated );
960 }
961 }
962
963 void removeDevice(DeviceEvent deviceEvt) {
964 if (deviceEvt == null) {
965 throw new IllegalArgumentException("Device cannot be null");
966 }
967
968 Device device = getDeviceByMac(deviceEvt.getMac());
969 if ( device == null ) {
970 log.warn("Device {} already removed, ignoring", deviceEvt);
971 return;
972 }
973 DeviceImpl memDevice = getDeviceImpl(device);
974
975 // for each attachment point
976 for (SwitchPort swp : deviceEvt.getAttachmentPoints() ) {
Yuta HIGUCHI76df2472014-02-12 22:36:51 -0800977 // Attached Ports must exist
Yuta HIGUCHId5315c42014-02-18 09:35:48 -0800978 Port port = getPort(swp.dpid, swp.number);
Yuta HIGUCHI76df2472014-02-12 22:36:51 -0800979 if ( port == null ) {
Yuta HIGUCHI25719052014-02-13 14:42:06 -0800980 log.warn("Port for the attachment point {} did not exist. skipping attachment point mutation", swp);
Yuta HIGUCHI76df2472014-02-12 22:36:51 -0800981 continue;
982 }
983
984 // finally remove Device <-> Port on In-memory structure
985 PortImpl memPort = getPortImpl(port);
986 memPort.removeDevice(device);
987 memDevice.removeAttachmentPoint(port);
988 }
989
990 // for each IP address
991 for( InetAddress ipAddr : deviceEvt.getIpAddresses() ) {
992 // Remove Device -> IP
993 memDevice.removeIpAddress(ipAddr);
994
995 // Remove IP -> Set<Device>
996 boolean updated = false;
997 do {
998 Set<Device> devices = this.addr2Device.get(ipAddr);
999 if ( devices == null ) {
1000 // already empty set, nothing to do
1001 updated = true;
1002 } else {
1003 Set<Device> updateDevices = new HashSet<>(devices);
1004 updateDevices.remove(device);
1005 updated = this.addr2Device.replace(ipAddr, devices, updateDevices);
1006 }
1007 if (!updated) {
1008 log.debug("Collision detected, updating IP to Device mapping retrying.");
1009 }
1010 } while( !updated );
1011 }
1012 }
1013
Yuta HIGUCHIa536e762014-02-17 21:47:28 -08001014 private void dispatchPutSwitchEvent(SwitchEvent switchEvent) {
1015 for (INetworkGraphListener listener : this.networkGraphListeners) {
1016 // TODO Should copy before handing them over to listener
1017 listener.putSwitchEvent(switchEvent);
1018 }
1019 }
1020
1021 private void dispatchRemoveSwitchEvent(SwitchEvent switchEvent) {
1022 for (INetworkGraphListener listener : this.networkGraphListeners) {
1023 // TODO Should copy before handing them over to listener
1024 listener.removeSwitchEvent(switchEvent);
1025 }
1026 }
1027
1028 private void dispatchPutPortEvent(PortEvent portEvent) {
1029 for (INetworkGraphListener listener : this.networkGraphListeners) {
1030 // TODO Should copy before handing them over to listener
1031 listener.putPortEvent(portEvent);
1032 }
1033 }
1034
1035 private void dispatchRemovePortEvent(PortEvent portEvent) {
1036 for (INetworkGraphListener listener : this.networkGraphListeners) {
1037 // TODO Should copy before handing them over to listener
1038 listener.removePortEvent(portEvent);
1039 }
1040 }
1041
1042 private void dispatchPutLinkEvent(LinkEvent linkEvent) {
1043 for (INetworkGraphListener listener : this.networkGraphListeners) {
1044 // TODO Should copy before handing them over to listener
1045 listener.putLinkEvent(linkEvent);
1046 }
1047 }
1048
1049 private void dispatchRemoveLinkEvent(LinkEvent linkEvent) {
1050 for (INetworkGraphListener listener : this.networkGraphListeners) {
1051 // TODO Should copy before handing them over to listener
1052 listener.removeLinkEvent(linkEvent);
1053 }
1054 }
1055
1056 private void dispatchPutDeviceEvent(DeviceEvent deviceEvent) {
1057 for (INetworkGraphListener listener : this.networkGraphListeners) {
1058 // TODO Should copy before handing them over to listener
1059 listener.putDeviceEvent(deviceEvent);;
1060 }
1061 }
1062
1063 private void dispatchRemoveDeviceEvent(DeviceEvent deviceEvent) {
1064 for (INetworkGraphListener listener : this.networkGraphListeners) {
1065 // TODO Should copy before handing them over to listener
1066 listener.removeDeviceEvent(deviceEvent);
1067 }
1068 }
1069
Yuta HIGUCHId5315c42014-02-18 09:35:48 -08001070 // we might want to include this in NetworkGraph interface
1071 private Port getPort(Long dpid, Long number) {
1072 Switch sw = getSwitch(dpid);
1073 if (sw != null) {
1074 return sw.getPort(number);
1075 }
1076 return null;
1077 }
1078
Yuta HIGUCHI76df2472014-02-12 22:36:51 -08001079 private SwitchImpl getSwitchImpl(Switch sw) {
1080 if (sw instanceof SwitchImpl) {
1081 return (SwitchImpl) sw;
1082 }
1083 throw new ClassCastException("SwitchImpl expected, but found: " + sw);
1084 }
1085
1086 private PortImpl getPortImpl(Port p) {
1087 if (p instanceof PortImpl) {
1088 return (PortImpl) p;
1089 }
1090 throw new ClassCastException("PortImpl expected, but found: " + p);
1091 }
1092
1093 private LinkImpl getLinkImpl(Link l) {
1094 if (l instanceof LinkImpl) {
1095 return (LinkImpl) l;
1096 }
1097 throw new ClassCastException("LinkImpl expected, but found: " + l);
1098 }
1099
1100 private DeviceImpl getDeviceImpl(Device d) {
1101 if (d instanceof DeviceImpl) {
1102 return (DeviceImpl) d;
1103 }
1104 throw new ClassCastException("DeviceImpl expected, but found: " + d);
1105 }
1106
1107 @Deprecated
1108 public void loadWholeTopologyFromDB() {
Yuta HIGUCHI0a4bd192014-02-17 13:52:34 -08001109 // XXX May need to clear whole topology first, depending on
1110 // how we initially subscribe to replication events
Yuta HIGUCHI76df2472014-02-12 22:36:51 -08001111
1112 for (RCSwitch sw : RCSwitch.getAllSwitches()) {
1113 if ( sw.getStatus() != RCSwitch.STATUS.ACTIVE ) {
1114 continue;
1115 }
1116 putSwitchReplicationEvent(new SwitchEvent(sw.getDpid()));
1117 }
1118
1119 for (RCPort p : RCPort.getAllPorts()) {
1120 if (p.getStatus() != RCPort.STATUS.ACTIVE) {
1121 continue;
1122 }
1123 putPortReplicationEvent(new PortEvent(p.getDpid(), p.getNumber() ));
1124 }
1125
1126 // TODO Is Device going to be in DB? If so, read from DB.
1127 // for (RCDevice d : RCDevice.getAllDevices()) {
1128 // DeviceEvent devEvent = new DeviceEvent( MACAddress.valueOf(d.getMac()) );
1129 // for (byte[] portId : d.getAllPortIds() ) {
1130 // devEvent.addAttachmentPoint( new SwitchPort( RCPort.getDpidFromKey(portId), RCPort.getNumberFromKey(portId) ));
1131 // }
1132 // }
1133
1134 for (RCLink l : RCLink.getAllLinks()) {
Yuta HIGUCHIdab94692014-02-18 09:12:02 -08001135 // check if src/dst switch/port exist before triggering event
Yuta HIGUCHId5315c42014-02-18 09:35:48 -08001136 Port srcPort = getPort(l.getSrc().dpid, l.getSrc().number);
1137 Port dstPort = getPort(l.getDst().dpid, l.getDst().number);
Yuta HIGUCHIdab94692014-02-18 09:12:02 -08001138 if ( srcPort == null || dstPort == null ) {
1139 continue;
1140 }
Yuta HIGUCHI76df2472014-02-12 22:36:51 -08001141 putLinkReplicationEvent( new LinkEvent(l.getSrc().dpid, l.getSrc().number, l.getDst().dpid, l.getDst().number));
1142 }
1143 }
Jonathan Hart062a2e82014-02-03 09:41:57 -08001144}