blob: 8b6faebddfc8afc06fa11e756fb0518ce29cdf9a [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;
Yuta HIGUCHI170229f2014-02-17 15:47:54 -080022import net.onrc.onos.registry.controller.IControllerRegistryService;
Jonathan Hart062a2e82014-02-03 09:41:57 -080023
24import org.slf4j.Logger;
25import org.slf4j.LoggerFactory;
26
Yuta HIGUCHI181d34d2014-02-05 15:05:46 -080027/**
28 * The "NB" read-only Network Map.
29 *
Yuta HIGUCHI4bfdd532014-02-07 13:47:36 -080030 * - Maintain Invariant/Relationships between Topology Objects.
31 *
Yuta HIGUCHI765cd0d2014-02-06 12:46:41 -080032 * TODO To be synchronized based on TopologyEvent Notification.
Yuta HIGUCHI181d34d2014-02-05 15:05:46 -080033 *
Yuta HIGUCHIcb951982014-02-11 13:31:44 -080034 * TODO TBD: Caller is expected to maintain parent/child calling order. Parent
Yuta HIGUCHI1c700102014-02-12 16:30:52 -080035 * Object must exist before adding sub component(Add Switch -> Port).
Yuta HIGUCHIcb951982014-02-11 13:31:44 -080036 *
Yuta HIGUCHI4bfdd532014-02-07 13:47:36 -080037 * TODO TBD: This class may delay the requested change to handle event
38 * re-ordering. e.g.) Link Add came in, but Switch was not there.
Yuta HIGUCHIcb951982014-02-11 13:31:44 -080039 *
Yuta HIGUCHI181d34d2014-02-05 15:05:46 -080040 */
Yuta HIGUCHI928fa682014-02-11 19:07:57 -080041public class NetworkGraphImpl extends AbstractNetworkGraph implements
42 NetworkGraphDiscoveryInterface, NetworkGraphReplicationInterface {
Jonathan Hart062a2e82014-02-03 09:41:57 -080043
Yuta HIGUCHI80829d12014-02-05 20:16:56 -080044 private static final Logger log = LoggerFactory
45 .getLogger(NetworkGraphImpl.class);
Yuta HIGUCHIcd922f42014-02-11 18:59:11 -080046
Pavlin Radoslavov721a2e02014-02-14 23:40:14 -080047 private IEventChannel<byte[], TopologyEvent> eventChannel;
48 private static final String EVENT_CHANNEL_NAME = "onos.topology";
49 private EventHandler eventHandler = new EventHandler();
50
Jonathan Hart22eb9882014-02-11 15:52:59 -080051 private final NetworkGraphDatastore datastore;
Yuta HIGUCHI170229f2014-02-17 15:47:54 -080052 private final IControllerRegistryService registryService;
Yuta HIGUCHI181d34d2014-02-05 15:05:46 -080053
Yuta HIGUCHI170229f2014-02-17 15:47:54 -080054 public NetworkGraphImpl(IControllerRegistryService registryService) {
Yuta HIGUCHI80829d12014-02-05 20:16:56 -080055 super();
Jonathan Hart22eb9882014-02-11 15:52:59 -080056 datastore = new NetworkGraphDatastore(this);
Yuta HIGUCHI170229f2014-02-17 15:47:54 -080057 this.registryService = registryService;
Yuta HIGUCHI80829d12014-02-05 20:16:56 -080058 }
Yuta HIGUCHI181d34d2014-02-05 15:05:46 -080059
Yuta HIGUCHI4bfdd532014-02-07 13:47:36 -080060 /**
Pavlin Radoslavov721a2e02014-02-14 23:40:14 -080061 * Event handler class.
62 */
63 private class EventHandler extends Thread implements
64 IEventChannelListener<byte[], TopologyEvent> {
65 private BlockingQueue<EventEntry<TopologyEvent>> topologyEvents =
66 new LinkedBlockingQueue<EventEntry<TopologyEvent>>();
67
68 /**
69 * Startup processing.
70 */
71 private void startup() {
72 //
73 // TODO: Read all state from the database
74 // For now, as a shortcut we read it from the datagrid
75 //
76 Collection<TopologyEvent> topologyEvents =
77 eventChannel.getAllEntries();
78 Collection<EventEntry<TopologyEvent>> collection =
79 new LinkedList<EventEntry<TopologyEvent>>();
80
81 for (TopologyEvent topologyEvent : topologyEvents) {
82 EventEntry<TopologyEvent> eventEntry =
83 new EventEntry<TopologyEvent>(EventEntry.Type.ENTRY_ADD,
84 topologyEvent);
85 collection.add(eventEntry);
86 }
87 processEvents(collection);
88 }
89
90 /**
91 * Run the thread.
92 */
Yuta HIGUCHI240bf072014-02-17 10:55:21 -080093 @Override
Pavlin Radoslavov721a2e02014-02-14 23:40:14 -080094 public void run() {
95 Collection<EventEntry<TopologyEvent>> collection =
96 new LinkedList<EventEntry<TopologyEvent>>();
97
98 this.setName("NetworkGraphImpl.EventHandler " + this.getId());
99 startup();
100
101 //
102 // The main loop
103 //
104 try {
105 while (true) {
106 EventEntry<TopologyEvent> eventEntry = topologyEvents.take();
107 collection.add(eventEntry);
108 topologyEvents.drainTo(collection);
109
110 processEvents(collection);
111 collection.clear();
112 }
113 } catch (Exception exception) {
114 log.debug("Exception processing Topology Events: ", exception);
115 }
116 }
117
118 /**
119 * Process all topology events.
120 *
121 * @param events the events to process.
122 */
123 private void processEvents(Collection<EventEntry<TopologyEvent>> events) {
124 for (EventEntry<TopologyEvent> event : events) {
Yuta HIGUCHI170229f2014-02-17 15:47:54 -0800125 if (event.eventData().getOriginID().equals(registryService.getControllerId())) {
126 // ignore event triggered by myself
127 continue;
128 }
Pavlin Radoslavov721a2e02014-02-14 23:40:14 -0800129 TopologyEvent topologyEvent = event.eventData();
130 switch (event.eventType()) {
131 case ENTRY_ADD:
132 log.debug("Topology event ENTRY_ADD: {}", topologyEvent);
133 if (topologyEvent.switchEvent != null)
134 putSwitchReplicationEvent(topologyEvent.switchEvent);
135 if (topologyEvent.portEvent != null)
136 putPortReplicationEvent(topologyEvent.portEvent);
137 if (topologyEvent.linkEvent != null)
138 putLinkReplicationEvent(topologyEvent.linkEvent);
139 if (topologyEvent.deviceEvent != null)
140 putDeviceReplicationEvent(topologyEvent.deviceEvent);
141 break;
142 case ENTRY_REMOVE:
143 log.debug("Topology event ENTRY_REMOVE: {}", topologyEvent);
144 if (topologyEvent.switchEvent != null)
145 removeSwitchReplicationEvent(topologyEvent.switchEvent);
146 if (topologyEvent.portEvent != null)
147 removePortReplicationEvent(topologyEvent.portEvent);
148 if (topologyEvent.linkEvent != null)
149 removeLinkReplicationEvent(topologyEvent.linkEvent);
150 if (topologyEvent.deviceEvent != null)
151 removeDeviceReplicationEvent(topologyEvent.deviceEvent);
152 break;
153 }
154 }
155 }
156
157 /**
158 * Receive a notification that an entry is added.
159 *
160 * @param value the value for the entry.
161 */
162 @Override
163 public void entryAdded(TopologyEvent value) {
164 EventEntry<TopologyEvent> eventEntry =
165 new EventEntry<TopologyEvent>(EventEntry.Type.ENTRY_ADD,
166 value);
167 topologyEvents.add(eventEntry);
168 }
169
170 /**
171 * Receive a notification that an entry is removed.
172 *
173 * @param value the value for the entry.
174 */
175 @Override
176 public void entryRemoved(TopologyEvent value) {
177 EventEntry<TopologyEvent> eventEntry =
178 new EventEntry<TopologyEvent>(EventEntry.Type.ENTRY_REMOVE,
179 value);
180 topologyEvents.add(eventEntry);
181 }
182
183 /**
184 * Receive a notification that an entry is updated.
185 *
186 * @param value the value for the entry.
187 */
188 @Override
189 public void entryUpdated(TopologyEvent value) {
190 // NOTE: The ADD and UPDATE events are processed in same way
191 entryAdded(value);
192 }
193 }
194
195 /**
196 * Startup processing.
197 *
198 * @param datagridService the datagrid service to use.
199 */
200 void startup(IDatagridService datagridService) {
201 eventChannel = datagridService.addListener(EVENT_CHANNEL_NAME,
202 eventHandler,
203 byte[].class,
204 TopologyEvent.class);
205 eventHandler.start();
206 }
207
208 /**
Yuta HIGUCHIcb951982014-02-11 13:31:44 -0800209 * Exception to be thrown when Modification to the Network Graph cannot be continued due to broken invariant.
210 *
211 * XXX Should this be checked exception or RuntimeException
212 */
213 public static class BrokenInvariantException extends RuntimeException {
214 private static final long serialVersionUID = 1L;
215
216 public BrokenInvariantException() {
217 super();
218 }
219
220 public BrokenInvariantException(String message) {
221 super(message);
222 }
223 }
Jonathan Hart22eb9882014-02-11 15:52:59 -0800224
225 /* ******************************
226 * NetworkGraphDiscoveryInterface methods
227 * ******************************/
Yuta HIGUCHIcd922f42014-02-11 18:59:11 -0800228
Jonathan Hart22eb9882014-02-11 15:52:59 -0800229 @Override
230 public void putSwitchEvent(SwitchEvent switchEvent) {
Yuta HIGUCHId02e9282014-02-12 09:24:41 -0800231 if (prepareForAddSwitchEvent(switchEvent)) {
Jonathan Hart22eb9882014-02-11 15:52:59 -0800232 datastore.addSwitch(switchEvent);
233 putSwitch(switchEvent);
Pavlin Radoslavov721a2e02014-02-14 23:40:14 -0800234 // Send out notification
235 TopologyEvent topologyEvent =
Yuta HIGUCHI170229f2014-02-17 15:47:54 -0800236 new TopologyEvent(switchEvent, registryService.getControllerId());
Pavlin Radoslavov721a2e02014-02-14 23:40:14 -0800237 eventChannel.addEntry(topologyEvent.getID(),
238 topologyEvent);
Jonathan Hart22eb9882014-02-11 15:52:59 -0800239 }
240 // TODO handle invariant violation
241 }
242
243 @Override
244 public void removeSwitchEvent(SwitchEvent switchEvent) {
Yuta HIGUCHId02e9282014-02-12 09:24:41 -0800245 if (prepareForRemoveSwitchEvent(switchEvent)) {
Jonathan Hart22eb9882014-02-11 15:52:59 -0800246 datastore.deactivateSwitch(switchEvent);
247 removeSwitch(switchEvent);
Pavlin Radoslavov721a2e02014-02-14 23:40:14 -0800248 // Send out notification
249 eventChannel.removeEntry(switchEvent.getID());
Jonathan Hart22eb9882014-02-11 15:52:59 -0800250 }
251 // TODO handle invariant violation
252 }
253
254 @Override
255 public void putPortEvent(PortEvent portEvent) {
Jonathan Hart4c263272014-02-13 17:41:05 -0800256 if (prepareForAddPortEvent(portEvent)) {
257 datastore.addPort(portEvent);
258 putPort(portEvent);
Pavlin Radoslavov721a2e02014-02-14 23:40:14 -0800259 // Send out notification
260 TopologyEvent topologyEvent =
Yuta HIGUCHI170229f2014-02-17 15:47:54 -0800261 new TopologyEvent(portEvent, registryService.getControllerId());
Pavlin Radoslavov721a2e02014-02-14 23:40:14 -0800262 eventChannel.addEntry(topologyEvent.getID(),
263 topologyEvent);
Jonathan Hart4c263272014-02-13 17:41:05 -0800264 }
Yuta HIGUCHI75c51ed2014-02-13 17:02:26 -0800265 // TODO handle invariant violation
Jonathan Hart22eb9882014-02-11 15:52:59 -0800266 }
267
268 @Override
269 public void removePortEvent(PortEvent portEvent) {
Jonathan Hart4c263272014-02-13 17:41:05 -0800270 if (prepareForRemovePortEvent(portEvent)) {
271 datastore.deactivatePort(portEvent);
272 removePort(portEvent);
Pavlin Radoslavov721a2e02014-02-14 23:40:14 -0800273 // Send out notification
274 eventChannel.removeEntry(portEvent.getID());
Jonathan Hart4c263272014-02-13 17:41:05 -0800275 }
Yuta HIGUCHI75c51ed2014-02-13 17:02:26 -0800276 // TODO handle invariant violation
Jonathan Hart22eb9882014-02-11 15:52:59 -0800277 }
278
279 @Override
280 public void putLinkEvent(LinkEvent linkEvent) {
Yuta HIGUCHId02e9282014-02-12 09:24:41 -0800281 if (prepareForAddLinkEvent(linkEvent)) {
Jonathan Hart22eb9882014-02-11 15:52:59 -0800282 datastore.addLink(linkEvent);
283 putLink(linkEvent);
Pavlin Radoslavov721a2e02014-02-14 23:40:14 -0800284 // Send out notification
285 TopologyEvent topologyEvent =
Yuta HIGUCHI170229f2014-02-17 15:47:54 -0800286 new TopologyEvent(linkEvent, registryService.getControllerId());
Pavlin Radoslavov721a2e02014-02-14 23:40:14 -0800287 eventChannel.addEntry(topologyEvent.getID(),
288 topologyEvent);
Jonathan Hart22eb9882014-02-11 15:52:59 -0800289 }
290 // TODO handle invariant violation
291 }
292
293 @Override
294 public void removeLinkEvent(LinkEvent linkEvent) {
Yuta HIGUCHI0a4bd192014-02-17 13:52:34 -0800295 // TODO may need to distinguish internal event, which checks
296 // ownership of dst-dpid of this link, and only write to DB
297 // if it is owner of the dpid
Yuta HIGUCHId02e9282014-02-12 09:24:41 -0800298 if (prepareForRemoveLinkEvent(linkEvent)) {
Jonathan Hart22eb9882014-02-11 15:52:59 -0800299 datastore.removeLink(linkEvent);
300 removeLink(linkEvent);
Pavlin Radoslavov721a2e02014-02-14 23:40:14 -0800301 // Send out notification
302 eventChannel.removeEntry(linkEvent.getID());
Jonathan Hart22eb9882014-02-11 15:52:59 -0800303 }
304 // TODO handle invariant violation
305 }
306
307 @Override
Yuta HIGUCHI586d33e2014-02-13 17:05:08 -0800308 public void putDeviceEvent(DeviceEvent deviceEvent) {
309 if (prepareForAddDeviceEvent(deviceEvent)) {
310// datastore.addDevice(deviceEvent);
Yuta HIGUCHId457c052014-02-14 18:33:04 -0800311// putDevice(deviceEvent);
Pavlin Radoslavov721a2e02014-02-14 23:40:14 -0800312 // Send out notification
313 TopologyEvent topologyEvent =
Yuta HIGUCHI170229f2014-02-17 15:47:54 -0800314 new TopologyEvent(deviceEvent, registryService.getControllerId());
Pavlin Radoslavov721a2e02014-02-14 23:40:14 -0800315 eventChannel.addEntry(topologyEvent.getID(),
316 topologyEvent);
Yuta HIGUCHI586d33e2014-02-13 17:05:08 -0800317 }
318 // TODO handle invariant violation
319 // XXX if prepareFor~ method returned false, event should be dropped
Jonathan Hart22eb9882014-02-11 15:52:59 -0800320 }
321
322 @Override
323 public void removeDeviceEvent(DeviceEvent deviceEvent) {
Yuta HIGUCHI586d33e2014-02-13 17:05:08 -0800324 if (prepareForRemoveDeviceEvent(deviceEvent)) {
325// datastore.removeDevice(deviceEvent);
Yuta HIGUCHId457c052014-02-14 18:33:04 -0800326// removeDevice(deviceEvent);
Pavlin Radoslavov721a2e02014-02-14 23:40:14 -0800327 // Send out notification
328 eventChannel.removeEntry(deviceEvent.getID());
Yuta HIGUCHI586d33e2014-02-13 17:05:08 -0800329 }
330 // TODO handle invariant violation
331 // XXX if prepareFor~ method returned false, event should be dropped
Jonathan Hart22eb9882014-02-11 15:52:59 -0800332 }
Yuta HIGUCHIcd922f42014-02-11 18:59:11 -0800333
Jonathan Hart22eb9882014-02-11 15:52:59 -0800334 /* *****************
Yuta HIGUCHId02e9282014-02-12 09:24:41 -0800335 * Internal methods to maintain invariants of the network graph
Jonathan Hart22eb9882014-02-11 15:52:59 -0800336 * *****************/
Yuta HIGUCHIcd922f42014-02-11 18:59:11 -0800337
Yuta HIGUCHId02e9282014-02-12 09:24:41 -0800338 /**
339 *
340 * @param swEvt
341 * @return true if ready to accept event.
342 */
343 private boolean prepareForAddSwitchEvent(SwitchEvent swEvt) {
Yuta HIGUCHI76df2472014-02-12 22:36:51 -0800344 // No show stopping precondition
Yuta HIGUCHI8d762e92014-02-12 14:10:25 -0800345 // Prep: remove(deactivate) Ports on Switch, which is not on event
346 removePortsNotOnEvent(swEvt);
347 return true;
Jonathan Hart22eb9882014-02-11 15:52:59 -0800348 }
Yuta HIGUCHIcd922f42014-02-11 18:59:11 -0800349
Yuta HIGUCHId02e9282014-02-12 09:24:41 -0800350 private boolean prepareForRemoveSwitchEvent(SwitchEvent swEvt) {
Yuta HIGUCHI76df2472014-02-12 22:36:51 -0800351 // No show stopping precondition
Yuta HIGUCHI8d762e92014-02-12 14:10:25 -0800352 // Prep: remove(deactivate) Ports on Switch, which is not on event
353 // XXX may be remove switch should imply wipe all ports
354 removePortsNotOnEvent(swEvt);
355 return true;
356 }
Yuta HIGUCHId02e9282014-02-12 09:24:41 -0800357
Yuta HIGUCHI8d762e92014-02-12 14:10:25 -0800358 private void removePortsNotOnEvent(SwitchEvent swEvt) {
359 Switch sw = switches.get( swEvt.getDpid() );
360 if ( sw != null ) {
361 Set<Long> port_noOnEvent = new HashSet<>();
362 for( PortEvent portEvent : swEvt.getPorts()) {
363 port_noOnEvent.add(portEvent.getNumber());
364 }
365 // Existing ports not on event should be removed.
366 // TODO Should batch eventually for performance?
Jonathan Hart480c5572014-02-14 18:28:16 -0800367 List<Port> portsToRemove = new ArrayList<Port>();
Yuta HIGUCHI8d762e92014-02-12 14:10:25 -0800368 for( Port p : sw.getPorts() ) {
369 if ( !port_noOnEvent.contains(p.getNumber()) ) {
Jonathan Hart480c5572014-02-14 18:28:16 -0800370 //PortEvent rmEvent = new PortEvent(p.getSwitch().getDpid(), p.getNumber());
371 // calling Discovery removePort() API to wipe from DB, etc.
372 //removePortEvent(rmEvent);
Yuta HIGUCHI240bf072014-02-17 10:55:21 -0800373
Jonathan Hart480c5572014-02-14 18:28:16 -0800374 // We can't remove ports here because this will trigger a remove
375 // from the switch's port list, which we are currently iterating
376 // over.
377 portsToRemove.add(p);
378 }
379 }
380 for (Port p : portsToRemove) {
Yuta HIGUCHI8d762e92014-02-12 14:10:25 -0800381 PortEvent rmEvent = new PortEvent(p.getSwitch().getDpid(), p.getNumber());
382 // calling Discovery removePort() API to wipe from DB, etc.
383 removePortEvent(rmEvent);
Yuta HIGUCHI8d762e92014-02-12 14:10:25 -0800384 }
385 }
Jonathan Hart22eb9882014-02-11 15:52:59 -0800386 }
Yuta HIGUCHIcd922f42014-02-11 18:59:11 -0800387
Yuta HIGUCHId02e9282014-02-12 09:24:41 -0800388 private boolean prepareForAddPortEvent(PortEvent portEvt) {
Yuta HIGUCHId02e9282014-02-12 09:24:41 -0800389 // Parent Switch must exist
390 if ( getSwitch(portEvt.getDpid()) == null) {
391 return false;
392 }
393 // Prep: None
Jonathan Hart22eb9882014-02-11 15:52:59 -0800394 return true;
395 }
Yuta HIGUCHIcd922f42014-02-11 18:59:11 -0800396
Yuta HIGUCHId02e9282014-02-12 09:24:41 -0800397 private boolean prepareForRemovePortEvent(PortEvent portEvt) {
Yuta HIGUCHId02e9282014-02-12 09:24:41 -0800398 // Parent Switch must exist
Yuta HIGUCHI8d762e92014-02-12 14:10:25 -0800399 Switch sw = getSwitch(portEvt.getDpid());
400 if ( sw == null ) {
Yuta HIGUCHI88be0f22014-02-14 17:20:43 -0800401 log.debug("Switch already removed? {}", portEvt);
Yuta HIGUCHId02e9282014-02-12 09:24:41 -0800402 return false;
403 }
Yuta HIGUCHI8d762e92014-02-12 14:10:25 -0800404 Port port = sw.getPort(portEvt.getNumber());
405 if ( port == null ) {
406 log.debug("Port already removed? {}", portEvt);
407 // let it pass
408 return true;
409 }
410
411 // Prep: Remove Link and Device Attachment
Yuta HIGUCHI240bf072014-02-17 10:55:21 -0800412 ArrayList<DeviceEvent> deviceEvts = new ArrayList<>();
Yuta HIGUCHI8d762e92014-02-12 14:10:25 -0800413 for (Device device : port.getDevices()) {
Yuta HIGUCHI88be0f22014-02-14 17:20:43 -0800414 log.debug("Removing Device {} on Port {}", device, portEvt);
Yuta HIGUCHI8d762e92014-02-12 14:10:25 -0800415 DeviceEvent devEvt = new DeviceEvent(device.getMacAddress());
416 devEvt.addAttachmentPoint(new SwitchPort(port.getSwitch().getDpid(), port.getNumber()));
Yuta HIGUCHI240bf072014-02-17 10:55:21 -0800417 deviceEvts.add(devEvt);
418 }
419 for (DeviceEvent devEvt : deviceEvts) {
Yuta HIGUCHI8d762e92014-02-12 14:10:25 -0800420 // calling Discovery API to wipe from DB, etc.
421 removeDeviceEvent(devEvt);
422 }
Yuta HIGUCHI240bf072014-02-17 10:55:21 -0800423
Yuta HIGUCHI8d762e92014-02-12 14:10:25 -0800424 Set<Link> links = new HashSet<>();
425 links.add(port.getOutgoingLink());
426 links.add(port.getIncomingLink());
427 for ( Link link : links) {
428 if (link == null ) {
429 continue;
430 }
Yuta HIGUCHI88be0f22014-02-14 17:20:43 -0800431 log.debug("Removing Link {} on Port {}", link, portEvt);
Yuta HIGUCHI8d762e92014-02-12 14:10:25 -0800432 LinkEvent linkEvent = new LinkEvent(link.getSourceSwitchDpid(), link.getSourcePortNumber(), link.getDestinationSwitchDpid(), link.getDestinationPortNumber());
433 // calling Discovery API to wipe from DB, etc.
Yuta HIGUCHI0a4bd192014-02-17 13:52:34 -0800434 // XXX call internal remove Link, which will check
435 // ownership and modify only if it is the owner
Yuta HIGUCHI8d762e92014-02-12 14:10:25 -0800436 removeLinkEvent(linkEvent);
437 }
Jonathan Hart22eb9882014-02-11 15:52:59 -0800438 return true;
439 }
Yuta HIGUCHIcd922f42014-02-11 18:59:11 -0800440
Yuta HIGUCHId02e9282014-02-12 09:24:41 -0800441 private boolean prepareForAddLinkEvent(LinkEvent linkEvt) {
Yuta HIGUCHI8d762e92014-02-12 14:10:25 -0800442 // Src/Dst Switch must exist
443 Switch srcSw = getSwitch(linkEvt.getSrc().dpid);
444 Switch dstSw = getSwitch(linkEvt.getDst().dpid);
445 if ( srcSw == null || dstSw == null ) {
446 return false;
447 }
448 // Src/Dst Port must exist
449 Port srcPort = srcSw.getPort(linkEvt.getSrc().number);
Jonathan Hart4c263272014-02-13 17:41:05 -0800450 Port dstPort = dstSw.getPort(linkEvt.getDst().number);
Yuta HIGUCHI8d762e92014-02-12 14:10:25 -0800451 if ( srcPort == null || dstPort == null ) {
452 return false;
453 }
454
455 // Prep: remove Device attachment on both Ports
Yuta HIGUCHI240bf072014-02-17 10:55:21 -0800456 ArrayList<DeviceEvent> deviceEvents = new ArrayList<>();
Yuta HIGUCHI8d762e92014-02-12 14:10:25 -0800457 for (Device device : srcPort.getDevices()) {
458 DeviceEvent devEvt = new DeviceEvent(device.getMacAddress());
459 devEvt.addAttachmentPoint(new SwitchPort(srcPort.getSwitch().getDpid(), srcPort.getNumber()));
Yuta HIGUCHI240bf072014-02-17 10:55:21 -0800460 deviceEvents.add(devEvt);
Yuta HIGUCHI8d762e92014-02-12 14:10:25 -0800461 }
462 for (Device device : dstPort.getDevices()) {
463 DeviceEvent devEvt = new DeviceEvent(device.getMacAddress());
464 devEvt.addAttachmentPoint(new SwitchPort(dstPort.getSwitch().getDpid(), dstPort.getNumber()));
Yuta HIGUCHI240bf072014-02-17 10:55:21 -0800465 deviceEvents.add(devEvt);
466 }
467 for (DeviceEvent devEvt : deviceEvents) {
Yuta HIGUCHI8d762e92014-02-12 14:10:25 -0800468 // calling Discovery API to wipe from DB, etc.
469 removeDeviceEvent(devEvt);
470 }
471
472 return true;
Jonathan Hart22eb9882014-02-11 15:52:59 -0800473 }
Yuta HIGUCHIcd922f42014-02-11 18:59:11 -0800474
Yuta HIGUCHId02e9282014-02-12 09:24:41 -0800475 private boolean prepareForRemoveLinkEvent(LinkEvent linkEvt) {
Yuta HIGUCHI8d762e92014-02-12 14:10:25 -0800476 // Src/Dst Switch must exist
477 Switch srcSw = getSwitch(linkEvt.getSrc().dpid);
478 Switch dstSw = getSwitch(linkEvt.getDst().dpid);
479 if ( srcSw == null || dstSw == null ) {
Yuta HIGUCHI125c7df2014-02-14 12:28:10 -0800480 log.warn("Rejecting removeLink {} because switch doesn't exist", linkEvt);
Yuta HIGUCHI8d762e92014-02-12 14:10:25 -0800481 return false;
482 }
483 // Src/Dst Port must exist
484 Port srcPort = srcSw.getPort(linkEvt.getSrc().number);
Yuta HIGUCHI125c7df2014-02-14 12:28:10 -0800485 Port dstPort = dstSw.getPort(linkEvt.getDst().number);
Yuta HIGUCHI8d762e92014-02-12 14:10:25 -0800486 if ( srcPort == null || dstPort == null ) {
Yuta HIGUCHI125c7df2014-02-14 12:28:10 -0800487 log.warn("Rejecting removeLink {} because port doesn't exist", linkEvt);
Yuta HIGUCHI8d762e92014-02-12 14:10:25 -0800488 return false;
489 }
490
Yuta HIGUCHI125c7df2014-02-14 12:28:10 -0800491 Link link = srcPort.getOutgoingLink();
492
493 // Link is already gone, or different Link exist in memory
494 // XXX Check if we should reject or just accept these cases.
495 // it should be harmless to remove the Link on event from DB anyways
496 if (link == null ||
497 !link.getDestinationPortNumber().equals(linkEvt.getDst().number)
498 || !link.getDestinationSwitchDpid().equals(linkEvt.getDst().dpid)) {
499 log.warn("Rejecting removeLink {} because link doesn't exist", linkEvt);
500 return false;
501 }
Yuta HIGUCHI8d762e92014-02-12 14:10:25 -0800502 // Prep: None
503 return true;
Jonathan Hart22eb9882014-02-11 15:52:59 -0800504 }
Yuta HIGUCHIcd922f42014-02-11 18:59:11 -0800505
Yuta HIGUCHI8d762e92014-02-12 14:10:25 -0800506 /**
507 *
508 * @param deviceEvt Event will be modified to remove inapplicable attachemntPoints/ipAddress
509 * @return false if this event should be dropped.
510 */
Yuta HIGUCHId02e9282014-02-12 09:24:41 -0800511 private boolean prepareForAddDeviceEvent(DeviceEvent deviceEvt) {
Yuta HIGUCHI8d762e92014-02-12 14:10:25 -0800512 boolean preconditionBroken = false;
513 ArrayList<PortEvent.SwitchPort> failedSwitchPort = new ArrayList<>();
514 for ( PortEvent.SwitchPort swp : deviceEvt.getAttachmentPoints() ) {
Yuta HIGUCHId02e9282014-02-12 09:24:41 -0800515 // Attached Ports' Parent Switch must exist
Yuta HIGUCHI8d762e92014-02-12 14:10:25 -0800516 Switch sw = getSwitch(swp.dpid);
517 if ( sw == null ) {
518 preconditionBroken = true;
519 failedSwitchPort.add(swp);
520 continue;
521 }
Yuta HIGUCHId02e9282014-02-12 09:24:41 -0800522 // Attached Ports must exist
Yuta HIGUCHI8d762e92014-02-12 14:10:25 -0800523 Port port = sw.getPort(swp.number);
524 if ( port == null ) {
525 preconditionBroken = true;
526 failedSwitchPort.add(swp);
527 continue;
528 }
Yuta HIGUCHId02e9282014-02-12 09:24:41 -0800529 // Attached Ports must not have Link
Yuta HIGUCHI8d762e92014-02-12 14:10:25 -0800530 if ( port.getOutgoingLink() != null || port.getIncomingLink() != null ) {
531 preconditionBroken = true;
532 failedSwitchPort.add(swp);
533 continue;
534 }
535 }
Yuta HIGUCHId02e9282014-02-12 09:24:41 -0800536
Yuta HIGUCHI8d762e92014-02-12 14:10:25 -0800537 // Rewriting event to exclude failed attachmentPoint
538 // XXX Assumption behind this is that inapplicable device event should
539 // be dropped, not deferred. If we decide to defer Device event,
540 // rewriting can become a problem
541 List<SwitchPort> attachmentPoints = deviceEvt.getAttachmentPoints();
542 attachmentPoints.removeAll(failedSwitchPort);
543 deviceEvt.setAttachmentPoints(attachmentPoints);
544
545 if ( deviceEvt.getAttachmentPoints().isEmpty() && deviceEvt.getIpAddresses().isEmpty() ) {
Yuta HIGUCHI125c7df2014-02-14 12:28:10 -0800546 // return false to represent: Nothing left to do for this event. Caller should drop event
Yuta HIGUCHI8d762e92014-02-12 14:10:25 -0800547 return false;
548 }
549
550 // Should we return false to tell caller that the event was trimmed?
551 // if ( preconditionBroken ) {
552 // return false;
553 // }
554
555 return true;
Jonathan Hart22eb9882014-02-11 15:52:59 -0800556 }
Yuta HIGUCHIcd922f42014-02-11 18:59:11 -0800557
Yuta HIGUCHId02e9282014-02-12 09:24:41 -0800558 private boolean prepareForRemoveDeviceEvent(DeviceEvent deviceEvt) {
Yuta HIGUCHId02e9282014-02-12 09:24:41 -0800559 // No show stopping precondition?
560 // Prep: none
Jonathan Hart22eb9882014-02-11 15:52:59 -0800561 return true;
562 }
Yuta HIGUCHI928fa682014-02-11 19:07:57 -0800563
Yuta HIGUCHI76df2472014-02-12 22:36:51 -0800564 /* ******************************
565 * NetworkGraphReplicationInterface methods
566 * ******************************/
567
Yuta HIGUCHI928fa682014-02-11 19:07:57 -0800568 @Override
569 public void putSwitchReplicationEvent(SwitchEvent switchEvent) {
Yuta HIGUCHI9fc10ac2014-02-12 17:18:57 -0800570 if (prepareForAddSwitchEvent(switchEvent)) {
571 putSwitch(switchEvent);
572 }
573 // TODO handle invariant violation
Yuta HIGUCHI0a4bd192014-02-17 13:52:34 -0800574 // TODO trigger instance local topology event handler
Yuta HIGUCHI928fa682014-02-11 19:07:57 -0800575 }
576
577 @Override
578 public void removeSwitchReplicationEvent(SwitchEvent switchEvent) {
Yuta HIGUCHI9fc10ac2014-02-12 17:18:57 -0800579 if (prepareForRemoveSwitchEvent(switchEvent)) {
580 removeSwitch(switchEvent);
581 }
Yuta HIGUCHI125c7df2014-02-14 12:28:10 -0800582 // TODO handle invariant violation
Yuta HIGUCHI0a4bd192014-02-17 13:52:34 -0800583 // TODO trigger instance local topology event handler
Yuta HIGUCHI928fa682014-02-11 19:07:57 -0800584 }
585
586 @Override
587 public void putPortReplicationEvent(PortEvent portEvent) {
Yuta HIGUCHI9fc10ac2014-02-12 17:18:57 -0800588 if (prepareForAddPortEvent(portEvent)) {
589 putPort(portEvent);
590 }
Yuta HIGUCHI125c7df2014-02-14 12:28:10 -0800591 // TODO handle invariant violation
Yuta HIGUCHI0a4bd192014-02-17 13:52:34 -0800592 // TODO trigger instance local topology event handler
Yuta HIGUCHI928fa682014-02-11 19:07:57 -0800593 }
594
595 @Override
596 public void removePortReplicationEvent(PortEvent portEvent) {
Yuta HIGUCHI9fc10ac2014-02-12 17:18:57 -0800597 if (prepareForRemovePortEvent(portEvent)) {
598 removePort(portEvent);
599 }
Yuta HIGUCHI125c7df2014-02-14 12:28:10 -0800600 // TODO handle invariant violation
Yuta HIGUCHI0a4bd192014-02-17 13:52:34 -0800601 // TODO trigger instance local topology event handler
Yuta HIGUCHI928fa682014-02-11 19:07:57 -0800602 }
603
604 @Override
605 public void putLinkReplicationEvent(LinkEvent linkEvent) {
Yuta HIGUCHI9fc10ac2014-02-12 17:18:57 -0800606 if (prepareForAddLinkEvent(linkEvent)) {
607 putLink(linkEvent);
608 }
Yuta HIGUCHI125c7df2014-02-14 12:28:10 -0800609 // TODO handle invariant violation
Yuta HIGUCHI0a4bd192014-02-17 13:52:34 -0800610 // TODO trigger instance local topology event handler
Yuta HIGUCHI928fa682014-02-11 19:07:57 -0800611 }
612
613 @Override
614 public void removeLinkReplicationEvent(LinkEvent linkEvent) {
Yuta HIGUCHI9fc10ac2014-02-12 17:18:57 -0800615 if (prepareForRemoveLinkEvent(linkEvent)) {
616 removeLink(linkEvent);
617 }
Yuta HIGUCHI125c7df2014-02-14 12:28:10 -0800618 // TODO handle invariant violation
Yuta HIGUCHI0a4bd192014-02-17 13:52:34 -0800619 // TODO trigger instance local topology event handler
Yuta HIGUCHI928fa682014-02-11 19:07:57 -0800620 }
621
622 @Override
623 public void putDeviceReplicationEvent(DeviceEvent deviceEvent) {
Yuta HIGUCHI9fc10ac2014-02-12 17:18:57 -0800624 if (prepareForAddDeviceEvent(deviceEvent)) {
625 putDevice(deviceEvent);
626 }
Yuta HIGUCHI125c7df2014-02-14 12:28:10 -0800627 // TODO handle invariant violation
Yuta HIGUCHI0a4bd192014-02-17 13:52:34 -0800628 // TODO trigger instance local topology event handler
Yuta HIGUCHI928fa682014-02-11 19:07:57 -0800629 }
630
631 @Override
632 public void removeDeviceReplicationEvent(DeviceEvent deviceEvent) {
Yuta HIGUCHI9fc10ac2014-02-12 17:18:57 -0800633 if (prepareForRemoveDeviceEvent(deviceEvent)) {
634 removeDevice(deviceEvent);
635 }
Yuta HIGUCHI125c7df2014-02-14 12:28:10 -0800636 // TODO handle invariant violation
Yuta HIGUCHI0a4bd192014-02-17 13:52:34 -0800637 // TODO trigger instance local topology event handler
Yuta HIGUCHI928fa682014-02-11 19:07:57 -0800638 }
Yuta HIGUCHI76df2472014-02-12 22:36:51 -0800639
640 /* ************************************************
641 * Internal In-memory object mutation methods.
642 * ************************************************/
643
644 void putSwitch(SwitchEvent swEvt) {
645 if (swEvt == null) {
646 throw new IllegalArgumentException("Switch cannot be null");
647 }
648
649 Switch sw = switches.get(swEvt.getDpid());
650
651 if (sw == null) {
652 sw = new SwitchImpl(this, swEvt.getDpid());
653 Switch existing = switches.putIfAbsent(swEvt.getDpid(), sw);
654 if (existing != null) {
655 log.warn(
656 "Concurrent putSwitch not expected. Continuing updating {}",
657 existing);
658 sw = existing;
659 }
660 }
661
662 // Update when more attributes are added to Event object
663 // no attribute to update for now
664
665 // TODO handle child Port event properly for performance
666 for (PortEvent portEvt : swEvt.getPorts() ) {
667 putPort(portEvt);
668 }
669
670 }
671
672 void removeSwitch(SwitchEvent swEvt) {
673 if (swEvt == null) {
674 throw new IllegalArgumentException("Switch cannot be null");
675 }
676
677 // TODO handle child Port event properly for performance
678 for (PortEvent portEvt : swEvt.getPorts() ) {
679 removePort(portEvt);
680 }
681
682 Switch sw = switches.get(swEvt.getDpid());
683
684 if (sw == null) {
685 log.warn("Switch {} already removed, ignoring", swEvt);
686 return;
687 }
688
Yuta HIGUCHI317bf542014-02-17 11:02:39 -0800689 // remove all ports if there still exist
690 ArrayList<PortEvent> portsToRemove = new ArrayList<>();
691 for (Port port : sw.getPorts()) {
Yuta HIGUCHI76df2472014-02-12 22:36:51 -0800692 log.warn(
Yuta HIGUCHI317bf542014-02-17 11:02:39 -0800693 "Port {} on Switch {} should be removed prior to removing Switch. Removing Port now",
694 port, swEvt);
695 PortEvent portEvt = new PortEvent(port.getDpid(), port.getNumber());
696 portsToRemove.add(portEvt);
Yuta HIGUCHI76df2472014-02-12 22:36:51 -0800697 }
Yuta HIGUCHI0a4bd192014-02-17 13:52:34 -0800698 for (PortEvent portEvt : portsToRemove) {
Yuta HIGUCHI317bf542014-02-17 11:02:39 -0800699 // XXX calling removePortEvent() may trigger duplicate event, once at prepare phase, second time here
700 // If event can be squashed, ignored etc. at receiver side it shouldn't be a problem, but if not
701 // need to re-visit this issue.
702
703 // Note: removePortEvent() implies removal of attached Device, etc.
704 // if we decide not to call removePortEvent(), Device needs to be handled properly
705 removePortEvent(portEvt);
Yuta HIGUCHI76df2472014-02-12 22:36:51 -0800706 }
707
708 boolean removed = switches.remove(swEvt.getDpid(), sw);
709 if (removed) {
710 log.warn(
711 "Switch instance was replaced concurrently while removing {}. Something is not right.",
712 sw);
713 }
714 }
715
716 void putPort(PortEvent portEvt) {
717 if (portEvt == null) {
718 throw new IllegalArgumentException("Port cannot be null");
719 }
720 Switch sw = switches.get(portEvt.getDpid());
721 if (sw == null) {
722 throw new BrokenInvariantException(String.format(
723 "Switch with dpid %s did not exist.",
724 new Dpid(portEvt.getDpid())));
725 }
726 Port p = sw.getPort(portEvt.getNumber());
727 PortImpl port = null;
728 if (p != null) {
729 port = getPortImpl(p);
730 }
731
732 if (port == null) {
733 port = new PortImpl(this, sw, portEvt.getNumber());
734 }
735
736 // TODO update attributes
737
738 SwitchImpl s = getSwitchImpl(sw);
739 s.addPort(port);
740 }
741
742 void removePort(PortEvent portEvt) {
743 if (portEvt == null) {
744 throw new IllegalArgumentException("Port cannot be null");
745 }
746
747 Switch sw = switches.get(portEvt.getDpid());
748 if (sw == null) {
749 log.warn("Parent Switch for Port {} already removed, ignoring", portEvt);
750 return;
751 }
752
753 Port p = sw.getPort(portEvt.getNumber());
754 if (p == null) {
755 log.warn("Port {} already removed, ignoring", portEvt);
756 return;
757 }
758
Yuta HIGUCHIde040642014-02-17 11:03:39 -0800759 // Remove Link and Device Attachment
760 for (Device device : p.getDevices()) {
761 log.debug("Removing Device {} on Port {}", device, portEvt);
762 DeviceEvent devEvt = new DeviceEvent(device.getMacAddress());
763 devEvt.addAttachmentPoint(new SwitchPort(p.getSwitch().getDpid(), p.getNumber()));
Yuta HIGUCHI76df2472014-02-12 22:36:51 -0800764
Yuta HIGUCHIde040642014-02-17 11:03:39 -0800765 // XXX calling removeDeviceEvent() 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 removeDeviceEvent(devEvt);
Yuta HIGUCHI76df2472014-02-12 22:36:51 -0800771 }
Yuta HIGUCHIde040642014-02-17 11:03:39 -0800772 Set<Link> links = new HashSet<>();
773 links.add(p.getOutgoingLink());
774 links.add(p.getIncomingLink());
775 ArrayList<LinkEvent> linksToRemove = new ArrayList<>();
776 for (Link link : links) {
777 if (link == null) {
778 continue;
779 }
780 log.debug("Removing Link {} on Port {}", link, portEvt);
781 LinkEvent linkEvent = new LinkEvent(link.getSourceSwitchDpid(), link.getSourcePortNumber(), link.getDestinationSwitchDpid(), link.getDestinationPortNumber());
782 linksToRemove.add(linkEvent);
Yuta HIGUCHI76df2472014-02-12 22:36:51 -0800783 }
Yuta HIGUCHIde040642014-02-17 11:03:39 -0800784 for (LinkEvent linkEvent : linksToRemove) {
785 // XXX calling removeLinkEvent() may trigger duplicate event, once at prepare phase, second time here
786 // If event can be squashed, ignored etc. at receiver side it shouldn't be a problem, but if not
787 // need to re-visit
788
789 // calling Discovery API to wipe from DB, etc.
790 removeLinkEvent(linkEvent);
Yuta HIGUCHI76df2472014-02-12 22:36:51 -0800791 }
792
793 // remove Port from Switch
794 SwitchImpl s = getSwitchImpl(sw);
795 s.removePort(p);
796 }
797
798 void putLink(LinkEvent linkEvt) {
799 if (linkEvt == null) {
800 throw new IllegalArgumentException("Link cannot be null");
801 }
802
803 Switch srcSw = switches.get(linkEvt.getSrc().dpid);
804 if (srcSw == null) {
805 throw new BrokenInvariantException(
806 String.format(
807 "Switch with dpid %s did not exist.",
808 new Dpid(linkEvt.getSrc().dpid)));
809 }
810
811 Switch dstSw = switches.get(linkEvt.getDst().dpid);
812 if (dstSw == null) {
813 throw new BrokenInvariantException(
814 String.format(
815 "Switch with dpid %s did not exist.",
816 new Dpid(linkEvt.getDst().dpid)));
817 }
818
819 Port srcPort = srcSw.getPort(linkEvt.getSrc().number);
820 if (srcPort == null) {
821 throw new BrokenInvariantException(
822 String.format(
823 "Src Port %s of a Link did not exist.",
824 linkEvt.getSrc() ));
825 }
826
827 Port dstPort = dstSw.getPort(linkEvt.getDst().number);
828 if (dstPort == null) {
829 throw new BrokenInvariantException(
830 String.format(
831 "Dst Port %s of a Link did not exist.",
832 linkEvt.getDst() ));
833 }
834
835 // getting Link instance from destination port incoming Link
836 Link l = dstPort.getIncomingLink();
837 LinkImpl link = null;
838 assert( l == srcPort.getOutgoingLink() );
839 if (l != null) {
840 link = getLinkImpl(l);
841 }
842
843 if (link == null) {
844 link = new LinkImpl(this, srcPort, dstPort);
845 }
846
847
848 PortImpl dstPortMem = getPortImpl(dstPort);
849 PortImpl srcPortMem = getPortImpl(srcPort);
850
851 // Add Link first to avoid further Device addition
852
853 // add Link to Port
854 dstPortMem.setIncomingLink(link);
855 srcPortMem.setOutgoingLink(link);
856
857 // remove Device Pointing to Port if any
858 for(Device d : dstPortMem.getDevices() ) {
859 log.error("Device {} on Port {} should have been removed prior to adding Link {}", d, dstPort, linkEvt);
860 DeviceImpl dev = getDeviceImpl(d);
861 dev.removeAttachmentPoint(dstPort);
Yuta HIGUCHI407261a2014-02-13 16:34:06 -0800862 // This implies that change is made to Device Object.
863 // sending Device attachment point removed event
864 DeviceEvent rmEvent = new DeviceEvent(d.getMacAddress());
865 rmEvent.addAttachmentPoint(new SwitchPort(dstPort.getDpid(), dstPort.getNumber()));
866 removeDeviceEvent(rmEvent);
Yuta HIGUCHI76df2472014-02-12 22:36:51 -0800867 }
868 dstPortMem.removeAllDevice();
869 for(Device d : srcPortMem.getDevices() ) {
870 log.error("Device {} on Port {} should have been removed prior to adding Link {}", d, srcPort, linkEvt);
871 DeviceImpl dev = getDeviceImpl(d);
872 dev.removeAttachmentPoint(srcPort);
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 srcPortMem.removeAllDevice();
880
881 }
882
883 void removeLink(LinkEvent linkEvt) {
884 if (linkEvt == null) {
885 throw new IllegalArgumentException("Link cannot be null");
886 }
887
888 Switch srcSw = switches.get(linkEvt.getSrc().dpid);
889 if (srcSw == null) {
890 log.warn("Src Switch for Link {} already removed, ignoring", linkEvt);
891 return;
892 }
893
894 Switch dstSw = switches.get(linkEvt.getDst().dpid);
895 if (dstSw == null) {
896 log.warn("Dst Switch for Link {} already removed, ignoring", linkEvt);
897 return;
898 }
899
900 Port srcPort = srcSw.getPort(linkEvt.getSrc().number);
901 if (srcPort == null) {
902 log.warn("Src Port for Link {} already removed, ignoring", linkEvt);
903 return;
904 }
905
906 Port dstPort = dstSw.getPort(linkEvt.getDst().number);
907 if (dstPort == null) {
908 log.warn("Dst Port for Link {} already removed, ignoring", linkEvt);
909 return;
910 }
911
912 Link l = dstPort.getIncomingLink();
913 if ( l == null ) {
914 log.warn("Link {} already removed on destination Port", linkEvt);
915 }
916 l = srcPort.getOutgoingLink();
917 if ( l == null ) {
918 log.warn("Link {} already removed on src Port", linkEvt);
919 }
920
921 getPortImpl(dstPort).setIncomingLink(null);
922 getPortImpl(srcPort).setOutgoingLink(null);
923 }
924
925 // XXX Need to rework Device related
926 void putDevice(DeviceEvent deviceEvt) {
927 if (deviceEvt == null) {
928 throw new IllegalArgumentException("Device cannot be null");
929 }
930
931 Device device = getDeviceByMac(deviceEvt.getMac());
932 if ( device == null ) {
933 device = new DeviceImpl(this, deviceEvt.getMac());
934 Device existing = mac2Device.putIfAbsent(deviceEvt.getMac(), device);
935 if (existing != null) {
936 log.warn(
937 "Concurrent putDevice seems to be in action. Continuing updating {}",
938 existing);
939 device = existing;
940 }
941 }
942 DeviceImpl memDevice = getDeviceImpl(device);
943
944 // for each attachment point
945 for (SwitchPort swp : deviceEvt.getAttachmentPoints() ) {
946 // Attached Ports' Parent Switch must exist
947 Switch sw = getSwitch(swp.dpid);
948 if ( sw == null ) {
Yuta HIGUCHI25719052014-02-13 14:42:06 -0800949 log.warn("Switch for the attachment point {} did not exist. skipping mutation", swp);
Yuta HIGUCHI76df2472014-02-12 22:36:51 -0800950 continue;
951 }
952 // Attached Ports must exist
953 Port port = sw.getPort(swp.number);
954 if ( port == null ) {
Yuta HIGUCHI25719052014-02-13 14:42:06 -0800955 log.warn("Port for the attachment point {} did not exist. skipping mutation", swp);
Yuta HIGUCHI76df2472014-02-12 22:36:51 -0800956 continue;
957 }
958 // Attached Ports must not have Link
959 if ( port.getOutgoingLink() != null || port.getIncomingLink() != null ) {
960 log.warn("Link (Out:{},In:{}) exist on the attachment point, skipping mutation.", port.getOutgoingLink(), port.getIncomingLink());
961 continue;
962 }
963
964 // finally add Device <-> Port on In-memory structure
965 PortImpl memPort = getPortImpl(port);
966 memPort.addDevice(device);
967 memDevice.addAttachmentPoint(port);
968 }
969
970 // for each IP address
971 for( InetAddress ipAddr : deviceEvt.getIpAddresses() ) {
972 // Add Device -> IP
973 memDevice.addIpAddress(ipAddr);
974
975 // Add IP -> Set<Device>
976 boolean updated = false;
977 do {
978 Set<Device> devices = this.addr2Device.get(ipAddr);
979 if ( devices == null ) {
980 devices = new HashSet<>();
981 Set<Device> existing = this.addr2Device.putIfAbsent(ipAddr, devices);
982 if ( existing == null ) {
983 // success
984 updated = true;
985 }
986 } else {
987 Set<Device> updateDevices = new HashSet<>(devices);
988 updateDevices.add(device);
989 updated = this.addr2Device.replace(ipAddr, devices, updateDevices);
990 }
991 if (!updated) {
992 log.debug("Collision detected, updating IP to Device mapping retrying.");
993 }
994 } while( !updated );
995 }
996 }
997
998 void removeDevice(DeviceEvent deviceEvt) {
999 if (deviceEvt == null) {
1000 throw new IllegalArgumentException("Device cannot be null");
1001 }
1002
1003 Device device = getDeviceByMac(deviceEvt.getMac());
1004 if ( device == null ) {
1005 log.warn("Device {} already removed, ignoring", deviceEvt);
1006 return;
1007 }
1008 DeviceImpl memDevice = getDeviceImpl(device);
1009
1010 // for each attachment point
1011 for (SwitchPort swp : deviceEvt.getAttachmentPoints() ) {
1012 // Attached Ports' Parent Switch must exist
1013 Switch sw = getSwitch(swp.dpid);
1014 if ( sw == null ) {
Yuta HIGUCHI25719052014-02-13 14:42:06 -08001015 log.warn("Switch for the attachment point {} did not exist. skipping attachment point mutation", swp);
Yuta HIGUCHI76df2472014-02-12 22:36:51 -08001016 continue;
1017 }
1018 // Attached Ports must exist
1019 Port port = sw.getPort(swp.number);
1020 if ( port == null ) {
Yuta HIGUCHI25719052014-02-13 14:42:06 -08001021 log.warn("Port for the attachment point {} did not exist. skipping attachment point mutation", swp);
Yuta HIGUCHI76df2472014-02-12 22:36:51 -08001022 continue;
1023 }
1024
1025 // finally remove Device <-> Port on In-memory structure
1026 PortImpl memPort = getPortImpl(port);
1027 memPort.removeDevice(device);
1028 memDevice.removeAttachmentPoint(port);
1029 }
1030
1031 // for each IP address
1032 for( InetAddress ipAddr : deviceEvt.getIpAddresses() ) {
1033 // Remove Device -> IP
1034 memDevice.removeIpAddress(ipAddr);
1035
1036 // Remove IP -> Set<Device>
1037 boolean updated = false;
1038 do {
1039 Set<Device> devices = this.addr2Device.get(ipAddr);
1040 if ( devices == null ) {
1041 // already empty set, nothing to do
1042 updated = true;
1043 } else {
1044 Set<Device> updateDevices = new HashSet<>(devices);
1045 updateDevices.remove(device);
1046 updated = this.addr2Device.replace(ipAddr, devices, updateDevices);
1047 }
1048 if (!updated) {
1049 log.debug("Collision detected, updating IP to Device mapping retrying.");
1050 }
1051 } while( !updated );
1052 }
1053 }
1054
1055 private SwitchImpl getSwitchImpl(Switch sw) {
1056 if (sw instanceof SwitchImpl) {
1057 return (SwitchImpl) sw;
1058 }
1059 throw new ClassCastException("SwitchImpl expected, but found: " + sw);
1060 }
1061
1062 private PortImpl getPortImpl(Port p) {
1063 if (p instanceof PortImpl) {
1064 return (PortImpl) p;
1065 }
1066 throw new ClassCastException("PortImpl expected, but found: " + p);
1067 }
1068
1069 private LinkImpl getLinkImpl(Link l) {
1070 if (l instanceof LinkImpl) {
1071 return (LinkImpl) l;
1072 }
1073 throw new ClassCastException("LinkImpl expected, but found: " + l);
1074 }
1075
1076 private DeviceImpl getDeviceImpl(Device d) {
1077 if (d instanceof DeviceImpl) {
1078 return (DeviceImpl) d;
1079 }
1080 throw new ClassCastException("DeviceImpl expected, but found: " + d);
1081 }
1082
1083 @Deprecated
1084 public void loadWholeTopologyFromDB() {
Yuta HIGUCHI0a4bd192014-02-17 13:52:34 -08001085 // XXX May need to clear whole topology first, depending on
1086 // how we initially subscribe to replication events
Yuta HIGUCHI76df2472014-02-12 22:36:51 -08001087
1088 for (RCSwitch sw : RCSwitch.getAllSwitches()) {
1089 if ( sw.getStatus() != RCSwitch.STATUS.ACTIVE ) {
1090 continue;
1091 }
1092 putSwitchReplicationEvent(new SwitchEvent(sw.getDpid()));
1093 }
1094
1095 for (RCPort p : RCPort.getAllPorts()) {
1096 if (p.getStatus() != RCPort.STATUS.ACTIVE) {
1097 continue;
1098 }
1099 putPortReplicationEvent(new PortEvent(p.getDpid(), p.getNumber() ));
1100 }
1101
1102 // TODO Is Device going to be in DB? If so, read from DB.
1103 // for (RCDevice d : RCDevice.getAllDevices()) {
1104 // DeviceEvent devEvent = new DeviceEvent( MACAddress.valueOf(d.getMac()) );
1105 // for (byte[] portId : d.getAllPortIds() ) {
1106 // devEvent.addAttachmentPoint( new SwitchPort( RCPort.getDpidFromKey(portId), RCPort.getNumberFromKey(portId) ));
1107 // }
1108 // }
1109
1110 for (RCLink l : RCLink.getAllLinks()) {
Yuta HIGUCHI0a4bd192014-02-17 13:52:34 -08001111 // TODO check if src/dst switch/port exist before triggering event
Yuta HIGUCHI76df2472014-02-12 22:36:51 -08001112 putLinkReplicationEvent( new LinkEvent(l.getSrc().dpid, l.getSrc().number, l.getDst().dpid, l.getDst().number));
1113 }
1114 }
Jonathan Hart062a2e82014-02-03 09:41:57 -08001115}