blob: ae7163330b459c3d4fd86b3b7eb19a176dfc2b38 [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 */
Yuta HIGUCHI928fa682014-02-11 19:07:57 -080042public class NetworkGraphImpl extends AbstractNetworkGraph implements
43 NetworkGraphDiscoveryInterface, NetworkGraphReplicationInterface {
Jonathan Hart062a2e82014-02-03 09:41:57 -080044
Yuta HIGUCHI80829d12014-02-05 20:16:56 -080045 private static final Logger log = LoggerFactory
46 .getLogger(NetworkGraphImpl.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
Yuta HIGUCHIa536e762014-02-17 21:47:28 -080056 public NetworkGraphImpl(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
101 this.setName("NetworkGraphImpl.EventHandler " + this.getId());
102 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 HIGUCHI0a4bd192014-02-17 13:52:34 -0800298 // TODO may need to distinguish internal event, which checks
299 // ownership of dst-dpid of this link, and only write to DB
300 // if it is owner of the dpid
Yuta HIGUCHId02e9282014-02-12 09:24:41 -0800301 if (prepareForRemoveLinkEvent(linkEvent)) {
Jonathan Hart22eb9882014-02-11 15:52:59 -0800302 datastore.removeLink(linkEvent);
303 removeLink(linkEvent);
Pavlin Radoslavov721a2e02014-02-14 23:40:14 -0800304 // Send out notification
305 eventChannel.removeEntry(linkEvent.getID());
Jonathan Hart22eb9882014-02-11 15:52:59 -0800306 }
307 // TODO handle invariant violation
308 }
309
310 @Override
Yuta HIGUCHI586d33e2014-02-13 17:05:08 -0800311 public void putDeviceEvent(DeviceEvent deviceEvent) {
312 if (prepareForAddDeviceEvent(deviceEvent)) {
313// datastore.addDevice(deviceEvent);
Yuta HIGUCHId457c052014-02-14 18:33:04 -0800314// putDevice(deviceEvent);
Pavlin Radoslavov721a2e02014-02-14 23:40:14 -0800315 // Send out notification
316 TopologyEvent topologyEvent =
Yuta HIGUCHI170229f2014-02-17 15:47:54 -0800317 new TopologyEvent(deviceEvent, registryService.getControllerId());
Pavlin Radoslavov721a2e02014-02-14 23:40:14 -0800318 eventChannel.addEntry(topologyEvent.getID(),
319 topologyEvent);
Yuta HIGUCHI586d33e2014-02-13 17:05:08 -0800320 }
321 // TODO handle invariant violation
322 // XXX if prepareFor~ method returned false, event should be dropped
Jonathan Hart22eb9882014-02-11 15:52:59 -0800323 }
324
325 @Override
326 public void removeDeviceEvent(DeviceEvent deviceEvent) {
Yuta HIGUCHI586d33e2014-02-13 17:05:08 -0800327 if (prepareForRemoveDeviceEvent(deviceEvent)) {
328// datastore.removeDevice(deviceEvent);
Yuta HIGUCHId457c052014-02-14 18:33:04 -0800329// removeDevice(deviceEvent);
Pavlin Radoslavov721a2e02014-02-14 23:40:14 -0800330 // Send out notification
331 eventChannel.removeEntry(deviceEvent.getID());
Yuta HIGUCHI586d33e2014-02-13 17:05:08 -0800332 }
333 // TODO handle invariant violation
334 // XXX if prepareFor~ method returned false, event should be dropped
Jonathan Hart22eb9882014-02-11 15:52:59 -0800335 }
Yuta HIGUCHIcd922f42014-02-11 18:59:11 -0800336
Jonathan Hart22eb9882014-02-11 15:52:59 -0800337 /* *****************
Yuta HIGUCHId02e9282014-02-12 09:24:41 -0800338 * Internal methods to maintain invariants of the network graph
Jonathan Hart22eb9882014-02-11 15:52:59 -0800339 * *****************/
Yuta HIGUCHIcd922f42014-02-11 18:59:11 -0800340
Yuta HIGUCHId02e9282014-02-12 09:24:41 -0800341 /**
342 *
343 * @param swEvt
344 * @return true if ready to accept event.
345 */
346 private boolean prepareForAddSwitchEvent(SwitchEvent swEvt) {
Yuta HIGUCHI76df2472014-02-12 22:36:51 -0800347 // No show stopping precondition
Yuta HIGUCHI8d762e92014-02-12 14:10:25 -0800348 // Prep: remove(deactivate) Ports on Switch, which is not on event
349 removePortsNotOnEvent(swEvt);
350 return true;
Jonathan Hart22eb9882014-02-11 15:52:59 -0800351 }
Yuta HIGUCHIcd922f42014-02-11 18:59:11 -0800352
Yuta HIGUCHId02e9282014-02-12 09:24:41 -0800353 private boolean prepareForRemoveSwitchEvent(SwitchEvent swEvt) {
Yuta HIGUCHI76df2472014-02-12 22:36:51 -0800354 // No show stopping precondition
Yuta HIGUCHI8d762e92014-02-12 14:10:25 -0800355 // Prep: remove(deactivate) Ports on Switch, which is not on event
356 // XXX may be remove switch should imply wipe all ports
357 removePortsNotOnEvent(swEvt);
358 return true;
359 }
Yuta HIGUCHId02e9282014-02-12 09:24:41 -0800360
Yuta HIGUCHI8d762e92014-02-12 14:10:25 -0800361 private void removePortsNotOnEvent(SwitchEvent swEvt) {
362 Switch sw = switches.get( swEvt.getDpid() );
363 if ( sw != null ) {
364 Set<Long> port_noOnEvent = new HashSet<>();
365 for( PortEvent portEvent : swEvt.getPorts()) {
366 port_noOnEvent.add(portEvent.getNumber());
367 }
368 // Existing ports not on event should be removed.
369 // TODO Should batch eventually for performance?
Jonathan Hart480c5572014-02-14 18:28:16 -0800370 List<Port> portsToRemove = new ArrayList<Port>();
Yuta HIGUCHI8d762e92014-02-12 14:10:25 -0800371 for( Port p : sw.getPorts() ) {
372 if ( !port_noOnEvent.contains(p.getNumber()) ) {
Jonathan Hart480c5572014-02-14 18:28:16 -0800373 //PortEvent rmEvent = new PortEvent(p.getSwitch().getDpid(), p.getNumber());
374 // calling Discovery removePort() API to wipe from DB, etc.
375 //removePortEvent(rmEvent);
Yuta HIGUCHI240bf072014-02-17 10:55:21 -0800376
Jonathan Hart480c5572014-02-14 18:28:16 -0800377 // We can't remove ports here because this will trigger a remove
378 // from the switch's port list, which we are currently iterating
379 // over.
380 portsToRemove.add(p);
381 }
382 }
383 for (Port p : portsToRemove) {
Yuta HIGUCHI8d762e92014-02-12 14:10:25 -0800384 PortEvent rmEvent = new PortEvent(p.getSwitch().getDpid(), p.getNumber());
385 // calling Discovery removePort() API to wipe from DB, etc.
386 removePortEvent(rmEvent);
Yuta HIGUCHI8d762e92014-02-12 14:10:25 -0800387 }
388 }
Jonathan Hart22eb9882014-02-11 15:52:59 -0800389 }
Yuta HIGUCHIcd922f42014-02-11 18:59:11 -0800390
Yuta HIGUCHId02e9282014-02-12 09:24:41 -0800391 private boolean prepareForAddPortEvent(PortEvent portEvt) {
Yuta HIGUCHId02e9282014-02-12 09:24:41 -0800392 // Parent Switch must exist
393 if ( getSwitch(portEvt.getDpid()) == null) {
394 return false;
395 }
396 // Prep: None
Jonathan Hart22eb9882014-02-11 15:52:59 -0800397 return true;
398 }
Yuta HIGUCHIcd922f42014-02-11 18:59:11 -0800399
Yuta HIGUCHId02e9282014-02-12 09:24:41 -0800400 private boolean prepareForRemovePortEvent(PortEvent portEvt) {
Yuta HIGUCHId02e9282014-02-12 09:24:41 -0800401 // Parent Switch must exist
Yuta HIGUCHI8d762e92014-02-12 14:10:25 -0800402 Switch sw = getSwitch(portEvt.getDpid());
403 if ( sw == null ) {
Yuta HIGUCHI88be0f22014-02-14 17:20:43 -0800404 log.debug("Switch already removed? {}", portEvt);
Yuta HIGUCHId02e9282014-02-12 09:24:41 -0800405 return false;
406 }
Yuta HIGUCHI8d762e92014-02-12 14:10:25 -0800407 Port port = sw.getPort(portEvt.getNumber());
408 if ( port == null ) {
409 log.debug("Port already removed? {}", portEvt);
410 // let it pass
411 return true;
412 }
413
414 // Prep: Remove Link and Device Attachment
Yuta HIGUCHI240bf072014-02-17 10:55:21 -0800415 ArrayList<DeviceEvent> deviceEvts = new ArrayList<>();
Yuta HIGUCHI8d762e92014-02-12 14:10:25 -0800416 for (Device device : port.getDevices()) {
Yuta HIGUCHI88be0f22014-02-14 17:20:43 -0800417 log.debug("Removing Device {} on Port {}", device, portEvt);
Yuta HIGUCHI8d762e92014-02-12 14:10:25 -0800418 DeviceEvent devEvt = new DeviceEvent(device.getMacAddress());
419 devEvt.addAttachmentPoint(new SwitchPort(port.getSwitch().getDpid(), port.getNumber()));
Yuta HIGUCHI240bf072014-02-17 10:55:21 -0800420 deviceEvts.add(devEvt);
421 }
422 for (DeviceEvent devEvt : deviceEvts) {
Yuta HIGUCHI8d762e92014-02-12 14:10:25 -0800423 // calling Discovery API to wipe from DB, etc.
424 removeDeviceEvent(devEvt);
425 }
Yuta HIGUCHI240bf072014-02-17 10:55:21 -0800426
Yuta HIGUCHI8d762e92014-02-12 14:10:25 -0800427 Set<Link> links = new HashSet<>();
428 links.add(port.getOutgoingLink());
429 links.add(port.getIncomingLink());
430 for ( Link link : links) {
431 if (link == null ) {
432 continue;
433 }
Yuta HIGUCHI88be0f22014-02-14 17:20:43 -0800434 log.debug("Removing Link {} on Port {}", link, portEvt);
Yuta HIGUCHI8d762e92014-02-12 14:10:25 -0800435 LinkEvent linkEvent = new LinkEvent(link.getSourceSwitchDpid(), link.getSourcePortNumber(), link.getDestinationSwitchDpid(), link.getDestinationPortNumber());
436 // calling Discovery API to wipe from DB, etc.
Yuta HIGUCHI0a4bd192014-02-17 13:52:34 -0800437 // XXX call internal remove Link, which will check
438 // ownership and modify only if it is the owner
Yuta HIGUCHI8d762e92014-02-12 14:10:25 -0800439 removeLinkEvent(linkEvent);
440 }
Jonathan Hart22eb9882014-02-11 15:52:59 -0800441 return true;
442 }
Yuta HIGUCHIcd922f42014-02-11 18:59:11 -0800443
Yuta HIGUCHId02e9282014-02-12 09:24:41 -0800444 private boolean prepareForAddLinkEvent(LinkEvent linkEvt) {
Yuta HIGUCHI8d762e92014-02-12 14:10:25 -0800445 // Src/Dst Switch must exist
446 Switch srcSw = getSwitch(linkEvt.getSrc().dpid);
447 Switch dstSw = getSwitch(linkEvt.getDst().dpid);
448 if ( srcSw == null || dstSw == null ) {
449 return false;
450 }
451 // Src/Dst Port must exist
452 Port srcPort = srcSw.getPort(linkEvt.getSrc().number);
Jonathan Hart4c263272014-02-13 17:41:05 -0800453 Port dstPort = dstSw.getPort(linkEvt.getDst().number);
Yuta HIGUCHI8d762e92014-02-12 14:10:25 -0800454 if ( srcPort == null || dstPort == null ) {
455 return false;
456 }
457
458 // Prep: remove Device attachment on both Ports
Yuta HIGUCHI240bf072014-02-17 10:55:21 -0800459 ArrayList<DeviceEvent> deviceEvents = new ArrayList<>();
Yuta HIGUCHI8d762e92014-02-12 14:10:25 -0800460 for (Device device : srcPort.getDevices()) {
461 DeviceEvent devEvt = new DeviceEvent(device.getMacAddress());
462 devEvt.addAttachmentPoint(new SwitchPort(srcPort.getSwitch().getDpid(), srcPort.getNumber()));
Yuta HIGUCHI240bf072014-02-17 10:55:21 -0800463 deviceEvents.add(devEvt);
Yuta HIGUCHI8d762e92014-02-12 14:10:25 -0800464 }
465 for (Device device : dstPort.getDevices()) {
466 DeviceEvent devEvt = new DeviceEvent(device.getMacAddress());
467 devEvt.addAttachmentPoint(new SwitchPort(dstPort.getSwitch().getDpid(), dstPort.getNumber()));
Yuta HIGUCHI240bf072014-02-17 10:55:21 -0800468 deviceEvents.add(devEvt);
469 }
470 for (DeviceEvent devEvt : deviceEvents) {
Yuta HIGUCHI8d762e92014-02-12 14:10:25 -0800471 // calling Discovery API to wipe from DB, etc.
472 removeDeviceEvent(devEvt);
473 }
474
475 return true;
Jonathan Hart22eb9882014-02-11 15:52:59 -0800476 }
Yuta HIGUCHIcd922f42014-02-11 18:59:11 -0800477
Yuta HIGUCHId02e9282014-02-12 09:24:41 -0800478 private boolean prepareForRemoveLinkEvent(LinkEvent linkEvt) {
Yuta HIGUCHI8d762e92014-02-12 14:10:25 -0800479 // Src/Dst Switch must exist
480 Switch srcSw = getSwitch(linkEvt.getSrc().dpid);
481 Switch dstSw = getSwitch(linkEvt.getDst().dpid);
482 if ( srcSw == null || dstSw == null ) {
Yuta HIGUCHI125c7df2014-02-14 12:28:10 -0800483 log.warn("Rejecting removeLink {} because switch doesn't exist", linkEvt);
Yuta HIGUCHI8d762e92014-02-12 14:10:25 -0800484 return false;
485 }
486 // Src/Dst Port must exist
487 Port srcPort = srcSw.getPort(linkEvt.getSrc().number);
Yuta HIGUCHI125c7df2014-02-14 12:28:10 -0800488 Port dstPort = dstSw.getPort(linkEvt.getDst().number);
Yuta HIGUCHI8d762e92014-02-12 14:10:25 -0800489 if ( srcPort == null || dstPort == null ) {
Yuta HIGUCHI125c7df2014-02-14 12:28:10 -0800490 log.warn("Rejecting removeLink {} because port doesn't exist", linkEvt);
Yuta HIGUCHI8d762e92014-02-12 14:10:25 -0800491 return false;
492 }
493
Yuta HIGUCHI125c7df2014-02-14 12:28:10 -0800494 Link link = srcPort.getOutgoingLink();
495
496 // Link is already gone, or different Link exist in memory
497 // XXX Check if we should reject or just accept these cases.
498 // it should be harmless to remove the Link on event from DB anyways
499 if (link == null ||
500 !link.getDestinationPortNumber().equals(linkEvt.getDst().number)
501 || !link.getDestinationSwitchDpid().equals(linkEvt.getDst().dpid)) {
502 log.warn("Rejecting removeLink {} because link doesn't exist", linkEvt);
503 return false;
504 }
Yuta HIGUCHI8d762e92014-02-12 14:10:25 -0800505 // Prep: None
506 return true;
Jonathan Hart22eb9882014-02-11 15:52:59 -0800507 }
Yuta HIGUCHIcd922f42014-02-11 18:59:11 -0800508
Yuta HIGUCHI8d762e92014-02-12 14:10:25 -0800509 /**
510 *
511 * @param deviceEvt Event will be modified to remove inapplicable attachemntPoints/ipAddress
512 * @return false if this event should be dropped.
513 */
Yuta HIGUCHId02e9282014-02-12 09:24:41 -0800514 private boolean prepareForAddDeviceEvent(DeviceEvent deviceEvt) {
Yuta HIGUCHI8d762e92014-02-12 14:10:25 -0800515 boolean preconditionBroken = false;
516 ArrayList<PortEvent.SwitchPort> failedSwitchPort = new ArrayList<>();
517 for ( PortEvent.SwitchPort swp : deviceEvt.getAttachmentPoints() ) {
Yuta HIGUCHId02e9282014-02-12 09:24:41 -0800518 // Attached Ports' Parent Switch must exist
Yuta HIGUCHI8d762e92014-02-12 14:10:25 -0800519 Switch sw = getSwitch(swp.dpid);
520 if ( sw == null ) {
521 preconditionBroken = true;
522 failedSwitchPort.add(swp);
523 continue;
524 }
Yuta HIGUCHId02e9282014-02-12 09:24:41 -0800525 // Attached Ports must exist
Yuta HIGUCHI8d762e92014-02-12 14:10:25 -0800526 Port port = sw.getPort(swp.number);
527 if ( port == null ) {
528 preconditionBroken = true;
529 failedSwitchPort.add(swp);
530 continue;
531 }
Yuta HIGUCHId02e9282014-02-12 09:24:41 -0800532 // Attached Ports must not have Link
Yuta HIGUCHI8d762e92014-02-12 14:10:25 -0800533 if ( port.getOutgoingLink() != null || port.getIncomingLink() != null ) {
534 preconditionBroken = true;
535 failedSwitchPort.add(swp);
536 continue;
537 }
538 }
Yuta HIGUCHId02e9282014-02-12 09:24:41 -0800539
Yuta HIGUCHI8d762e92014-02-12 14:10:25 -0800540 // Rewriting event to exclude failed attachmentPoint
541 // XXX Assumption behind this is that inapplicable device event should
542 // be dropped, not deferred. If we decide to defer Device event,
543 // rewriting can become a problem
544 List<SwitchPort> attachmentPoints = deviceEvt.getAttachmentPoints();
545 attachmentPoints.removeAll(failedSwitchPort);
546 deviceEvt.setAttachmentPoints(attachmentPoints);
547
548 if ( deviceEvt.getAttachmentPoints().isEmpty() && deviceEvt.getIpAddresses().isEmpty() ) {
Yuta HIGUCHI125c7df2014-02-14 12:28:10 -0800549 // return false to represent: Nothing left to do for this event. Caller should drop event
Yuta HIGUCHI8d762e92014-02-12 14:10:25 -0800550 return false;
551 }
552
553 // Should we return false to tell caller that the event was trimmed?
554 // if ( preconditionBroken ) {
555 // return false;
556 // }
557
558 return true;
Jonathan Hart22eb9882014-02-11 15:52:59 -0800559 }
Yuta HIGUCHIcd922f42014-02-11 18:59:11 -0800560
Yuta HIGUCHId02e9282014-02-12 09:24:41 -0800561 private boolean prepareForRemoveDeviceEvent(DeviceEvent deviceEvt) {
Yuta HIGUCHId02e9282014-02-12 09:24:41 -0800562 // No show stopping precondition?
563 // Prep: none
Jonathan Hart22eb9882014-02-11 15:52:59 -0800564 return true;
565 }
Yuta HIGUCHI928fa682014-02-11 19:07:57 -0800566
Yuta HIGUCHI76df2472014-02-12 22:36:51 -0800567 /* ******************************
568 * NetworkGraphReplicationInterface methods
569 * ******************************/
570
Yuta HIGUCHI928fa682014-02-11 19:07:57 -0800571 @Override
572 public void putSwitchReplicationEvent(SwitchEvent switchEvent) {
Yuta HIGUCHI9fc10ac2014-02-12 17:18:57 -0800573 if (prepareForAddSwitchEvent(switchEvent)) {
574 putSwitch(switchEvent);
575 }
576 // TODO handle invariant violation
Yuta HIGUCHIa536e762014-02-17 21:47:28 -0800577 // trigger instance local topology event handler
578 dispatchPutSwitchEvent(switchEvent);
Yuta HIGUCHI928fa682014-02-11 19:07:57 -0800579 }
580
581 @Override
582 public void removeSwitchReplicationEvent(SwitchEvent switchEvent) {
Yuta HIGUCHI9fc10ac2014-02-12 17:18:57 -0800583 if (prepareForRemoveSwitchEvent(switchEvent)) {
584 removeSwitch(switchEvent);
585 }
Yuta HIGUCHI125c7df2014-02-14 12:28:10 -0800586 // TODO handle invariant violation
Yuta HIGUCHIa536e762014-02-17 21:47:28 -0800587 // trigger instance local topology event handler
588 dispatchRemoveSwitchEvent(switchEvent);
Yuta HIGUCHI928fa682014-02-11 19:07:57 -0800589 }
590
591 @Override
592 public void putPortReplicationEvent(PortEvent portEvent) {
Yuta HIGUCHI9fc10ac2014-02-12 17:18:57 -0800593 if (prepareForAddPortEvent(portEvent)) {
594 putPort(portEvent);
595 }
Yuta HIGUCHI125c7df2014-02-14 12:28:10 -0800596 // TODO handle invariant violation
Yuta HIGUCHIa536e762014-02-17 21:47:28 -0800597 // trigger instance local topology event handler
598 dispatchPutPortEvent(portEvent);
Yuta HIGUCHI928fa682014-02-11 19:07:57 -0800599 }
600
601 @Override
602 public void removePortReplicationEvent(PortEvent portEvent) {
Yuta HIGUCHI9fc10ac2014-02-12 17:18:57 -0800603 if (prepareForRemovePortEvent(portEvent)) {
604 removePort(portEvent);
605 }
Yuta HIGUCHI125c7df2014-02-14 12:28:10 -0800606 // TODO handle invariant violation
Yuta HIGUCHIa536e762014-02-17 21:47:28 -0800607 // trigger instance local topology event handler
608 dispatchRemovePortEvent(portEvent);
Yuta HIGUCHI928fa682014-02-11 19:07:57 -0800609 }
610
611 @Override
612 public void putLinkReplicationEvent(LinkEvent linkEvent) {
Yuta HIGUCHI9fc10ac2014-02-12 17:18:57 -0800613 if (prepareForAddLinkEvent(linkEvent)) {
614 putLink(linkEvent);
615 }
Yuta HIGUCHI125c7df2014-02-14 12:28:10 -0800616 // TODO handle invariant violation
Yuta HIGUCHIa536e762014-02-17 21:47:28 -0800617 // trigger instance local topology event handler
618 dispatchPutLinkEvent(linkEvent);
Yuta HIGUCHI928fa682014-02-11 19:07:57 -0800619 }
620
621 @Override
622 public void removeLinkReplicationEvent(LinkEvent linkEvent) {
Yuta HIGUCHI9fc10ac2014-02-12 17:18:57 -0800623 if (prepareForRemoveLinkEvent(linkEvent)) {
624 removeLink(linkEvent);
625 }
Yuta HIGUCHI125c7df2014-02-14 12:28:10 -0800626 // TODO handle invariant violation
Yuta HIGUCHIa536e762014-02-17 21:47:28 -0800627 // trigger instance local topology event handler
628 dispatchRemoveLinkEvent(linkEvent);
Yuta HIGUCHI928fa682014-02-11 19:07:57 -0800629 }
630
631 @Override
632 public void putDeviceReplicationEvent(DeviceEvent deviceEvent) {
Yuta HIGUCHI9fc10ac2014-02-12 17:18:57 -0800633 if (prepareForAddDeviceEvent(deviceEvent)) {
634 putDevice(deviceEvent);
635 }
Yuta HIGUCHI125c7df2014-02-14 12:28:10 -0800636 // TODO handle invariant violation
Yuta HIGUCHIa536e762014-02-17 21:47:28 -0800637 // trigger instance local topology event handler
638 dispatchPutDeviceEvent(deviceEvent);
Yuta HIGUCHI928fa682014-02-11 19:07:57 -0800639 }
640
641 @Override
642 public void removeDeviceReplicationEvent(DeviceEvent deviceEvent) {
Yuta HIGUCHI9fc10ac2014-02-12 17:18:57 -0800643 if (prepareForRemoveDeviceEvent(deviceEvent)) {
644 removeDevice(deviceEvent);
645 }
Yuta HIGUCHI125c7df2014-02-14 12:28:10 -0800646 // TODO handle invariant violation
Yuta HIGUCHIa536e762014-02-17 21:47:28 -0800647 // trigger instance local topology event handler
648 dispatchRemoveDeviceEvent(deviceEvent);
Yuta HIGUCHI928fa682014-02-11 19:07:57 -0800649 }
Yuta HIGUCHI76df2472014-02-12 22:36:51 -0800650
651 /* ************************************************
652 * Internal In-memory object mutation methods.
653 * ************************************************/
654
655 void putSwitch(SwitchEvent swEvt) {
656 if (swEvt == null) {
657 throw new IllegalArgumentException("Switch cannot be null");
658 }
659
660 Switch sw = switches.get(swEvt.getDpid());
661
662 if (sw == null) {
663 sw = new SwitchImpl(this, swEvt.getDpid());
664 Switch existing = switches.putIfAbsent(swEvt.getDpid(), sw);
665 if (existing != null) {
666 log.warn(
667 "Concurrent putSwitch not expected. Continuing updating {}",
668 existing);
669 sw = existing;
670 }
671 }
672
673 // Update when more attributes are added to Event object
674 // no attribute to update for now
675
676 // TODO handle child Port event properly for performance
677 for (PortEvent portEvt : swEvt.getPorts() ) {
678 putPort(portEvt);
679 }
680
681 }
682
683 void removeSwitch(SwitchEvent swEvt) {
684 if (swEvt == null) {
685 throw new IllegalArgumentException("Switch cannot be null");
686 }
687
688 // TODO handle child Port event properly for performance
689 for (PortEvent portEvt : swEvt.getPorts() ) {
690 removePort(portEvt);
691 }
692
693 Switch sw = switches.get(swEvt.getDpid());
694
695 if (sw == null) {
696 log.warn("Switch {} already removed, ignoring", swEvt);
697 return;
698 }
699
Yuta HIGUCHI317bf542014-02-17 11:02:39 -0800700 // remove all ports if there still exist
701 ArrayList<PortEvent> portsToRemove = new ArrayList<>();
702 for (Port port : sw.getPorts()) {
Yuta HIGUCHI76df2472014-02-12 22:36:51 -0800703 log.warn(
Yuta HIGUCHI317bf542014-02-17 11:02:39 -0800704 "Port {} on Switch {} should be removed prior to removing Switch. Removing Port now",
705 port, swEvt);
706 PortEvent portEvt = new PortEvent(port.getDpid(), port.getNumber());
707 portsToRemove.add(portEvt);
Yuta HIGUCHI76df2472014-02-12 22:36:51 -0800708 }
Yuta HIGUCHI0a4bd192014-02-17 13:52:34 -0800709 for (PortEvent portEvt : portsToRemove) {
Yuta HIGUCHI317bf542014-02-17 11:02:39 -0800710 // XXX calling removePortEvent() may trigger duplicate event, once at prepare phase, second time here
711 // If event can be squashed, ignored etc. at receiver side it shouldn't be a problem, but if not
712 // need to re-visit this issue.
713
714 // Note: removePortEvent() implies removal of attached Device, etc.
715 // if we decide not to call removePortEvent(), Device needs to be handled properly
716 removePortEvent(portEvt);
Yuta HIGUCHI76df2472014-02-12 22:36:51 -0800717 }
718
719 boolean removed = switches.remove(swEvt.getDpid(), sw);
720 if (removed) {
721 log.warn(
722 "Switch instance was replaced concurrently while removing {}. Something is not right.",
723 sw);
724 }
725 }
726
727 void putPort(PortEvent portEvt) {
728 if (portEvt == null) {
729 throw new IllegalArgumentException("Port cannot be null");
730 }
731 Switch sw = switches.get(portEvt.getDpid());
732 if (sw == null) {
733 throw new BrokenInvariantException(String.format(
734 "Switch with dpid %s did not exist.",
735 new Dpid(portEvt.getDpid())));
736 }
737 Port p = sw.getPort(portEvt.getNumber());
738 PortImpl port = null;
739 if (p != null) {
740 port = getPortImpl(p);
741 }
742
743 if (port == null) {
744 port = new PortImpl(this, sw, portEvt.getNumber());
745 }
746
747 // TODO update attributes
748
749 SwitchImpl s = getSwitchImpl(sw);
750 s.addPort(port);
751 }
752
753 void removePort(PortEvent portEvt) {
754 if (portEvt == null) {
755 throw new IllegalArgumentException("Port cannot be null");
756 }
757
758 Switch sw = switches.get(portEvt.getDpid());
759 if (sw == null) {
760 log.warn("Parent Switch for Port {} already removed, ignoring", portEvt);
761 return;
762 }
763
764 Port p = sw.getPort(portEvt.getNumber());
765 if (p == null) {
766 log.warn("Port {} already removed, ignoring", portEvt);
767 return;
768 }
769
Yuta HIGUCHIde040642014-02-17 11:03:39 -0800770 // Remove Link and Device Attachment
771 for (Device device : p.getDevices()) {
772 log.debug("Removing Device {} on Port {}", device, portEvt);
773 DeviceEvent devEvt = new DeviceEvent(device.getMacAddress());
774 devEvt.addAttachmentPoint(new SwitchPort(p.getSwitch().getDpid(), p.getNumber()));
Yuta HIGUCHI76df2472014-02-12 22:36:51 -0800775
Yuta HIGUCHIde040642014-02-17 11:03:39 -0800776 // XXX calling removeDeviceEvent() may trigger duplicate event, once at prepare phase, second time here
777 // If event can be squashed, ignored etc. at receiver side it shouldn't be a problem, but if not
778 // need to re-visit
779
780 // calling Discovery API to wipe from DB, etc.
781 removeDeviceEvent(devEvt);
Yuta HIGUCHI76df2472014-02-12 22:36:51 -0800782 }
Yuta HIGUCHIde040642014-02-17 11:03:39 -0800783 Set<Link> links = new HashSet<>();
784 links.add(p.getOutgoingLink());
785 links.add(p.getIncomingLink());
786 ArrayList<LinkEvent> linksToRemove = new ArrayList<>();
787 for (Link link : links) {
788 if (link == null) {
789 continue;
790 }
791 log.debug("Removing Link {} on Port {}", link, portEvt);
792 LinkEvent linkEvent = new LinkEvent(link.getSourceSwitchDpid(), link.getSourcePortNumber(), link.getDestinationSwitchDpid(), link.getDestinationPortNumber());
793 linksToRemove.add(linkEvent);
Yuta HIGUCHI76df2472014-02-12 22:36:51 -0800794 }
Yuta HIGUCHIde040642014-02-17 11:03:39 -0800795 for (LinkEvent linkEvent : linksToRemove) {
796 // XXX calling removeLinkEvent() may trigger duplicate event, once at prepare phase, second time here
797 // If event can be squashed, ignored etc. at receiver side it shouldn't be a problem, but if not
798 // need to re-visit
799
800 // calling Discovery API to wipe from DB, etc.
801 removeLinkEvent(linkEvent);
Yuta HIGUCHI76df2472014-02-12 22:36:51 -0800802 }
803
804 // remove Port from Switch
805 SwitchImpl s = getSwitchImpl(sw);
806 s.removePort(p);
807 }
808
809 void putLink(LinkEvent linkEvt) {
810 if (linkEvt == null) {
811 throw new IllegalArgumentException("Link cannot be null");
812 }
813
814 Switch srcSw = switches.get(linkEvt.getSrc().dpid);
815 if (srcSw == null) {
816 throw new BrokenInvariantException(
817 String.format(
818 "Switch with dpid %s did not exist.",
819 new Dpid(linkEvt.getSrc().dpid)));
820 }
821
822 Switch dstSw = switches.get(linkEvt.getDst().dpid);
823 if (dstSw == null) {
824 throw new BrokenInvariantException(
825 String.format(
826 "Switch with dpid %s did not exist.",
827 new Dpid(linkEvt.getDst().dpid)));
828 }
829
830 Port srcPort = srcSw.getPort(linkEvt.getSrc().number);
831 if (srcPort == null) {
832 throw new BrokenInvariantException(
833 String.format(
834 "Src Port %s of a Link did not exist.",
835 linkEvt.getSrc() ));
836 }
837
838 Port dstPort = dstSw.getPort(linkEvt.getDst().number);
839 if (dstPort == null) {
840 throw new BrokenInvariantException(
841 String.format(
842 "Dst Port %s of a Link did not exist.",
843 linkEvt.getDst() ));
844 }
845
846 // getting Link instance from destination port incoming Link
847 Link l = dstPort.getIncomingLink();
848 LinkImpl link = null;
849 assert( l == srcPort.getOutgoingLink() );
850 if (l != null) {
851 link = getLinkImpl(l);
852 }
853
854 if (link == null) {
855 link = new LinkImpl(this, srcPort, dstPort);
856 }
857
858
859 PortImpl dstPortMem = getPortImpl(dstPort);
860 PortImpl srcPortMem = getPortImpl(srcPort);
861
862 // Add Link first to avoid further Device addition
863
864 // add Link to Port
865 dstPortMem.setIncomingLink(link);
866 srcPortMem.setOutgoingLink(link);
867
868 // remove Device Pointing to Port if any
869 for(Device d : dstPortMem.getDevices() ) {
870 log.error("Device {} on Port {} should have been removed prior to adding Link {}", d, dstPort, linkEvt);
871 DeviceImpl dev = getDeviceImpl(d);
872 dev.removeAttachmentPoint(dstPort);
Yuta HIGUCHI407261a2014-02-13 16:34:06 -0800873 // This implies that change is made to Device Object.
874 // sending Device attachment point removed event
875 DeviceEvent rmEvent = new DeviceEvent(d.getMacAddress());
876 rmEvent.addAttachmentPoint(new SwitchPort(dstPort.getDpid(), dstPort.getNumber()));
877 removeDeviceEvent(rmEvent);
Yuta HIGUCHI76df2472014-02-12 22:36:51 -0800878 }
879 dstPortMem.removeAllDevice();
880 for(Device d : srcPortMem.getDevices() ) {
881 log.error("Device {} on Port {} should have been removed prior to adding Link {}", d, srcPort, linkEvt);
882 DeviceImpl dev = getDeviceImpl(d);
883 dev.removeAttachmentPoint(srcPort);
Yuta HIGUCHI407261a2014-02-13 16:34:06 -0800884 // This implies that change is made to Device Object.
885 // sending Device attachment point removed event
886 DeviceEvent rmEvent = new DeviceEvent(d.getMacAddress());
887 rmEvent.addAttachmentPoint(new SwitchPort(dstPort.getDpid(), dstPort.getNumber()));
888 removeDeviceEvent(rmEvent);
Yuta HIGUCHI76df2472014-02-12 22:36:51 -0800889 }
890 srcPortMem.removeAllDevice();
891
892 }
893
894 void removeLink(LinkEvent linkEvt) {
895 if (linkEvt == null) {
896 throw new IllegalArgumentException("Link cannot be null");
897 }
898
899 Switch srcSw = switches.get(linkEvt.getSrc().dpid);
900 if (srcSw == null) {
901 log.warn("Src Switch for Link {} already removed, ignoring", linkEvt);
902 return;
903 }
904
905 Switch dstSw = switches.get(linkEvt.getDst().dpid);
906 if (dstSw == null) {
907 log.warn("Dst Switch for Link {} already removed, ignoring", linkEvt);
908 return;
909 }
910
911 Port srcPort = srcSw.getPort(linkEvt.getSrc().number);
912 if (srcPort == null) {
913 log.warn("Src Port for Link {} already removed, ignoring", linkEvt);
914 return;
915 }
916
917 Port dstPort = dstSw.getPort(linkEvt.getDst().number);
918 if (dstPort == null) {
919 log.warn("Dst Port for Link {} already removed, ignoring", linkEvt);
920 return;
921 }
922
923 Link l = dstPort.getIncomingLink();
924 if ( l == null ) {
925 log.warn("Link {} already removed on destination Port", linkEvt);
926 }
927 l = srcPort.getOutgoingLink();
928 if ( l == null ) {
929 log.warn("Link {} already removed on src Port", linkEvt);
930 }
931
932 getPortImpl(dstPort).setIncomingLink(null);
933 getPortImpl(srcPort).setOutgoingLink(null);
934 }
935
936 // XXX Need to rework Device related
937 void putDevice(DeviceEvent deviceEvt) {
938 if (deviceEvt == null) {
939 throw new IllegalArgumentException("Device cannot be null");
940 }
941
942 Device device = getDeviceByMac(deviceEvt.getMac());
943 if ( device == null ) {
944 device = new DeviceImpl(this, deviceEvt.getMac());
945 Device existing = mac2Device.putIfAbsent(deviceEvt.getMac(), device);
946 if (existing != null) {
947 log.warn(
948 "Concurrent putDevice seems to be in action. Continuing updating {}",
949 existing);
950 device = existing;
951 }
952 }
953 DeviceImpl memDevice = getDeviceImpl(device);
954
955 // for each attachment point
956 for (SwitchPort swp : deviceEvt.getAttachmentPoints() ) {
957 // Attached Ports' Parent Switch must exist
958 Switch sw = getSwitch(swp.dpid);
959 if ( sw == null ) {
Yuta HIGUCHI25719052014-02-13 14:42:06 -0800960 log.warn("Switch for the attachment point {} did not exist. skipping mutation", swp);
Yuta HIGUCHI76df2472014-02-12 22:36:51 -0800961 continue;
962 }
963 // Attached Ports must exist
964 Port port = sw.getPort(swp.number);
965 if ( port == null ) {
Yuta HIGUCHI25719052014-02-13 14:42:06 -0800966 log.warn("Port for the attachment point {} did not exist. skipping mutation", swp);
Yuta HIGUCHI76df2472014-02-12 22:36:51 -0800967 continue;
968 }
969 // Attached Ports must not have Link
970 if ( port.getOutgoingLink() != null || port.getIncomingLink() != null ) {
971 log.warn("Link (Out:{},In:{}) exist on the attachment point, skipping mutation.", port.getOutgoingLink(), port.getIncomingLink());
972 continue;
973 }
974
975 // finally add Device <-> Port on In-memory structure
976 PortImpl memPort = getPortImpl(port);
977 memPort.addDevice(device);
978 memDevice.addAttachmentPoint(port);
979 }
980
981 // for each IP address
982 for( InetAddress ipAddr : deviceEvt.getIpAddresses() ) {
983 // Add Device -> IP
984 memDevice.addIpAddress(ipAddr);
985
986 // Add IP -> Set<Device>
987 boolean updated = false;
988 do {
989 Set<Device> devices = this.addr2Device.get(ipAddr);
990 if ( devices == null ) {
991 devices = new HashSet<>();
992 Set<Device> existing = this.addr2Device.putIfAbsent(ipAddr, devices);
993 if ( existing == null ) {
994 // success
995 updated = true;
996 }
997 } else {
998 Set<Device> updateDevices = new HashSet<>(devices);
999 updateDevices.add(device);
1000 updated = this.addr2Device.replace(ipAddr, devices, updateDevices);
1001 }
1002 if (!updated) {
1003 log.debug("Collision detected, updating IP to Device mapping retrying.");
1004 }
1005 } while( !updated );
1006 }
1007 }
1008
1009 void removeDevice(DeviceEvent deviceEvt) {
1010 if (deviceEvt == null) {
1011 throw new IllegalArgumentException("Device cannot be null");
1012 }
1013
1014 Device device = getDeviceByMac(deviceEvt.getMac());
1015 if ( device == null ) {
1016 log.warn("Device {} already removed, ignoring", deviceEvt);
1017 return;
1018 }
1019 DeviceImpl memDevice = getDeviceImpl(device);
1020
1021 // for each attachment point
1022 for (SwitchPort swp : deviceEvt.getAttachmentPoints() ) {
1023 // Attached Ports' Parent Switch must exist
1024 Switch sw = getSwitch(swp.dpid);
1025 if ( sw == null ) {
Yuta HIGUCHI25719052014-02-13 14:42:06 -08001026 log.warn("Switch for the attachment point {} did not exist. skipping attachment point mutation", swp);
Yuta HIGUCHI76df2472014-02-12 22:36:51 -08001027 continue;
1028 }
1029 // Attached Ports must exist
1030 Port port = sw.getPort(swp.number);
1031 if ( port == null ) {
Yuta HIGUCHI25719052014-02-13 14:42:06 -08001032 log.warn("Port for the attachment point {} did not exist. skipping attachment point mutation", swp);
Yuta HIGUCHI76df2472014-02-12 22:36:51 -08001033 continue;
1034 }
1035
1036 // finally remove Device <-> Port on In-memory structure
1037 PortImpl memPort = getPortImpl(port);
1038 memPort.removeDevice(device);
1039 memDevice.removeAttachmentPoint(port);
1040 }
1041
1042 // for each IP address
1043 for( InetAddress ipAddr : deviceEvt.getIpAddresses() ) {
1044 // Remove Device -> IP
1045 memDevice.removeIpAddress(ipAddr);
1046
1047 // Remove IP -> Set<Device>
1048 boolean updated = false;
1049 do {
1050 Set<Device> devices = this.addr2Device.get(ipAddr);
1051 if ( devices == null ) {
1052 // already empty set, nothing to do
1053 updated = true;
1054 } else {
1055 Set<Device> updateDevices = new HashSet<>(devices);
1056 updateDevices.remove(device);
1057 updated = this.addr2Device.replace(ipAddr, devices, updateDevices);
1058 }
1059 if (!updated) {
1060 log.debug("Collision detected, updating IP to Device mapping retrying.");
1061 }
1062 } while( !updated );
1063 }
1064 }
1065
Yuta HIGUCHIa536e762014-02-17 21:47:28 -08001066 private void dispatchPutSwitchEvent(SwitchEvent switchEvent) {
1067 for (INetworkGraphListener listener : this.networkGraphListeners) {
1068 // TODO Should copy before handing them over to listener
1069 listener.putSwitchEvent(switchEvent);
1070 }
1071 }
1072
1073 private void dispatchRemoveSwitchEvent(SwitchEvent switchEvent) {
1074 for (INetworkGraphListener listener : this.networkGraphListeners) {
1075 // TODO Should copy before handing them over to listener
1076 listener.removeSwitchEvent(switchEvent);
1077 }
1078 }
1079
1080 private void dispatchPutPortEvent(PortEvent portEvent) {
1081 for (INetworkGraphListener listener : this.networkGraphListeners) {
1082 // TODO Should copy before handing them over to listener
1083 listener.putPortEvent(portEvent);
1084 }
1085 }
1086
1087 private void dispatchRemovePortEvent(PortEvent portEvent) {
1088 for (INetworkGraphListener listener : this.networkGraphListeners) {
1089 // TODO Should copy before handing them over to listener
1090 listener.removePortEvent(portEvent);
1091 }
1092 }
1093
1094 private void dispatchPutLinkEvent(LinkEvent linkEvent) {
1095 for (INetworkGraphListener listener : this.networkGraphListeners) {
1096 // TODO Should copy before handing them over to listener
1097 listener.putLinkEvent(linkEvent);
1098 }
1099 }
1100
1101 private void dispatchRemoveLinkEvent(LinkEvent linkEvent) {
1102 for (INetworkGraphListener listener : this.networkGraphListeners) {
1103 // TODO Should copy before handing them over to listener
1104 listener.removeLinkEvent(linkEvent);
1105 }
1106 }
1107
1108 private void dispatchPutDeviceEvent(DeviceEvent deviceEvent) {
1109 for (INetworkGraphListener listener : this.networkGraphListeners) {
1110 // TODO Should copy before handing them over to listener
1111 listener.putDeviceEvent(deviceEvent);;
1112 }
1113 }
1114
1115 private void dispatchRemoveDeviceEvent(DeviceEvent deviceEvent) {
1116 for (INetworkGraphListener listener : this.networkGraphListeners) {
1117 // TODO Should copy before handing them over to listener
1118 listener.removeDeviceEvent(deviceEvent);
1119 }
1120 }
1121
Yuta HIGUCHI76df2472014-02-12 22:36:51 -08001122 private SwitchImpl getSwitchImpl(Switch sw) {
1123 if (sw instanceof SwitchImpl) {
1124 return (SwitchImpl) sw;
1125 }
1126 throw new ClassCastException("SwitchImpl expected, but found: " + sw);
1127 }
1128
1129 private PortImpl getPortImpl(Port p) {
1130 if (p instanceof PortImpl) {
1131 return (PortImpl) p;
1132 }
1133 throw new ClassCastException("PortImpl expected, but found: " + p);
1134 }
1135
1136 private LinkImpl getLinkImpl(Link l) {
1137 if (l instanceof LinkImpl) {
1138 return (LinkImpl) l;
1139 }
1140 throw new ClassCastException("LinkImpl expected, but found: " + l);
1141 }
1142
1143 private DeviceImpl getDeviceImpl(Device d) {
1144 if (d instanceof DeviceImpl) {
1145 return (DeviceImpl) d;
1146 }
1147 throw new ClassCastException("DeviceImpl expected, but found: " + d);
1148 }
1149
1150 @Deprecated
1151 public void loadWholeTopologyFromDB() {
Yuta HIGUCHI0a4bd192014-02-17 13:52:34 -08001152 // XXX May need to clear whole topology first, depending on
1153 // how we initially subscribe to replication events
Yuta HIGUCHI76df2472014-02-12 22:36:51 -08001154
1155 for (RCSwitch sw : RCSwitch.getAllSwitches()) {
1156 if ( sw.getStatus() != RCSwitch.STATUS.ACTIVE ) {
1157 continue;
1158 }
1159 putSwitchReplicationEvent(new SwitchEvent(sw.getDpid()));
1160 }
1161
1162 for (RCPort p : RCPort.getAllPorts()) {
1163 if (p.getStatus() != RCPort.STATUS.ACTIVE) {
1164 continue;
1165 }
1166 putPortReplicationEvent(new PortEvent(p.getDpid(), p.getNumber() ));
1167 }
1168
1169 // TODO Is Device going to be in DB? If so, read from DB.
1170 // for (RCDevice d : RCDevice.getAllDevices()) {
1171 // DeviceEvent devEvent = new DeviceEvent( MACAddress.valueOf(d.getMac()) );
1172 // for (byte[] portId : d.getAllPortIds() ) {
1173 // devEvent.addAttachmentPoint( new SwitchPort( RCPort.getDpidFromKey(portId), RCPort.getNumberFromKey(portId) ));
1174 // }
1175 // }
1176
1177 for (RCLink l : RCLink.getAllLinks()) {
Yuta HIGUCHI0a4bd192014-02-17 13:52:34 -08001178 // TODO check if src/dst switch/port exist before triggering event
Yuta HIGUCHI76df2472014-02-12 22:36:51 -08001179 putLinkReplicationEvent( new LinkEvent(l.getSrc().dpid, l.getSrc().number, l.getDst().dpid, l.getDst().number));
1180 }
1181 }
Jonathan Hart062a2e82014-02-03 09:41:57 -08001182}