blob: 921907e4e2d4bdc031f02e8b09fba58e56d8226b [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;
11import java.util.concurrent.LinkedBlockingQueue;
Yuta HIGUCHI8d762e92014-02-12 14:10:25 -080012
Pavlin Radoslavov721a2e02014-02-14 23:40:14 -080013import net.onrc.onos.datagrid.IDatagridService;
14import net.onrc.onos.datagrid.IEventChannel;
15import net.onrc.onos.datagrid.IEventChannelListener;
Yuta HIGUCHI765cd0d2014-02-06 12:46:41 -080016import net.onrc.onos.datastore.topology.RCLink;
Jonathan Hart062a2e82014-02-03 09:41:57 -080017import net.onrc.onos.datastore.topology.RCPort;
18import net.onrc.onos.datastore.topology.RCSwitch;
Yuta HIGUCHI8d762e92014-02-12 14:10:25 -080019import net.onrc.onos.ofcontroller.networkgraph.PortEvent.SwitchPort;
Pavlin Radoslavov721a2e02014-02-14 23:40:14 -080020import net.onrc.onos.ofcontroller.util.EventEntry;
Yuta HIGUCHI765cd0d2014-02-06 12:46:41 -080021import net.onrc.onos.ofcontroller.util.Dpid;
Jonathan Hart062a2e82014-02-03 09:41:57 -080022
23import org.slf4j.Logger;
24import org.slf4j.LoggerFactory;
25
Yuta HIGUCHI181d34d2014-02-05 15:05:46 -080026/**
27 * The "NB" read-only Network Map.
28 *
Yuta HIGUCHI4bfdd532014-02-07 13:47:36 -080029 * - Maintain Invariant/Relationships between Topology Objects.
30 *
Yuta HIGUCHI765cd0d2014-02-06 12:46:41 -080031 * TODO To be synchronized based on TopologyEvent Notification.
Yuta HIGUCHI181d34d2014-02-05 15:05:46 -080032 *
Yuta HIGUCHIcb951982014-02-11 13:31:44 -080033 * TODO TBD: Caller is expected to maintain parent/child calling order. Parent
Yuta HIGUCHI1c700102014-02-12 16:30:52 -080034 * Object must exist before adding sub component(Add Switch -> Port).
Yuta HIGUCHIcb951982014-02-11 13:31:44 -080035 *
Yuta HIGUCHI4bfdd532014-02-07 13:47:36 -080036 * TODO TBD: This class may delay the requested change to handle event
37 * re-ordering. e.g.) Link Add came in, but Switch was not there.
Yuta HIGUCHIcb951982014-02-11 13:31:44 -080038 *
Yuta HIGUCHI181d34d2014-02-05 15:05:46 -080039 */
Yuta HIGUCHI928fa682014-02-11 19:07:57 -080040public class NetworkGraphImpl extends AbstractNetworkGraph implements
41 NetworkGraphDiscoveryInterface, NetworkGraphReplicationInterface {
Jonathan Hart062a2e82014-02-03 09:41:57 -080042
Yuta HIGUCHI80829d12014-02-05 20:16:56 -080043 private static final Logger log = LoggerFactory
44 .getLogger(NetworkGraphImpl.class);
Yuta HIGUCHIcd922f42014-02-11 18:59:11 -080045
Pavlin Radoslavov721a2e02014-02-14 23:40:14 -080046 private IEventChannel<byte[], TopologyEvent> eventChannel;
47 private static final String EVENT_CHANNEL_NAME = "onos.topology";
48 private EventHandler eventHandler = new EventHandler();
49
Jonathan Hart22eb9882014-02-11 15:52:59 -080050 private final NetworkGraphDatastore datastore;
Yuta HIGUCHI181d34d2014-02-05 15:05:46 -080051
Yuta HIGUCHI80829d12014-02-05 20:16:56 -080052 public NetworkGraphImpl() {
53 super();
Jonathan Hart22eb9882014-02-11 15:52:59 -080054 datastore = new NetworkGraphDatastore(this);
Yuta HIGUCHI80829d12014-02-05 20:16:56 -080055 }
Yuta HIGUCHI181d34d2014-02-05 15:05:46 -080056
Yuta HIGUCHI4bfdd532014-02-07 13:47:36 -080057 /**
Pavlin Radoslavov721a2e02014-02-14 23:40:14 -080058 * Event handler class.
59 */
60 private class EventHandler extends Thread implements
61 IEventChannelListener<byte[], TopologyEvent> {
62 private BlockingQueue<EventEntry<TopologyEvent>> topologyEvents =
63 new LinkedBlockingQueue<EventEntry<TopologyEvent>>();
64
65 /**
66 * Startup processing.
67 */
68 private void startup() {
69 //
70 // TODO: Read all state from the database
71 // For now, as a shortcut we read it from the datagrid
72 //
73 Collection<TopologyEvent> topologyEvents =
74 eventChannel.getAllEntries();
75 Collection<EventEntry<TopologyEvent>> collection =
76 new LinkedList<EventEntry<TopologyEvent>>();
77
78 for (TopologyEvent topologyEvent : topologyEvents) {
79 EventEntry<TopologyEvent> eventEntry =
80 new EventEntry<TopologyEvent>(EventEntry.Type.ENTRY_ADD,
81 topologyEvent);
82 collection.add(eventEntry);
83 }
84 processEvents(collection);
85 }
86
87 /**
88 * Run the thread.
89 */
Yuta HIGUCHI240bf072014-02-17 10:55:21 -080090 @Override
Pavlin Radoslavov721a2e02014-02-14 23:40:14 -080091 public void run() {
92 Collection<EventEntry<TopologyEvent>> collection =
93 new LinkedList<EventEntry<TopologyEvent>>();
94
95 this.setName("NetworkGraphImpl.EventHandler " + this.getId());
96 startup();
97
98 //
99 // The main loop
100 //
101 try {
102 while (true) {
103 EventEntry<TopologyEvent> eventEntry = topologyEvents.take();
104 collection.add(eventEntry);
105 topologyEvents.drainTo(collection);
106
107 processEvents(collection);
108 collection.clear();
109 }
110 } catch (Exception exception) {
111 log.debug("Exception processing Topology Events: ", exception);
112 }
113 }
114
115 /**
116 * Process all topology events.
117 *
118 * @param events the events to process.
119 */
120 private void processEvents(Collection<EventEntry<TopologyEvent>> events) {
121 for (EventEntry<TopologyEvent> event : events) {
122 TopologyEvent topologyEvent = event.eventData();
123 switch (event.eventType()) {
124 case ENTRY_ADD:
125 log.debug("Topology event ENTRY_ADD: {}", topologyEvent);
126 if (topologyEvent.switchEvent != null)
127 putSwitchReplicationEvent(topologyEvent.switchEvent);
128 if (topologyEvent.portEvent != null)
129 putPortReplicationEvent(topologyEvent.portEvent);
130 if (topologyEvent.linkEvent != null)
131 putLinkReplicationEvent(topologyEvent.linkEvent);
132 if (topologyEvent.deviceEvent != null)
133 putDeviceReplicationEvent(topologyEvent.deviceEvent);
134 break;
135 case ENTRY_REMOVE:
136 log.debug("Topology event ENTRY_REMOVE: {}", topologyEvent);
137 if (topologyEvent.switchEvent != null)
138 removeSwitchReplicationEvent(topologyEvent.switchEvent);
139 if (topologyEvent.portEvent != null)
140 removePortReplicationEvent(topologyEvent.portEvent);
141 if (topologyEvent.linkEvent != null)
142 removeLinkReplicationEvent(topologyEvent.linkEvent);
143 if (topologyEvent.deviceEvent != null)
144 removeDeviceReplicationEvent(topologyEvent.deviceEvent);
145 break;
146 }
147 }
148 }
149
150 /**
151 * Receive a notification that an entry is added.
152 *
153 * @param value the value for the entry.
154 */
155 @Override
156 public void entryAdded(TopologyEvent value) {
157 EventEntry<TopologyEvent> eventEntry =
158 new EventEntry<TopologyEvent>(EventEntry.Type.ENTRY_ADD,
159 value);
160 topologyEvents.add(eventEntry);
161 }
162
163 /**
164 * Receive a notification that an entry is removed.
165 *
166 * @param value the value for the entry.
167 */
168 @Override
169 public void entryRemoved(TopologyEvent value) {
170 EventEntry<TopologyEvent> eventEntry =
171 new EventEntry<TopologyEvent>(EventEntry.Type.ENTRY_REMOVE,
172 value);
173 topologyEvents.add(eventEntry);
174 }
175
176 /**
177 * Receive a notification that an entry is updated.
178 *
179 * @param value the value for the entry.
180 */
181 @Override
182 public void entryUpdated(TopologyEvent value) {
183 // NOTE: The ADD and UPDATE events are processed in same way
184 entryAdded(value);
185 }
186 }
187
188 /**
189 * Startup processing.
190 *
191 * @param datagridService the datagrid service to use.
192 */
193 void startup(IDatagridService datagridService) {
194 eventChannel = datagridService.addListener(EVENT_CHANNEL_NAME,
195 eventHandler,
196 byte[].class,
197 TopologyEvent.class);
198 eventHandler.start();
199 }
200
201 /**
Yuta HIGUCHIcb951982014-02-11 13:31:44 -0800202 * Exception to be thrown when Modification to the Network Graph cannot be continued due to broken invariant.
203 *
204 * XXX Should this be checked exception or RuntimeException
205 */
206 public static class BrokenInvariantException extends RuntimeException {
207 private static final long serialVersionUID = 1L;
208
209 public BrokenInvariantException() {
210 super();
211 }
212
213 public BrokenInvariantException(String message) {
214 super(message);
215 }
216 }
Jonathan Hart22eb9882014-02-11 15:52:59 -0800217
218 /* ******************************
219 * NetworkGraphDiscoveryInterface methods
220 * ******************************/
Yuta HIGUCHIcd922f42014-02-11 18:59:11 -0800221
Jonathan Hart22eb9882014-02-11 15:52:59 -0800222 @Override
223 public void putSwitchEvent(SwitchEvent switchEvent) {
Yuta HIGUCHId02e9282014-02-12 09:24:41 -0800224 if (prepareForAddSwitchEvent(switchEvent)) {
Jonathan Hart22eb9882014-02-11 15:52:59 -0800225 datastore.addSwitch(switchEvent);
226 putSwitch(switchEvent);
Pavlin Radoslavov721a2e02014-02-14 23:40:14 -0800227 // Send out notification
228 TopologyEvent topologyEvent =
229 new TopologyEvent(switchEvent);
230 eventChannel.addEntry(topologyEvent.getID(),
231 topologyEvent);
Jonathan Hart22eb9882014-02-11 15:52:59 -0800232 }
233 // TODO handle invariant violation
234 }
235
236 @Override
237 public void removeSwitchEvent(SwitchEvent switchEvent) {
Yuta HIGUCHId02e9282014-02-12 09:24:41 -0800238 if (prepareForRemoveSwitchEvent(switchEvent)) {
Jonathan Hart22eb9882014-02-11 15:52:59 -0800239 datastore.deactivateSwitch(switchEvent);
240 removeSwitch(switchEvent);
Pavlin Radoslavov721a2e02014-02-14 23:40:14 -0800241 // Send out notification
242 eventChannel.removeEntry(switchEvent.getID());
Jonathan Hart22eb9882014-02-11 15:52:59 -0800243 }
244 // TODO handle invariant violation
245 }
246
247 @Override
248 public void putPortEvent(PortEvent portEvent) {
Jonathan Hart4c263272014-02-13 17:41:05 -0800249 if (prepareForAddPortEvent(portEvent)) {
250 datastore.addPort(portEvent);
251 putPort(portEvent);
Pavlin Radoslavov721a2e02014-02-14 23:40:14 -0800252 // Send out notification
253 TopologyEvent topologyEvent =
254 new TopologyEvent(portEvent);
255 eventChannel.addEntry(topologyEvent.getID(),
256 topologyEvent);
Jonathan Hart4c263272014-02-13 17:41:05 -0800257 }
Yuta HIGUCHI75c51ed2014-02-13 17:02:26 -0800258 // TODO handle invariant violation
Jonathan Hart22eb9882014-02-11 15:52:59 -0800259 }
260
261 @Override
262 public void removePortEvent(PortEvent portEvent) {
Jonathan Hart4c263272014-02-13 17:41:05 -0800263 if (prepareForRemovePortEvent(portEvent)) {
264 datastore.deactivatePort(portEvent);
265 removePort(portEvent);
Pavlin Radoslavov721a2e02014-02-14 23:40:14 -0800266 // Send out notification
267 eventChannel.removeEntry(portEvent.getID());
Jonathan Hart4c263272014-02-13 17:41:05 -0800268 }
Yuta HIGUCHI75c51ed2014-02-13 17:02:26 -0800269 // TODO handle invariant violation
Jonathan Hart22eb9882014-02-11 15:52:59 -0800270 }
271
272 @Override
273 public void putLinkEvent(LinkEvent linkEvent) {
Yuta HIGUCHId02e9282014-02-12 09:24:41 -0800274 if (prepareForAddLinkEvent(linkEvent)) {
Jonathan Hart22eb9882014-02-11 15:52:59 -0800275 datastore.addLink(linkEvent);
276 putLink(linkEvent);
Pavlin Radoslavov721a2e02014-02-14 23:40:14 -0800277 // Send out notification
278 TopologyEvent topologyEvent =
279 new TopologyEvent(linkEvent);
280 eventChannel.addEntry(topologyEvent.getID(),
281 topologyEvent);
Jonathan Hart22eb9882014-02-11 15:52:59 -0800282 }
283 // TODO handle invariant violation
284 }
285
286 @Override
287 public void removeLinkEvent(LinkEvent linkEvent) {
Yuta HIGUCHId02e9282014-02-12 09:24:41 -0800288 if (prepareForRemoveLinkEvent(linkEvent)) {
Jonathan Hart22eb9882014-02-11 15:52:59 -0800289 datastore.removeLink(linkEvent);
290 removeLink(linkEvent);
Pavlin Radoslavov721a2e02014-02-14 23:40:14 -0800291 // Send out notification
292 eventChannel.removeEntry(linkEvent.getID());
Jonathan Hart22eb9882014-02-11 15:52:59 -0800293 }
294 // TODO handle invariant violation
295 }
296
297 @Override
Yuta HIGUCHI586d33e2014-02-13 17:05:08 -0800298 public void putDeviceEvent(DeviceEvent deviceEvent) {
299 if (prepareForAddDeviceEvent(deviceEvent)) {
300// datastore.addDevice(deviceEvent);
Yuta HIGUCHId457c052014-02-14 18:33:04 -0800301// putDevice(deviceEvent);
Pavlin Radoslavov721a2e02014-02-14 23:40:14 -0800302 // Send out notification
303 TopologyEvent topologyEvent =
304 new TopologyEvent(deviceEvent);
305 eventChannel.addEntry(topologyEvent.getID(),
306 topologyEvent);
Yuta HIGUCHI586d33e2014-02-13 17:05:08 -0800307 }
308 // TODO handle invariant violation
309 // XXX if prepareFor~ method returned false, event should be dropped
Jonathan Hart22eb9882014-02-11 15:52:59 -0800310 }
311
312 @Override
313 public void removeDeviceEvent(DeviceEvent deviceEvent) {
Yuta HIGUCHI586d33e2014-02-13 17:05:08 -0800314 if (prepareForRemoveDeviceEvent(deviceEvent)) {
315// datastore.removeDevice(deviceEvent);
Yuta HIGUCHId457c052014-02-14 18:33:04 -0800316// removeDevice(deviceEvent);
Pavlin Radoslavov721a2e02014-02-14 23:40:14 -0800317 // Send out notification
318 eventChannel.removeEntry(deviceEvent.getID());
Yuta HIGUCHI586d33e2014-02-13 17:05:08 -0800319 }
320 // TODO handle invariant violation
321 // XXX if prepareFor~ method returned false, event should be dropped
Jonathan Hart22eb9882014-02-11 15:52:59 -0800322 }
Yuta HIGUCHIcd922f42014-02-11 18:59:11 -0800323
Jonathan Hart22eb9882014-02-11 15:52:59 -0800324 /* *****************
Yuta HIGUCHId02e9282014-02-12 09:24:41 -0800325 * Internal methods to maintain invariants of the network graph
Jonathan Hart22eb9882014-02-11 15:52:59 -0800326 * *****************/
Yuta HIGUCHIcd922f42014-02-11 18:59:11 -0800327
Yuta HIGUCHId02e9282014-02-12 09:24:41 -0800328 /**
329 *
330 * @param swEvt
331 * @return true if ready to accept event.
332 */
333 private boolean prepareForAddSwitchEvent(SwitchEvent swEvt) {
Yuta HIGUCHI76df2472014-02-12 22:36:51 -0800334 // No show stopping precondition
Yuta HIGUCHI8d762e92014-02-12 14:10:25 -0800335 // Prep: remove(deactivate) Ports on Switch, which is not on event
336 removePortsNotOnEvent(swEvt);
337 return true;
Jonathan Hart22eb9882014-02-11 15:52:59 -0800338 }
Yuta HIGUCHIcd922f42014-02-11 18:59:11 -0800339
Yuta HIGUCHId02e9282014-02-12 09:24:41 -0800340 private boolean prepareForRemoveSwitchEvent(SwitchEvent swEvt) {
Yuta HIGUCHI76df2472014-02-12 22:36:51 -0800341 // No show stopping precondition
Yuta HIGUCHI8d762e92014-02-12 14:10:25 -0800342 // Prep: remove(deactivate) Ports on Switch, which is not on event
343 // XXX may be remove switch should imply wipe all ports
344 removePortsNotOnEvent(swEvt);
345 return true;
346 }
Yuta HIGUCHId02e9282014-02-12 09:24:41 -0800347
Yuta HIGUCHI8d762e92014-02-12 14:10:25 -0800348 private void removePortsNotOnEvent(SwitchEvent swEvt) {
349 Switch sw = switches.get( swEvt.getDpid() );
350 if ( sw != null ) {
351 Set<Long> port_noOnEvent = new HashSet<>();
352 for( PortEvent portEvent : swEvt.getPorts()) {
353 port_noOnEvent.add(portEvent.getNumber());
354 }
355 // Existing ports not on event should be removed.
356 // TODO Should batch eventually for performance?
Jonathan Hart480c5572014-02-14 18:28:16 -0800357 List<Port> portsToRemove = new ArrayList<Port>();
Yuta HIGUCHI8d762e92014-02-12 14:10:25 -0800358 for( Port p : sw.getPorts() ) {
359 if ( !port_noOnEvent.contains(p.getNumber()) ) {
Jonathan Hart480c5572014-02-14 18:28:16 -0800360 //PortEvent rmEvent = new PortEvent(p.getSwitch().getDpid(), p.getNumber());
361 // calling Discovery removePort() API to wipe from DB, etc.
362 //removePortEvent(rmEvent);
Yuta HIGUCHI240bf072014-02-17 10:55:21 -0800363
Jonathan Hart480c5572014-02-14 18:28:16 -0800364 // We can't remove ports here because this will trigger a remove
365 // from the switch's port list, which we are currently iterating
366 // over.
367 portsToRemove.add(p);
368 }
369 }
370 for (Port p : portsToRemove) {
Yuta HIGUCHI8d762e92014-02-12 14:10:25 -0800371 PortEvent rmEvent = new PortEvent(p.getSwitch().getDpid(), p.getNumber());
372 // calling Discovery removePort() API to wipe from DB, etc.
373 removePortEvent(rmEvent);
Yuta HIGUCHI8d762e92014-02-12 14:10:25 -0800374 }
375 }
Jonathan Hart22eb9882014-02-11 15:52:59 -0800376 }
Yuta HIGUCHIcd922f42014-02-11 18:59:11 -0800377
Yuta HIGUCHId02e9282014-02-12 09:24:41 -0800378 private boolean prepareForAddPortEvent(PortEvent portEvt) {
Yuta HIGUCHId02e9282014-02-12 09:24:41 -0800379 // Parent Switch must exist
380 if ( getSwitch(portEvt.getDpid()) == null) {
381 return false;
382 }
383 // Prep: None
Jonathan Hart22eb9882014-02-11 15:52:59 -0800384 return true;
385 }
Yuta HIGUCHIcd922f42014-02-11 18:59:11 -0800386
Yuta HIGUCHId02e9282014-02-12 09:24:41 -0800387 private boolean prepareForRemovePortEvent(PortEvent portEvt) {
Yuta HIGUCHId02e9282014-02-12 09:24:41 -0800388 // Parent Switch must exist
Yuta HIGUCHI8d762e92014-02-12 14:10:25 -0800389 Switch sw = getSwitch(portEvt.getDpid());
390 if ( sw == null ) {
Yuta HIGUCHI88be0f22014-02-14 17:20:43 -0800391 log.debug("Switch already removed? {}", portEvt);
Yuta HIGUCHId02e9282014-02-12 09:24:41 -0800392 return false;
393 }
Yuta HIGUCHI8d762e92014-02-12 14:10:25 -0800394 Port port = sw.getPort(portEvt.getNumber());
395 if ( port == null ) {
396 log.debug("Port already removed? {}", portEvt);
397 // let it pass
398 return true;
399 }
400
401 // Prep: Remove Link and Device Attachment
Yuta HIGUCHI240bf072014-02-17 10:55:21 -0800402 ArrayList<DeviceEvent> deviceEvts = new ArrayList<>();
Yuta HIGUCHI8d762e92014-02-12 14:10:25 -0800403 for (Device device : port.getDevices()) {
Yuta HIGUCHI88be0f22014-02-14 17:20:43 -0800404 log.debug("Removing Device {} on Port {}", device, portEvt);
Yuta HIGUCHI8d762e92014-02-12 14:10:25 -0800405 DeviceEvent devEvt = new DeviceEvent(device.getMacAddress());
406 devEvt.addAttachmentPoint(new SwitchPort(port.getSwitch().getDpid(), port.getNumber()));
Yuta HIGUCHI240bf072014-02-17 10:55:21 -0800407 deviceEvts.add(devEvt);
408 }
409 for (DeviceEvent devEvt : deviceEvts) {
Yuta HIGUCHI8d762e92014-02-12 14:10:25 -0800410 // calling Discovery API to wipe from DB, etc.
411 removeDeviceEvent(devEvt);
412 }
Yuta HIGUCHI240bf072014-02-17 10:55:21 -0800413
Yuta HIGUCHI8d762e92014-02-12 14:10:25 -0800414 Set<Link> links = new HashSet<>();
415 links.add(port.getOutgoingLink());
416 links.add(port.getIncomingLink());
417 for ( Link link : links) {
418 if (link == null ) {
419 continue;
420 }
Yuta HIGUCHI88be0f22014-02-14 17:20:43 -0800421 log.debug("Removing Link {} on Port {}", link, portEvt);
Yuta HIGUCHI8d762e92014-02-12 14:10:25 -0800422 LinkEvent linkEvent = new LinkEvent(link.getSourceSwitchDpid(), link.getSourcePortNumber(), link.getDestinationSwitchDpid(), link.getDestinationPortNumber());
423 // calling Discovery API to wipe from DB, etc.
424 removeLinkEvent(linkEvent);
425 }
Jonathan Hart22eb9882014-02-11 15:52:59 -0800426 return true;
427 }
Yuta HIGUCHIcd922f42014-02-11 18:59:11 -0800428
Yuta HIGUCHId02e9282014-02-12 09:24:41 -0800429 private boolean prepareForAddLinkEvent(LinkEvent linkEvt) {
Yuta HIGUCHI8d762e92014-02-12 14:10:25 -0800430 // Src/Dst Switch must exist
431 Switch srcSw = getSwitch(linkEvt.getSrc().dpid);
432 Switch dstSw = getSwitch(linkEvt.getDst().dpid);
433 if ( srcSw == null || dstSw == null ) {
434 return false;
435 }
436 // Src/Dst Port must exist
437 Port srcPort = srcSw.getPort(linkEvt.getSrc().number);
Jonathan Hart4c263272014-02-13 17:41:05 -0800438 Port dstPort = dstSw.getPort(linkEvt.getDst().number);
Yuta HIGUCHI8d762e92014-02-12 14:10:25 -0800439 if ( srcPort == null || dstPort == null ) {
440 return false;
441 }
442
443 // Prep: remove Device attachment on both Ports
Yuta HIGUCHI240bf072014-02-17 10:55:21 -0800444 ArrayList<DeviceEvent> deviceEvents = new ArrayList<>();
Yuta HIGUCHI8d762e92014-02-12 14:10:25 -0800445 for (Device device : srcPort.getDevices()) {
446 DeviceEvent devEvt = new DeviceEvent(device.getMacAddress());
447 devEvt.addAttachmentPoint(new SwitchPort(srcPort.getSwitch().getDpid(), srcPort.getNumber()));
Yuta HIGUCHI240bf072014-02-17 10:55:21 -0800448 deviceEvents.add(devEvt);
Yuta HIGUCHI8d762e92014-02-12 14:10:25 -0800449 }
450 for (Device device : dstPort.getDevices()) {
451 DeviceEvent devEvt = new DeviceEvent(device.getMacAddress());
452 devEvt.addAttachmentPoint(new SwitchPort(dstPort.getSwitch().getDpid(), dstPort.getNumber()));
Yuta HIGUCHI240bf072014-02-17 10:55:21 -0800453 deviceEvents.add(devEvt);
454 }
455 for (DeviceEvent devEvt : deviceEvents) {
Yuta HIGUCHI8d762e92014-02-12 14:10:25 -0800456 // calling Discovery API to wipe from DB, etc.
457 removeDeviceEvent(devEvt);
458 }
459
460 return true;
Jonathan Hart22eb9882014-02-11 15:52:59 -0800461 }
Yuta HIGUCHIcd922f42014-02-11 18:59:11 -0800462
Yuta HIGUCHId02e9282014-02-12 09:24:41 -0800463 private boolean prepareForRemoveLinkEvent(LinkEvent linkEvt) {
Yuta HIGUCHI8d762e92014-02-12 14:10:25 -0800464 // Src/Dst Switch must exist
465 Switch srcSw = getSwitch(linkEvt.getSrc().dpid);
466 Switch dstSw = getSwitch(linkEvt.getDst().dpid);
467 if ( srcSw == null || dstSw == null ) {
Yuta HIGUCHI125c7df2014-02-14 12:28:10 -0800468 log.warn("Rejecting removeLink {} because switch doesn't exist", linkEvt);
Yuta HIGUCHI8d762e92014-02-12 14:10:25 -0800469 return false;
470 }
471 // Src/Dst Port must exist
472 Port srcPort = srcSw.getPort(linkEvt.getSrc().number);
Yuta HIGUCHI125c7df2014-02-14 12:28:10 -0800473 Port dstPort = dstSw.getPort(linkEvt.getDst().number);
Yuta HIGUCHI8d762e92014-02-12 14:10:25 -0800474 if ( srcPort == null || dstPort == null ) {
Yuta HIGUCHI125c7df2014-02-14 12:28:10 -0800475 log.warn("Rejecting removeLink {} because port doesn't exist", linkEvt);
Yuta HIGUCHI8d762e92014-02-12 14:10:25 -0800476 return false;
477 }
478
Yuta HIGUCHI125c7df2014-02-14 12:28:10 -0800479 Link link = srcPort.getOutgoingLink();
480
481 // Link is already gone, or different Link exist in memory
482 // XXX Check if we should reject or just accept these cases.
483 // it should be harmless to remove the Link on event from DB anyways
484 if (link == null ||
485 !link.getDestinationPortNumber().equals(linkEvt.getDst().number)
486 || !link.getDestinationSwitchDpid().equals(linkEvt.getDst().dpid)) {
487 log.warn("Rejecting removeLink {} because link doesn't exist", linkEvt);
488 return false;
489 }
Yuta HIGUCHI8d762e92014-02-12 14:10:25 -0800490 // Prep: None
491 return true;
Jonathan Hart22eb9882014-02-11 15:52:59 -0800492 }
Yuta HIGUCHIcd922f42014-02-11 18:59:11 -0800493
Yuta HIGUCHI8d762e92014-02-12 14:10:25 -0800494 /**
495 *
496 * @param deviceEvt Event will be modified to remove inapplicable attachemntPoints/ipAddress
497 * @return false if this event should be dropped.
498 */
Yuta HIGUCHId02e9282014-02-12 09:24:41 -0800499 private boolean prepareForAddDeviceEvent(DeviceEvent deviceEvt) {
Yuta HIGUCHI8d762e92014-02-12 14:10:25 -0800500 boolean preconditionBroken = false;
501 ArrayList<PortEvent.SwitchPort> failedSwitchPort = new ArrayList<>();
502 for ( PortEvent.SwitchPort swp : deviceEvt.getAttachmentPoints() ) {
Yuta HIGUCHId02e9282014-02-12 09:24:41 -0800503 // Attached Ports' Parent Switch must exist
Yuta HIGUCHI8d762e92014-02-12 14:10:25 -0800504 Switch sw = getSwitch(swp.dpid);
505 if ( sw == null ) {
506 preconditionBroken = true;
507 failedSwitchPort.add(swp);
508 continue;
509 }
Yuta HIGUCHId02e9282014-02-12 09:24:41 -0800510 // Attached Ports must exist
Yuta HIGUCHI8d762e92014-02-12 14:10:25 -0800511 Port port = sw.getPort(swp.number);
512 if ( port == null ) {
513 preconditionBroken = true;
514 failedSwitchPort.add(swp);
515 continue;
516 }
Yuta HIGUCHId02e9282014-02-12 09:24:41 -0800517 // Attached Ports must not have Link
Yuta HIGUCHI8d762e92014-02-12 14:10:25 -0800518 if ( port.getOutgoingLink() != null || port.getIncomingLink() != null ) {
519 preconditionBroken = true;
520 failedSwitchPort.add(swp);
521 continue;
522 }
523 }
Yuta HIGUCHId02e9282014-02-12 09:24:41 -0800524
Yuta HIGUCHI8d762e92014-02-12 14:10:25 -0800525 // Rewriting event to exclude failed attachmentPoint
526 // XXX Assumption behind this is that inapplicable device event should
527 // be dropped, not deferred. If we decide to defer Device event,
528 // rewriting can become a problem
529 List<SwitchPort> attachmentPoints = deviceEvt.getAttachmentPoints();
530 attachmentPoints.removeAll(failedSwitchPort);
531 deviceEvt.setAttachmentPoints(attachmentPoints);
532
533 if ( deviceEvt.getAttachmentPoints().isEmpty() && deviceEvt.getIpAddresses().isEmpty() ) {
Yuta HIGUCHI125c7df2014-02-14 12:28:10 -0800534 // return false to represent: Nothing left to do for this event. Caller should drop event
Yuta HIGUCHI8d762e92014-02-12 14:10:25 -0800535 return false;
536 }
537
538 // Should we return false to tell caller that the event was trimmed?
539 // if ( preconditionBroken ) {
540 // return false;
541 // }
542
543 return true;
Jonathan Hart22eb9882014-02-11 15:52:59 -0800544 }
Yuta HIGUCHIcd922f42014-02-11 18:59:11 -0800545
Yuta HIGUCHId02e9282014-02-12 09:24:41 -0800546 private boolean prepareForRemoveDeviceEvent(DeviceEvent deviceEvt) {
Yuta HIGUCHId02e9282014-02-12 09:24:41 -0800547 // No show stopping precondition?
548 // Prep: none
Jonathan Hart22eb9882014-02-11 15:52:59 -0800549 return true;
550 }
Yuta HIGUCHI928fa682014-02-11 19:07:57 -0800551
Yuta HIGUCHI76df2472014-02-12 22:36:51 -0800552 /* ******************************
553 * NetworkGraphReplicationInterface methods
554 * ******************************/
555
Yuta HIGUCHI928fa682014-02-11 19:07:57 -0800556 @Override
557 public void putSwitchReplicationEvent(SwitchEvent switchEvent) {
Yuta HIGUCHI9fc10ac2014-02-12 17:18:57 -0800558 if (prepareForAddSwitchEvent(switchEvent)) {
559 putSwitch(switchEvent);
560 }
561 // TODO handle invariant violation
Yuta HIGUCHI928fa682014-02-11 19:07:57 -0800562 }
563
564 @Override
565 public void removeSwitchReplicationEvent(SwitchEvent switchEvent) {
Yuta HIGUCHI9fc10ac2014-02-12 17:18:57 -0800566 if (prepareForRemoveSwitchEvent(switchEvent)) {
567 removeSwitch(switchEvent);
568 }
Yuta HIGUCHI125c7df2014-02-14 12:28:10 -0800569 // TODO handle invariant violation
Yuta HIGUCHI928fa682014-02-11 19:07:57 -0800570 }
571
572 @Override
573 public void putPortReplicationEvent(PortEvent portEvent) {
Yuta HIGUCHI9fc10ac2014-02-12 17:18:57 -0800574 if (prepareForAddPortEvent(portEvent)) {
575 putPort(portEvent);
576 }
Yuta HIGUCHI125c7df2014-02-14 12:28:10 -0800577 // TODO handle invariant violation
Yuta HIGUCHI928fa682014-02-11 19:07:57 -0800578 }
579
580 @Override
581 public void removePortReplicationEvent(PortEvent portEvent) {
Yuta HIGUCHI9fc10ac2014-02-12 17:18:57 -0800582 if (prepareForRemovePortEvent(portEvent)) {
583 removePort(portEvent);
584 }
Yuta HIGUCHI125c7df2014-02-14 12:28:10 -0800585 // TODO handle invariant violation
Yuta HIGUCHI928fa682014-02-11 19:07:57 -0800586 }
587
588 @Override
589 public void putLinkReplicationEvent(LinkEvent linkEvent) {
Yuta HIGUCHI9fc10ac2014-02-12 17:18:57 -0800590 if (prepareForAddLinkEvent(linkEvent)) {
591 putLink(linkEvent);
592 }
Yuta HIGUCHI125c7df2014-02-14 12:28:10 -0800593 // TODO handle invariant violation
Yuta HIGUCHI928fa682014-02-11 19:07:57 -0800594 }
595
596 @Override
597 public void removeLinkReplicationEvent(LinkEvent linkEvent) {
Yuta HIGUCHI9fc10ac2014-02-12 17:18:57 -0800598 if (prepareForRemoveLinkEvent(linkEvent)) {
599 removeLink(linkEvent);
600 }
Yuta HIGUCHI125c7df2014-02-14 12:28:10 -0800601 // TODO handle invariant violation
Yuta HIGUCHI928fa682014-02-11 19:07:57 -0800602 }
603
604 @Override
605 public void putDeviceReplicationEvent(DeviceEvent deviceEvent) {
Yuta HIGUCHI9fc10ac2014-02-12 17:18:57 -0800606 if (prepareForAddDeviceEvent(deviceEvent)) {
607 putDevice(deviceEvent);
608 }
Yuta HIGUCHI125c7df2014-02-14 12:28:10 -0800609 // TODO handle invariant violation
Yuta HIGUCHI928fa682014-02-11 19:07:57 -0800610 }
611
612 @Override
613 public void removeDeviceReplicationEvent(DeviceEvent deviceEvent) {
Yuta HIGUCHI9fc10ac2014-02-12 17:18:57 -0800614 if (prepareForRemoveDeviceEvent(deviceEvent)) {
615 removeDevice(deviceEvent);
616 }
Yuta HIGUCHI125c7df2014-02-14 12:28:10 -0800617 // TODO handle invariant violation
Yuta HIGUCHI928fa682014-02-11 19:07:57 -0800618 }
Yuta HIGUCHI76df2472014-02-12 22:36:51 -0800619
620 /* ************************************************
621 * Internal In-memory object mutation methods.
622 * ************************************************/
623
624 void putSwitch(SwitchEvent swEvt) {
625 if (swEvt == null) {
626 throw new IllegalArgumentException("Switch cannot be null");
627 }
628
629 Switch sw = switches.get(swEvt.getDpid());
630
631 if (sw == null) {
632 sw = new SwitchImpl(this, swEvt.getDpid());
633 Switch existing = switches.putIfAbsent(swEvt.getDpid(), sw);
634 if (existing != null) {
635 log.warn(
636 "Concurrent putSwitch not expected. Continuing updating {}",
637 existing);
638 sw = existing;
639 }
640 }
641
642 // Update when more attributes are added to Event object
643 // no attribute to update for now
644
645 // TODO handle child Port event properly for performance
646 for (PortEvent portEvt : swEvt.getPorts() ) {
647 putPort(portEvt);
648 }
649
650 }
651
652 void removeSwitch(SwitchEvent swEvt) {
653 if (swEvt == null) {
654 throw new IllegalArgumentException("Switch cannot be null");
655 }
656
657 // TODO handle child Port event properly for performance
658 for (PortEvent portEvt : swEvt.getPorts() ) {
659 removePort(portEvt);
660 }
661
662 Switch sw = switches.get(swEvt.getDpid());
663
664 if (sw == null) {
665 log.warn("Switch {} already removed, ignoring", swEvt);
666 return;
667 }
668
Yuta HIGUCHI317bf542014-02-17 11:02:39 -0800669 // remove all ports if there still exist
670 ArrayList<PortEvent> portsToRemove = new ArrayList<>();
671 for (Port port : sw.getPorts()) {
Yuta HIGUCHI76df2472014-02-12 22:36:51 -0800672 log.warn(
Yuta HIGUCHI317bf542014-02-17 11:02:39 -0800673 "Port {} on Switch {} should be removed prior to removing Switch. Removing Port now",
674 port, swEvt);
675 PortEvent portEvt = new PortEvent(port.getDpid(), port.getNumber());
676 portsToRemove.add(portEvt);
Yuta HIGUCHI76df2472014-02-12 22:36:51 -0800677 }
Yuta HIGUCHI317bf542014-02-17 11:02:39 -0800678 for (PortEvent portEvt : portsToRemove ) {
679 // XXX calling removePortEvent() may trigger duplicate event, once at prepare phase, second time here
680 // If event can be squashed, ignored etc. at receiver side it shouldn't be a problem, but if not
681 // need to re-visit this issue.
682
683 // Note: removePortEvent() implies removal of attached Device, etc.
684 // if we decide not to call removePortEvent(), Device needs to be handled properly
685 removePortEvent(portEvt);
Yuta HIGUCHI76df2472014-02-12 22:36:51 -0800686 }
687
688 boolean removed = switches.remove(swEvt.getDpid(), sw);
689 if (removed) {
690 log.warn(
691 "Switch instance was replaced concurrently while removing {}. Something is not right.",
692 sw);
693 }
694 }
695
696 void putPort(PortEvent portEvt) {
697 if (portEvt == null) {
698 throw new IllegalArgumentException("Port cannot be null");
699 }
700 Switch sw = switches.get(portEvt.getDpid());
701 if (sw == null) {
702 throw new BrokenInvariantException(String.format(
703 "Switch with dpid %s did not exist.",
704 new Dpid(portEvt.getDpid())));
705 }
706 Port p = sw.getPort(portEvt.getNumber());
707 PortImpl port = null;
708 if (p != null) {
709 port = getPortImpl(p);
710 }
711
712 if (port == null) {
713 port = new PortImpl(this, sw, portEvt.getNumber());
714 }
715
716 // TODO update attributes
717
718 SwitchImpl s = getSwitchImpl(sw);
719 s.addPort(port);
720 }
721
722 void removePort(PortEvent portEvt) {
723 if (portEvt == null) {
724 throw new IllegalArgumentException("Port cannot be null");
725 }
726
727 Switch sw = switches.get(portEvt.getDpid());
728 if (sw == null) {
729 log.warn("Parent Switch for Port {} already removed, ignoring", portEvt);
730 return;
731 }
732
733 Port p = sw.getPort(portEvt.getNumber());
734 if (p == null) {
735 log.warn("Port {} already removed, ignoring", portEvt);
736 return;
737 }
738
Yuta HIGUCHIde040642014-02-17 11:03:39 -0800739 // Remove Link and Device Attachment
740 for (Device device : p.getDevices()) {
741 log.debug("Removing Device {} on Port {}", device, portEvt);
742 DeviceEvent devEvt = new DeviceEvent(device.getMacAddress());
743 devEvt.addAttachmentPoint(new SwitchPort(p.getSwitch().getDpid(), p.getNumber()));
Yuta HIGUCHI76df2472014-02-12 22:36:51 -0800744
Yuta HIGUCHIde040642014-02-17 11:03:39 -0800745 // XXX calling removeDeviceEvent() may trigger duplicate event, once at prepare phase, second time here
746 // If event can be squashed, ignored etc. at receiver side it shouldn't be a problem, but if not
747 // need to re-visit
748
749 // calling Discovery API to wipe from DB, etc.
750 removeDeviceEvent(devEvt);
Yuta HIGUCHI76df2472014-02-12 22:36:51 -0800751 }
Yuta HIGUCHIde040642014-02-17 11:03:39 -0800752 Set<Link> links = new HashSet<>();
753 links.add(p.getOutgoingLink());
754 links.add(p.getIncomingLink());
755 ArrayList<LinkEvent> linksToRemove = new ArrayList<>();
756 for (Link link : links) {
757 if (link == null) {
758 continue;
759 }
760 log.debug("Removing Link {} on Port {}", link, portEvt);
761 LinkEvent linkEvent = new LinkEvent(link.getSourceSwitchDpid(), link.getSourcePortNumber(), link.getDestinationSwitchDpid(), link.getDestinationPortNumber());
762 linksToRemove.add(linkEvent);
Yuta HIGUCHI76df2472014-02-12 22:36:51 -0800763 }
Yuta HIGUCHIde040642014-02-17 11:03:39 -0800764 for (LinkEvent linkEvent : linksToRemove) {
765 // XXX calling removeLinkEvent() may trigger duplicate event, once at prepare phase, second time here
766 // If event can be squashed, ignored etc. at receiver side it shouldn't be a problem, but if not
767 // need to re-visit
768
769 // calling Discovery API to wipe from DB, etc.
770 removeLinkEvent(linkEvent);
Yuta HIGUCHI76df2472014-02-12 22:36:51 -0800771 }
772
773 // remove Port from Switch
774 SwitchImpl s = getSwitchImpl(sw);
775 s.removePort(p);
776 }
777
778 void putLink(LinkEvent linkEvt) {
779 if (linkEvt == null) {
780 throw new IllegalArgumentException("Link cannot be null");
781 }
782
783 Switch srcSw = switches.get(linkEvt.getSrc().dpid);
784 if (srcSw == null) {
785 throw new BrokenInvariantException(
786 String.format(
787 "Switch with dpid %s did not exist.",
788 new Dpid(linkEvt.getSrc().dpid)));
789 }
790
791 Switch dstSw = switches.get(linkEvt.getDst().dpid);
792 if (dstSw == null) {
793 throw new BrokenInvariantException(
794 String.format(
795 "Switch with dpid %s did not exist.",
796 new Dpid(linkEvt.getDst().dpid)));
797 }
798
799 Port srcPort = srcSw.getPort(linkEvt.getSrc().number);
800 if (srcPort == null) {
801 throw new BrokenInvariantException(
802 String.format(
803 "Src Port %s of a Link did not exist.",
804 linkEvt.getSrc() ));
805 }
806
807 Port dstPort = dstSw.getPort(linkEvt.getDst().number);
808 if (dstPort == null) {
809 throw new BrokenInvariantException(
810 String.format(
811 "Dst Port %s of a Link did not exist.",
812 linkEvt.getDst() ));
813 }
814
815 // getting Link instance from destination port incoming Link
816 Link l = dstPort.getIncomingLink();
817 LinkImpl link = null;
818 assert( l == srcPort.getOutgoingLink() );
819 if (l != null) {
820 link = getLinkImpl(l);
821 }
822
823 if (link == null) {
824 link = new LinkImpl(this, srcPort, dstPort);
825 }
826
827
828 PortImpl dstPortMem = getPortImpl(dstPort);
829 PortImpl srcPortMem = getPortImpl(srcPort);
830
831 // Add Link first to avoid further Device addition
832
833 // add Link to Port
834 dstPortMem.setIncomingLink(link);
835 srcPortMem.setOutgoingLink(link);
836
837 // remove Device Pointing to Port if any
838 for(Device d : dstPortMem.getDevices() ) {
839 log.error("Device {} on Port {} should have been removed prior to adding Link {}", d, dstPort, linkEvt);
840 DeviceImpl dev = getDeviceImpl(d);
841 dev.removeAttachmentPoint(dstPort);
Yuta HIGUCHI407261a2014-02-13 16:34:06 -0800842 // This implies that change is made to Device Object.
843 // sending Device attachment point removed event
844 DeviceEvent rmEvent = new DeviceEvent(d.getMacAddress());
845 rmEvent.addAttachmentPoint(new SwitchPort(dstPort.getDpid(), dstPort.getNumber()));
846 removeDeviceEvent(rmEvent);
Yuta HIGUCHI76df2472014-02-12 22:36:51 -0800847 }
848 dstPortMem.removeAllDevice();
849 for(Device d : srcPortMem.getDevices() ) {
850 log.error("Device {} on Port {} should have been removed prior to adding Link {}", d, srcPort, linkEvt);
851 DeviceImpl dev = getDeviceImpl(d);
852 dev.removeAttachmentPoint(srcPort);
Yuta HIGUCHI407261a2014-02-13 16:34:06 -0800853 // This implies that change is made to Device Object.
854 // sending Device attachment point removed event
855 DeviceEvent rmEvent = new DeviceEvent(d.getMacAddress());
856 rmEvent.addAttachmentPoint(new SwitchPort(dstPort.getDpid(), dstPort.getNumber()));
857 removeDeviceEvent(rmEvent);
Yuta HIGUCHI76df2472014-02-12 22:36:51 -0800858 }
859 srcPortMem.removeAllDevice();
860
861 }
862
863 void removeLink(LinkEvent linkEvt) {
864 if (linkEvt == null) {
865 throw new IllegalArgumentException("Link cannot be null");
866 }
867
868 Switch srcSw = switches.get(linkEvt.getSrc().dpid);
869 if (srcSw == null) {
870 log.warn("Src Switch for Link {} already removed, ignoring", linkEvt);
871 return;
872 }
873
874 Switch dstSw = switches.get(linkEvt.getDst().dpid);
875 if (dstSw == null) {
876 log.warn("Dst Switch for Link {} already removed, ignoring", linkEvt);
877 return;
878 }
879
880 Port srcPort = srcSw.getPort(linkEvt.getSrc().number);
881 if (srcPort == null) {
882 log.warn("Src Port for Link {} already removed, ignoring", linkEvt);
883 return;
884 }
885
886 Port dstPort = dstSw.getPort(linkEvt.getDst().number);
887 if (dstPort == null) {
888 log.warn("Dst Port for Link {} already removed, ignoring", linkEvt);
889 return;
890 }
891
892 Link l = dstPort.getIncomingLink();
893 if ( l == null ) {
894 log.warn("Link {} already removed on destination Port", linkEvt);
895 }
896 l = srcPort.getOutgoingLink();
897 if ( l == null ) {
898 log.warn("Link {} already removed on src Port", linkEvt);
899 }
900
901 getPortImpl(dstPort).setIncomingLink(null);
902 getPortImpl(srcPort).setOutgoingLink(null);
903 }
904
905 // XXX Need to rework Device related
906 void putDevice(DeviceEvent deviceEvt) {
907 if (deviceEvt == null) {
908 throw new IllegalArgumentException("Device cannot be null");
909 }
910
911 Device device = getDeviceByMac(deviceEvt.getMac());
912 if ( device == null ) {
913 device = new DeviceImpl(this, deviceEvt.getMac());
914 Device existing = mac2Device.putIfAbsent(deviceEvt.getMac(), device);
915 if (existing != null) {
916 log.warn(
917 "Concurrent putDevice seems to be in action. Continuing updating {}",
918 existing);
919 device = existing;
920 }
921 }
922 DeviceImpl memDevice = getDeviceImpl(device);
923
924 // for each attachment point
925 for (SwitchPort swp : deviceEvt.getAttachmentPoints() ) {
926 // Attached Ports' Parent Switch must exist
927 Switch sw = getSwitch(swp.dpid);
928 if ( sw == null ) {
Yuta HIGUCHI25719052014-02-13 14:42:06 -0800929 log.warn("Switch for the attachment point {} did not exist. skipping mutation", swp);
Yuta HIGUCHI76df2472014-02-12 22:36:51 -0800930 continue;
931 }
932 // Attached Ports must exist
933 Port port = sw.getPort(swp.number);
934 if ( port == null ) {
Yuta HIGUCHI25719052014-02-13 14:42:06 -0800935 log.warn("Port for the attachment point {} did not exist. skipping mutation", swp);
Yuta HIGUCHI76df2472014-02-12 22:36:51 -0800936 continue;
937 }
938 // Attached Ports must not have Link
939 if ( port.getOutgoingLink() != null || port.getIncomingLink() != null ) {
940 log.warn("Link (Out:{},In:{}) exist on the attachment point, skipping mutation.", port.getOutgoingLink(), port.getIncomingLink());
941 continue;
942 }
943
944 // finally add Device <-> Port on In-memory structure
945 PortImpl memPort = getPortImpl(port);
946 memPort.addDevice(device);
947 memDevice.addAttachmentPoint(port);
948 }
949
950 // for each IP address
951 for( InetAddress ipAddr : deviceEvt.getIpAddresses() ) {
952 // Add Device -> IP
953 memDevice.addIpAddress(ipAddr);
954
955 // Add IP -> Set<Device>
956 boolean updated = false;
957 do {
958 Set<Device> devices = this.addr2Device.get(ipAddr);
959 if ( devices == null ) {
960 devices = new HashSet<>();
961 Set<Device> existing = this.addr2Device.putIfAbsent(ipAddr, devices);
962 if ( existing == null ) {
963 // success
964 updated = true;
965 }
966 } else {
967 Set<Device> updateDevices = new HashSet<>(devices);
968 updateDevices.add(device);
969 updated = this.addr2Device.replace(ipAddr, devices, updateDevices);
970 }
971 if (!updated) {
972 log.debug("Collision detected, updating IP to Device mapping retrying.");
973 }
974 } while( !updated );
975 }
976 }
977
978 void removeDevice(DeviceEvent deviceEvt) {
979 if (deviceEvt == null) {
980 throw new IllegalArgumentException("Device cannot be null");
981 }
982
983 Device device = getDeviceByMac(deviceEvt.getMac());
984 if ( device == null ) {
985 log.warn("Device {} already removed, ignoring", deviceEvt);
986 return;
987 }
988 DeviceImpl memDevice = getDeviceImpl(device);
989
990 // for each attachment point
991 for (SwitchPort swp : deviceEvt.getAttachmentPoints() ) {
992 // Attached Ports' Parent Switch must exist
993 Switch sw = getSwitch(swp.dpid);
994 if ( sw == null ) {
Yuta HIGUCHI25719052014-02-13 14:42:06 -0800995 log.warn("Switch for the attachment point {} did not exist. skipping attachment point mutation", swp);
Yuta HIGUCHI76df2472014-02-12 22:36:51 -0800996 continue;
997 }
998 // Attached Ports must exist
999 Port port = sw.getPort(swp.number);
1000 if ( port == null ) {
Yuta HIGUCHI25719052014-02-13 14:42:06 -08001001 log.warn("Port for the attachment point {} did not exist. skipping attachment point mutation", swp);
Yuta HIGUCHI76df2472014-02-12 22:36:51 -08001002 continue;
1003 }
1004
1005 // finally remove Device <-> Port on In-memory structure
1006 PortImpl memPort = getPortImpl(port);
1007 memPort.removeDevice(device);
1008 memDevice.removeAttachmentPoint(port);
1009 }
1010
1011 // for each IP address
1012 for( InetAddress ipAddr : deviceEvt.getIpAddresses() ) {
1013 // Remove Device -> IP
1014 memDevice.removeIpAddress(ipAddr);
1015
1016 // Remove IP -> Set<Device>
1017 boolean updated = false;
1018 do {
1019 Set<Device> devices = this.addr2Device.get(ipAddr);
1020 if ( devices == null ) {
1021 // already empty set, nothing to do
1022 updated = true;
1023 } else {
1024 Set<Device> updateDevices = new HashSet<>(devices);
1025 updateDevices.remove(device);
1026 updated = this.addr2Device.replace(ipAddr, devices, updateDevices);
1027 }
1028 if (!updated) {
1029 log.debug("Collision detected, updating IP to Device mapping retrying.");
1030 }
1031 } while( !updated );
1032 }
1033 }
1034
1035 private SwitchImpl getSwitchImpl(Switch sw) {
1036 if (sw instanceof SwitchImpl) {
1037 return (SwitchImpl) sw;
1038 }
1039 throw new ClassCastException("SwitchImpl expected, but found: " + sw);
1040 }
1041
1042 private PortImpl getPortImpl(Port p) {
1043 if (p instanceof PortImpl) {
1044 return (PortImpl) p;
1045 }
1046 throw new ClassCastException("PortImpl expected, but found: " + p);
1047 }
1048
1049 private LinkImpl getLinkImpl(Link l) {
1050 if (l instanceof LinkImpl) {
1051 return (LinkImpl) l;
1052 }
1053 throw new ClassCastException("LinkImpl expected, but found: " + l);
1054 }
1055
1056 private DeviceImpl getDeviceImpl(Device d) {
1057 if (d instanceof DeviceImpl) {
1058 return (DeviceImpl) d;
1059 }
1060 throw new ClassCastException("DeviceImpl expected, but found: " + d);
1061 }
1062
1063 @Deprecated
1064 public void loadWholeTopologyFromDB() {
1065 // XXX clear everything first?
1066
1067 for (RCSwitch sw : RCSwitch.getAllSwitches()) {
1068 if ( sw.getStatus() != RCSwitch.STATUS.ACTIVE ) {
1069 continue;
1070 }
1071 putSwitchReplicationEvent(new SwitchEvent(sw.getDpid()));
1072 }
1073
1074 for (RCPort p : RCPort.getAllPorts()) {
1075 if (p.getStatus() != RCPort.STATUS.ACTIVE) {
1076 continue;
1077 }
1078 putPortReplicationEvent(new PortEvent(p.getDpid(), p.getNumber() ));
1079 }
1080
1081 // TODO Is Device going to be in DB? If so, read from DB.
1082 // for (RCDevice d : RCDevice.getAllDevices()) {
1083 // DeviceEvent devEvent = new DeviceEvent( MACAddress.valueOf(d.getMac()) );
1084 // for (byte[] portId : d.getAllPortIds() ) {
1085 // devEvent.addAttachmentPoint( new SwitchPort( RCPort.getDpidFromKey(portId), RCPort.getNumberFromKey(portId) ));
1086 // }
1087 // }
1088
1089 for (RCLink l : RCLink.getAllLinks()) {
1090 putLinkReplicationEvent( new LinkEvent(l.getSrc().dpid, l.getSrc().number, l.getDst().dpid, l.getDst().number));
1091 }
1092 }
Jonathan Hart062a2e82014-02-03 09:41:57 -08001093}