blob: 176e793d19a9500249bcaed401e33a81130ab499 [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) {
Yuta HIGUCHI0a4bd192014-02-17 13:52:34 -0800122 // TODO ignore event triggered by myself
Pavlin Radoslavov721a2e02014-02-14 23:40:14 -0800123 TopologyEvent topologyEvent = event.eventData();
124 switch (event.eventType()) {
125 case ENTRY_ADD:
126 log.debug("Topology event ENTRY_ADD: {}", topologyEvent);
127 if (topologyEvent.switchEvent != null)
128 putSwitchReplicationEvent(topologyEvent.switchEvent);
129 if (topologyEvent.portEvent != null)
130 putPortReplicationEvent(topologyEvent.portEvent);
131 if (topologyEvent.linkEvent != null)
132 putLinkReplicationEvent(topologyEvent.linkEvent);
133 if (topologyEvent.deviceEvent != null)
134 putDeviceReplicationEvent(topologyEvent.deviceEvent);
135 break;
136 case ENTRY_REMOVE:
137 log.debug("Topology event ENTRY_REMOVE: {}", topologyEvent);
138 if (topologyEvent.switchEvent != null)
139 removeSwitchReplicationEvent(topologyEvent.switchEvent);
140 if (topologyEvent.portEvent != null)
141 removePortReplicationEvent(topologyEvent.portEvent);
142 if (topologyEvent.linkEvent != null)
143 removeLinkReplicationEvent(topologyEvent.linkEvent);
144 if (topologyEvent.deviceEvent != null)
145 removeDeviceReplicationEvent(topologyEvent.deviceEvent);
146 break;
147 }
148 }
149 }
150
151 /**
152 * Receive a notification that an entry is added.
153 *
154 * @param value the value for the entry.
155 */
156 @Override
157 public void entryAdded(TopologyEvent value) {
158 EventEntry<TopologyEvent> eventEntry =
159 new EventEntry<TopologyEvent>(EventEntry.Type.ENTRY_ADD,
160 value);
161 topologyEvents.add(eventEntry);
162 }
163
164 /**
165 * Receive a notification that an entry is removed.
166 *
167 * @param value the value for the entry.
168 */
169 @Override
170 public void entryRemoved(TopologyEvent value) {
171 EventEntry<TopologyEvent> eventEntry =
172 new EventEntry<TopologyEvent>(EventEntry.Type.ENTRY_REMOVE,
173 value);
174 topologyEvents.add(eventEntry);
175 }
176
177 /**
178 * Receive a notification that an entry is updated.
179 *
180 * @param value the value for the entry.
181 */
182 @Override
183 public void entryUpdated(TopologyEvent value) {
184 // NOTE: The ADD and UPDATE events are processed in same way
185 entryAdded(value);
186 }
187 }
188
189 /**
190 * Startup processing.
191 *
192 * @param datagridService the datagrid service to use.
193 */
194 void startup(IDatagridService datagridService) {
195 eventChannel = datagridService.addListener(EVENT_CHANNEL_NAME,
196 eventHandler,
197 byte[].class,
198 TopologyEvent.class);
199 eventHandler.start();
200 }
201
202 /**
Yuta HIGUCHIcb951982014-02-11 13:31:44 -0800203 * Exception to be thrown when Modification to the Network Graph cannot be continued due to broken invariant.
204 *
205 * XXX Should this be checked exception or RuntimeException
206 */
207 public static class BrokenInvariantException extends RuntimeException {
208 private static final long serialVersionUID = 1L;
209
210 public BrokenInvariantException() {
211 super();
212 }
213
214 public BrokenInvariantException(String message) {
215 super(message);
216 }
217 }
Jonathan Hart22eb9882014-02-11 15:52:59 -0800218
219 /* ******************************
220 * NetworkGraphDiscoveryInterface methods
221 * ******************************/
Yuta HIGUCHIcd922f42014-02-11 18:59:11 -0800222
Jonathan Hart22eb9882014-02-11 15:52:59 -0800223 @Override
224 public void putSwitchEvent(SwitchEvent switchEvent) {
Yuta HIGUCHId02e9282014-02-12 09:24:41 -0800225 if (prepareForAddSwitchEvent(switchEvent)) {
Jonathan Hart22eb9882014-02-11 15:52:59 -0800226 datastore.addSwitch(switchEvent);
227 putSwitch(switchEvent);
Pavlin Radoslavov721a2e02014-02-14 23:40:14 -0800228 // Send out notification
229 TopologyEvent topologyEvent =
230 new TopologyEvent(switchEvent);
231 eventChannel.addEntry(topologyEvent.getID(),
232 topologyEvent);
Jonathan Hart22eb9882014-02-11 15:52:59 -0800233 }
234 // TODO handle invariant violation
235 }
236
237 @Override
238 public void removeSwitchEvent(SwitchEvent switchEvent) {
Yuta HIGUCHId02e9282014-02-12 09:24:41 -0800239 if (prepareForRemoveSwitchEvent(switchEvent)) {
Jonathan Hart22eb9882014-02-11 15:52:59 -0800240 datastore.deactivateSwitch(switchEvent);
241 removeSwitch(switchEvent);
Pavlin Radoslavov721a2e02014-02-14 23:40:14 -0800242 // Send out notification
243 eventChannel.removeEntry(switchEvent.getID());
Jonathan Hart22eb9882014-02-11 15:52:59 -0800244 }
245 // TODO handle invariant violation
246 }
247
248 @Override
249 public void putPortEvent(PortEvent portEvent) {
Jonathan Hart4c263272014-02-13 17:41:05 -0800250 if (prepareForAddPortEvent(portEvent)) {
251 datastore.addPort(portEvent);
252 putPort(portEvent);
Pavlin Radoslavov721a2e02014-02-14 23:40:14 -0800253 // Send out notification
254 TopologyEvent topologyEvent =
255 new TopologyEvent(portEvent);
256 eventChannel.addEntry(topologyEvent.getID(),
257 topologyEvent);
Jonathan Hart4c263272014-02-13 17:41:05 -0800258 }
Yuta HIGUCHI75c51ed2014-02-13 17:02:26 -0800259 // TODO handle invariant violation
Jonathan Hart22eb9882014-02-11 15:52:59 -0800260 }
261
262 @Override
263 public void removePortEvent(PortEvent portEvent) {
Jonathan Hart4c263272014-02-13 17:41:05 -0800264 if (prepareForRemovePortEvent(portEvent)) {
265 datastore.deactivatePort(portEvent);
266 removePort(portEvent);
Pavlin Radoslavov721a2e02014-02-14 23:40:14 -0800267 // Send out notification
268 eventChannel.removeEntry(portEvent.getID());
Jonathan Hart4c263272014-02-13 17:41:05 -0800269 }
Yuta HIGUCHI75c51ed2014-02-13 17:02:26 -0800270 // TODO handle invariant violation
Jonathan Hart22eb9882014-02-11 15:52:59 -0800271 }
272
273 @Override
274 public void putLinkEvent(LinkEvent linkEvent) {
Yuta HIGUCHId02e9282014-02-12 09:24:41 -0800275 if (prepareForAddLinkEvent(linkEvent)) {
Jonathan Hart22eb9882014-02-11 15:52:59 -0800276 datastore.addLink(linkEvent);
277 putLink(linkEvent);
Pavlin Radoslavov721a2e02014-02-14 23:40:14 -0800278 // Send out notification
279 TopologyEvent topologyEvent =
280 new TopologyEvent(linkEvent);
281 eventChannel.addEntry(topologyEvent.getID(),
282 topologyEvent);
Jonathan Hart22eb9882014-02-11 15:52:59 -0800283 }
284 // TODO handle invariant violation
285 }
286
287 @Override
288 public void removeLinkEvent(LinkEvent linkEvent) {
Yuta HIGUCHI0a4bd192014-02-17 13:52:34 -0800289 // TODO may need to distinguish internal event, which checks
290 // ownership of dst-dpid of this link, and only write to DB
291 // if it is owner of the dpid
Yuta HIGUCHId02e9282014-02-12 09:24:41 -0800292 if (prepareForRemoveLinkEvent(linkEvent)) {
Jonathan Hart22eb9882014-02-11 15:52:59 -0800293 datastore.removeLink(linkEvent);
294 removeLink(linkEvent);
Pavlin Radoslavov721a2e02014-02-14 23:40:14 -0800295 // Send out notification
296 eventChannel.removeEntry(linkEvent.getID());
Jonathan Hart22eb9882014-02-11 15:52:59 -0800297 }
298 // TODO handle invariant violation
299 }
300
301 @Override
Yuta HIGUCHI586d33e2014-02-13 17:05:08 -0800302 public void putDeviceEvent(DeviceEvent deviceEvent) {
303 if (prepareForAddDeviceEvent(deviceEvent)) {
304// datastore.addDevice(deviceEvent);
Yuta HIGUCHId457c052014-02-14 18:33:04 -0800305// putDevice(deviceEvent);
Pavlin Radoslavov721a2e02014-02-14 23:40:14 -0800306 // Send out notification
307 TopologyEvent topologyEvent =
308 new TopologyEvent(deviceEvent);
309 eventChannel.addEntry(topologyEvent.getID(),
310 topologyEvent);
Yuta HIGUCHI586d33e2014-02-13 17:05:08 -0800311 }
312 // TODO handle invariant violation
313 // XXX if prepareFor~ method returned false, event should be dropped
Jonathan Hart22eb9882014-02-11 15:52:59 -0800314 }
315
316 @Override
317 public void removeDeviceEvent(DeviceEvent deviceEvent) {
Yuta HIGUCHI586d33e2014-02-13 17:05:08 -0800318 if (prepareForRemoveDeviceEvent(deviceEvent)) {
319// datastore.removeDevice(deviceEvent);
Yuta HIGUCHId457c052014-02-14 18:33:04 -0800320// removeDevice(deviceEvent);
Pavlin Radoslavov721a2e02014-02-14 23:40:14 -0800321 // Send out notification
322 eventChannel.removeEntry(deviceEvent.getID());
Yuta HIGUCHI586d33e2014-02-13 17:05:08 -0800323 }
324 // TODO handle invariant violation
325 // XXX if prepareFor~ method returned false, event should be dropped
Jonathan Hart22eb9882014-02-11 15:52:59 -0800326 }
Yuta HIGUCHIcd922f42014-02-11 18:59:11 -0800327
Jonathan Hart22eb9882014-02-11 15:52:59 -0800328 /* *****************
Yuta HIGUCHId02e9282014-02-12 09:24:41 -0800329 * Internal methods to maintain invariants of the network graph
Jonathan Hart22eb9882014-02-11 15:52:59 -0800330 * *****************/
Yuta HIGUCHIcd922f42014-02-11 18:59:11 -0800331
Yuta HIGUCHId02e9282014-02-12 09:24:41 -0800332 /**
333 *
334 * @param swEvt
335 * @return true if ready to accept event.
336 */
337 private boolean prepareForAddSwitchEvent(SwitchEvent swEvt) {
Yuta HIGUCHI76df2472014-02-12 22:36:51 -0800338 // No show stopping precondition
Yuta HIGUCHI8d762e92014-02-12 14:10:25 -0800339 // Prep: remove(deactivate) Ports on Switch, which is not on event
340 removePortsNotOnEvent(swEvt);
341 return true;
Jonathan Hart22eb9882014-02-11 15:52:59 -0800342 }
Yuta HIGUCHIcd922f42014-02-11 18:59:11 -0800343
Yuta HIGUCHId02e9282014-02-12 09:24:41 -0800344 private boolean prepareForRemoveSwitchEvent(SwitchEvent swEvt) {
Yuta HIGUCHI76df2472014-02-12 22:36:51 -0800345 // No show stopping precondition
Yuta HIGUCHI8d762e92014-02-12 14:10:25 -0800346 // Prep: remove(deactivate) Ports on Switch, which is not on event
347 // XXX may be remove switch should imply wipe all ports
348 removePortsNotOnEvent(swEvt);
349 return true;
350 }
Yuta HIGUCHId02e9282014-02-12 09:24:41 -0800351
Yuta HIGUCHI8d762e92014-02-12 14:10:25 -0800352 private void removePortsNotOnEvent(SwitchEvent swEvt) {
353 Switch sw = switches.get( swEvt.getDpid() );
354 if ( sw != null ) {
355 Set<Long> port_noOnEvent = new HashSet<>();
356 for( PortEvent portEvent : swEvt.getPorts()) {
357 port_noOnEvent.add(portEvent.getNumber());
358 }
359 // Existing ports not on event should be removed.
360 // TODO Should batch eventually for performance?
Jonathan Hart480c5572014-02-14 18:28:16 -0800361 List<Port> portsToRemove = new ArrayList<Port>();
Yuta HIGUCHI8d762e92014-02-12 14:10:25 -0800362 for( Port p : sw.getPorts() ) {
363 if ( !port_noOnEvent.contains(p.getNumber()) ) {
Jonathan Hart480c5572014-02-14 18:28:16 -0800364 //PortEvent rmEvent = new PortEvent(p.getSwitch().getDpid(), p.getNumber());
365 // calling Discovery removePort() API to wipe from DB, etc.
366 //removePortEvent(rmEvent);
Yuta HIGUCHI240bf072014-02-17 10:55:21 -0800367
Jonathan Hart480c5572014-02-14 18:28:16 -0800368 // We can't remove ports here because this will trigger a remove
369 // from the switch's port list, which we are currently iterating
370 // over.
371 portsToRemove.add(p);
372 }
373 }
374 for (Port p : portsToRemove) {
Yuta HIGUCHI8d762e92014-02-12 14:10:25 -0800375 PortEvent rmEvent = new PortEvent(p.getSwitch().getDpid(), p.getNumber());
376 // calling Discovery removePort() API to wipe from DB, etc.
377 removePortEvent(rmEvent);
Yuta HIGUCHI8d762e92014-02-12 14:10:25 -0800378 }
379 }
Jonathan Hart22eb9882014-02-11 15:52:59 -0800380 }
Yuta HIGUCHIcd922f42014-02-11 18:59:11 -0800381
Yuta HIGUCHId02e9282014-02-12 09:24:41 -0800382 private boolean prepareForAddPortEvent(PortEvent portEvt) {
Yuta HIGUCHId02e9282014-02-12 09:24:41 -0800383 // Parent Switch must exist
384 if ( getSwitch(portEvt.getDpid()) == null) {
385 return false;
386 }
387 // Prep: None
Jonathan Hart22eb9882014-02-11 15:52:59 -0800388 return true;
389 }
Yuta HIGUCHIcd922f42014-02-11 18:59:11 -0800390
Yuta HIGUCHId02e9282014-02-12 09:24:41 -0800391 private boolean prepareForRemovePortEvent(PortEvent portEvt) {
Yuta HIGUCHId02e9282014-02-12 09:24:41 -0800392 // Parent Switch must exist
Yuta HIGUCHI8d762e92014-02-12 14:10:25 -0800393 Switch sw = getSwitch(portEvt.getDpid());
394 if ( sw == null ) {
Yuta HIGUCHI88be0f22014-02-14 17:20:43 -0800395 log.debug("Switch already removed? {}", portEvt);
Yuta HIGUCHId02e9282014-02-12 09:24:41 -0800396 return false;
397 }
Yuta HIGUCHI8d762e92014-02-12 14:10:25 -0800398 Port port = sw.getPort(portEvt.getNumber());
399 if ( port == null ) {
400 log.debug("Port already removed? {}", portEvt);
401 // let it pass
402 return true;
403 }
404
405 // Prep: Remove Link and Device Attachment
Yuta HIGUCHI240bf072014-02-17 10:55:21 -0800406 ArrayList<DeviceEvent> deviceEvts = new ArrayList<>();
Yuta HIGUCHI8d762e92014-02-12 14:10:25 -0800407 for (Device device : port.getDevices()) {
Yuta HIGUCHI88be0f22014-02-14 17:20:43 -0800408 log.debug("Removing Device {} on Port {}", device, portEvt);
Yuta HIGUCHI8d762e92014-02-12 14:10:25 -0800409 DeviceEvent devEvt = new DeviceEvent(device.getMacAddress());
410 devEvt.addAttachmentPoint(new SwitchPort(port.getSwitch().getDpid(), port.getNumber()));
Yuta HIGUCHI240bf072014-02-17 10:55:21 -0800411 deviceEvts.add(devEvt);
412 }
413 for (DeviceEvent devEvt : deviceEvts) {
Yuta HIGUCHI8d762e92014-02-12 14:10:25 -0800414 // calling Discovery API to wipe from DB, etc.
415 removeDeviceEvent(devEvt);
416 }
Yuta HIGUCHI240bf072014-02-17 10:55:21 -0800417
Yuta HIGUCHI8d762e92014-02-12 14:10:25 -0800418 Set<Link> links = new HashSet<>();
419 links.add(port.getOutgoingLink());
420 links.add(port.getIncomingLink());
421 for ( Link link : links) {
422 if (link == null ) {
423 continue;
424 }
Yuta HIGUCHI88be0f22014-02-14 17:20:43 -0800425 log.debug("Removing Link {} on Port {}", link, portEvt);
Yuta HIGUCHI8d762e92014-02-12 14:10:25 -0800426 LinkEvent linkEvent = new LinkEvent(link.getSourceSwitchDpid(), link.getSourcePortNumber(), link.getDestinationSwitchDpid(), link.getDestinationPortNumber());
427 // calling Discovery API to wipe from DB, etc.
Yuta HIGUCHI0a4bd192014-02-17 13:52:34 -0800428 // XXX call internal remove Link, which will check
429 // ownership and modify only if it is the owner
Yuta HIGUCHI8d762e92014-02-12 14:10:25 -0800430 removeLinkEvent(linkEvent);
431 }
Jonathan Hart22eb9882014-02-11 15:52:59 -0800432 return true;
433 }
Yuta HIGUCHIcd922f42014-02-11 18:59:11 -0800434
Yuta HIGUCHId02e9282014-02-12 09:24:41 -0800435 private boolean prepareForAddLinkEvent(LinkEvent linkEvt) {
Yuta HIGUCHI8d762e92014-02-12 14:10:25 -0800436 // Src/Dst Switch must exist
437 Switch srcSw = getSwitch(linkEvt.getSrc().dpid);
438 Switch dstSw = getSwitch(linkEvt.getDst().dpid);
439 if ( srcSw == null || dstSw == null ) {
440 return false;
441 }
442 // Src/Dst Port must exist
443 Port srcPort = srcSw.getPort(linkEvt.getSrc().number);
Jonathan Hart4c263272014-02-13 17:41:05 -0800444 Port dstPort = dstSw.getPort(linkEvt.getDst().number);
Yuta HIGUCHI8d762e92014-02-12 14:10:25 -0800445 if ( srcPort == null || dstPort == null ) {
446 return false;
447 }
448
449 // Prep: remove Device attachment on both Ports
Yuta HIGUCHI240bf072014-02-17 10:55:21 -0800450 ArrayList<DeviceEvent> deviceEvents = new ArrayList<>();
Yuta HIGUCHI8d762e92014-02-12 14:10:25 -0800451 for (Device device : srcPort.getDevices()) {
452 DeviceEvent devEvt = new DeviceEvent(device.getMacAddress());
453 devEvt.addAttachmentPoint(new SwitchPort(srcPort.getSwitch().getDpid(), srcPort.getNumber()));
Yuta HIGUCHI240bf072014-02-17 10:55:21 -0800454 deviceEvents.add(devEvt);
Yuta HIGUCHI8d762e92014-02-12 14:10:25 -0800455 }
456 for (Device device : dstPort.getDevices()) {
457 DeviceEvent devEvt = new DeviceEvent(device.getMacAddress());
458 devEvt.addAttachmentPoint(new SwitchPort(dstPort.getSwitch().getDpid(), dstPort.getNumber()));
Yuta HIGUCHI240bf072014-02-17 10:55:21 -0800459 deviceEvents.add(devEvt);
460 }
461 for (DeviceEvent devEvt : deviceEvents) {
Yuta HIGUCHI8d762e92014-02-12 14:10:25 -0800462 // calling Discovery API to wipe from DB, etc.
463 removeDeviceEvent(devEvt);
464 }
465
466 return true;
Jonathan Hart22eb9882014-02-11 15:52:59 -0800467 }
Yuta HIGUCHIcd922f42014-02-11 18:59:11 -0800468
Yuta HIGUCHId02e9282014-02-12 09:24:41 -0800469 private boolean prepareForRemoveLinkEvent(LinkEvent linkEvt) {
Yuta HIGUCHI8d762e92014-02-12 14:10:25 -0800470 // Src/Dst Switch must exist
471 Switch srcSw = getSwitch(linkEvt.getSrc().dpid);
472 Switch dstSw = getSwitch(linkEvt.getDst().dpid);
473 if ( srcSw == null || dstSw == null ) {
Yuta HIGUCHI125c7df2014-02-14 12:28:10 -0800474 log.warn("Rejecting removeLink {} because switch doesn't exist", linkEvt);
Yuta HIGUCHI8d762e92014-02-12 14:10:25 -0800475 return false;
476 }
477 // Src/Dst Port must exist
478 Port srcPort = srcSw.getPort(linkEvt.getSrc().number);
Yuta HIGUCHI125c7df2014-02-14 12:28:10 -0800479 Port dstPort = dstSw.getPort(linkEvt.getDst().number);
Yuta HIGUCHI8d762e92014-02-12 14:10:25 -0800480 if ( srcPort == null || dstPort == null ) {
Yuta HIGUCHI125c7df2014-02-14 12:28:10 -0800481 log.warn("Rejecting removeLink {} because port doesn't exist", linkEvt);
Yuta HIGUCHI8d762e92014-02-12 14:10:25 -0800482 return false;
483 }
484
Yuta HIGUCHI125c7df2014-02-14 12:28:10 -0800485 Link link = srcPort.getOutgoingLink();
486
487 // Link is already gone, or different Link exist in memory
488 // XXX Check if we should reject or just accept these cases.
489 // it should be harmless to remove the Link on event from DB anyways
490 if (link == null ||
491 !link.getDestinationPortNumber().equals(linkEvt.getDst().number)
492 || !link.getDestinationSwitchDpid().equals(linkEvt.getDst().dpid)) {
493 log.warn("Rejecting removeLink {} because link doesn't exist", linkEvt);
494 return false;
495 }
Yuta HIGUCHI8d762e92014-02-12 14:10:25 -0800496 // Prep: None
497 return true;
Jonathan Hart22eb9882014-02-11 15:52:59 -0800498 }
Yuta HIGUCHIcd922f42014-02-11 18:59:11 -0800499
Yuta HIGUCHI8d762e92014-02-12 14:10:25 -0800500 /**
501 *
502 * @param deviceEvt Event will be modified to remove inapplicable attachemntPoints/ipAddress
503 * @return false if this event should be dropped.
504 */
Yuta HIGUCHId02e9282014-02-12 09:24:41 -0800505 private boolean prepareForAddDeviceEvent(DeviceEvent deviceEvt) {
Yuta HIGUCHI8d762e92014-02-12 14:10:25 -0800506 boolean preconditionBroken = false;
507 ArrayList<PortEvent.SwitchPort> failedSwitchPort = new ArrayList<>();
508 for ( PortEvent.SwitchPort swp : deviceEvt.getAttachmentPoints() ) {
Yuta HIGUCHId02e9282014-02-12 09:24:41 -0800509 // Attached Ports' Parent Switch must exist
Yuta HIGUCHI8d762e92014-02-12 14:10:25 -0800510 Switch sw = getSwitch(swp.dpid);
511 if ( sw == null ) {
512 preconditionBroken = true;
513 failedSwitchPort.add(swp);
514 continue;
515 }
Yuta HIGUCHId02e9282014-02-12 09:24:41 -0800516 // Attached Ports must exist
Yuta HIGUCHI8d762e92014-02-12 14:10:25 -0800517 Port port = sw.getPort(swp.number);
518 if ( port == null ) {
519 preconditionBroken = true;
520 failedSwitchPort.add(swp);
521 continue;
522 }
Yuta HIGUCHId02e9282014-02-12 09:24:41 -0800523 // Attached Ports must not have Link
Yuta HIGUCHI8d762e92014-02-12 14:10:25 -0800524 if ( port.getOutgoingLink() != null || port.getIncomingLink() != null ) {
525 preconditionBroken = true;
526 failedSwitchPort.add(swp);
527 continue;
528 }
529 }
Yuta HIGUCHId02e9282014-02-12 09:24:41 -0800530
Yuta HIGUCHI8d762e92014-02-12 14:10:25 -0800531 // Rewriting event to exclude failed attachmentPoint
532 // XXX Assumption behind this is that inapplicable device event should
533 // be dropped, not deferred. If we decide to defer Device event,
534 // rewriting can become a problem
535 List<SwitchPort> attachmentPoints = deviceEvt.getAttachmentPoints();
536 attachmentPoints.removeAll(failedSwitchPort);
537 deviceEvt.setAttachmentPoints(attachmentPoints);
538
539 if ( deviceEvt.getAttachmentPoints().isEmpty() && deviceEvt.getIpAddresses().isEmpty() ) {
Yuta HIGUCHI125c7df2014-02-14 12:28:10 -0800540 // return false to represent: Nothing left to do for this event. Caller should drop event
Yuta HIGUCHI8d762e92014-02-12 14:10:25 -0800541 return false;
542 }
543
544 // Should we return false to tell caller that the event was trimmed?
545 // if ( preconditionBroken ) {
546 // return false;
547 // }
548
549 return true;
Jonathan Hart22eb9882014-02-11 15:52:59 -0800550 }
Yuta HIGUCHIcd922f42014-02-11 18:59:11 -0800551
Yuta HIGUCHId02e9282014-02-12 09:24:41 -0800552 private boolean prepareForRemoveDeviceEvent(DeviceEvent deviceEvt) {
Yuta HIGUCHId02e9282014-02-12 09:24:41 -0800553 // No show stopping precondition?
554 // Prep: none
Jonathan Hart22eb9882014-02-11 15:52:59 -0800555 return true;
556 }
Yuta HIGUCHI928fa682014-02-11 19:07:57 -0800557
Yuta HIGUCHI76df2472014-02-12 22:36:51 -0800558 /* ******************************
559 * NetworkGraphReplicationInterface methods
560 * ******************************/
561
Yuta HIGUCHI928fa682014-02-11 19:07:57 -0800562 @Override
563 public void putSwitchReplicationEvent(SwitchEvent switchEvent) {
Yuta HIGUCHI9fc10ac2014-02-12 17:18:57 -0800564 if (prepareForAddSwitchEvent(switchEvent)) {
565 putSwitch(switchEvent);
566 }
567 // TODO handle invariant violation
Yuta HIGUCHI0a4bd192014-02-17 13:52:34 -0800568 // TODO trigger instance local topology event handler
Yuta HIGUCHI928fa682014-02-11 19:07:57 -0800569 }
570
571 @Override
572 public void removeSwitchReplicationEvent(SwitchEvent switchEvent) {
Yuta HIGUCHI9fc10ac2014-02-12 17:18:57 -0800573 if (prepareForRemoveSwitchEvent(switchEvent)) {
574 removeSwitch(switchEvent);
575 }
Yuta HIGUCHI125c7df2014-02-14 12:28:10 -0800576 // TODO handle invariant violation
Yuta HIGUCHI0a4bd192014-02-17 13:52:34 -0800577 // TODO trigger instance local topology event handler
Yuta HIGUCHI928fa682014-02-11 19:07:57 -0800578 }
579
580 @Override
581 public void putPortReplicationEvent(PortEvent portEvent) {
Yuta HIGUCHI9fc10ac2014-02-12 17:18:57 -0800582 if (prepareForAddPortEvent(portEvent)) {
583 putPort(portEvent);
584 }
Yuta HIGUCHI125c7df2014-02-14 12:28:10 -0800585 // TODO handle invariant violation
Yuta HIGUCHI0a4bd192014-02-17 13:52:34 -0800586 // TODO trigger instance local topology event handler
Yuta HIGUCHI928fa682014-02-11 19:07:57 -0800587 }
588
589 @Override
590 public void removePortReplicationEvent(PortEvent portEvent) {
Yuta HIGUCHI9fc10ac2014-02-12 17:18:57 -0800591 if (prepareForRemovePortEvent(portEvent)) {
592 removePort(portEvent);
593 }
Yuta HIGUCHI125c7df2014-02-14 12:28:10 -0800594 // TODO handle invariant violation
Yuta HIGUCHI0a4bd192014-02-17 13:52:34 -0800595 // TODO trigger instance local topology event handler
Yuta HIGUCHI928fa682014-02-11 19:07:57 -0800596 }
597
598 @Override
599 public void putLinkReplicationEvent(LinkEvent linkEvent) {
Yuta HIGUCHI9fc10ac2014-02-12 17:18:57 -0800600 if (prepareForAddLinkEvent(linkEvent)) {
601 putLink(linkEvent);
602 }
Yuta HIGUCHI125c7df2014-02-14 12:28:10 -0800603 // TODO handle invariant violation
Yuta HIGUCHI0a4bd192014-02-17 13:52:34 -0800604 // TODO trigger instance local topology event handler
Yuta HIGUCHI928fa682014-02-11 19:07:57 -0800605 }
606
607 @Override
608 public void removeLinkReplicationEvent(LinkEvent linkEvent) {
Yuta HIGUCHI9fc10ac2014-02-12 17:18:57 -0800609 if (prepareForRemoveLinkEvent(linkEvent)) {
610 removeLink(linkEvent);
611 }
Yuta HIGUCHI125c7df2014-02-14 12:28:10 -0800612 // TODO handle invariant violation
Yuta HIGUCHI0a4bd192014-02-17 13:52:34 -0800613 // TODO trigger instance local topology event handler
Yuta HIGUCHI928fa682014-02-11 19:07:57 -0800614 }
615
616 @Override
617 public void putDeviceReplicationEvent(DeviceEvent deviceEvent) {
Yuta HIGUCHI9fc10ac2014-02-12 17:18:57 -0800618 if (prepareForAddDeviceEvent(deviceEvent)) {
619 putDevice(deviceEvent);
620 }
Yuta HIGUCHI125c7df2014-02-14 12:28:10 -0800621 // TODO handle invariant violation
Yuta HIGUCHI0a4bd192014-02-17 13:52:34 -0800622 // TODO trigger instance local topology event handler
Yuta HIGUCHI928fa682014-02-11 19:07:57 -0800623 }
624
625 @Override
626 public void removeDeviceReplicationEvent(DeviceEvent deviceEvent) {
Yuta HIGUCHI9fc10ac2014-02-12 17:18:57 -0800627 if (prepareForRemoveDeviceEvent(deviceEvent)) {
628 removeDevice(deviceEvent);
629 }
Yuta HIGUCHI125c7df2014-02-14 12:28:10 -0800630 // TODO handle invariant violation
Yuta HIGUCHI0a4bd192014-02-17 13:52:34 -0800631 // TODO trigger instance local topology event handler
Yuta HIGUCHI928fa682014-02-11 19:07:57 -0800632 }
Yuta HIGUCHI76df2472014-02-12 22:36:51 -0800633
634 /* ************************************************
635 * Internal In-memory object mutation methods.
636 * ************************************************/
637
638 void putSwitch(SwitchEvent swEvt) {
639 if (swEvt == null) {
640 throw new IllegalArgumentException("Switch cannot be null");
641 }
642
643 Switch sw = switches.get(swEvt.getDpid());
644
645 if (sw == null) {
646 sw = new SwitchImpl(this, swEvt.getDpid());
647 Switch existing = switches.putIfAbsent(swEvt.getDpid(), sw);
648 if (existing != null) {
649 log.warn(
650 "Concurrent putSwitch not expected. Continuing updating {}",
651 existing);
652 sw = existing;
653 }
654 }
655
656 // Update when more attributes are added to Event object
657 // no attribute to update for now
658
659 // TODO handle child Port event properly for performance
660 for (PortEvent portEvt : swEvt.getPorts() ) {
661 putPort(portEvt);
662 }
663
664 }
665
666 void removeSwitch(SwitchEvent swEvt) {
667 if (swEvt == null) {
668 throw new IllegalArgumentException("Switch cannot be null");
669 }
670
671 // TODO handle child Port event properly for performance
672 for (PortEvent portEvt : swEvt.getPorts() ) {
673 removePort(portEvt);
674 }
675
676 Switch sw = switches.get(swEvt.getDpid());
677
678 if (sw == null) {
679 log.warn("Switch {} already removed, ignoring", swEvt);
680 return;
681 }
682
Yuta HIGUCHI317bf542014-02-17 11:02:39 -0800683 // remove all ports if there still exist
684 ArrayList<PortEvent> portsToRemove = new ArrayList<>();
685 for (Port port : sw.getPorts()) {
Yuta HIGUCHI76df2472014-02-12 22:36:51 -0800686 log.warn(
Yuta HIGUCHI317bf542014-02-17 11:02:39 -0800687 "Port {} on Switch {} should be removed prior to removing Switch. Removing Port now",
688 port, swEvt);
689 PortEvent portEvt = new PortEvent(port.getDpid(), port.getNumber());
690 portsToRemove.add(portEvt);
Yuta HIGUCHI76df2472014-02-12 22:36:51 -0800691 }
Yuta HIGUCHI0a4bd192014-02-17 13:52:34 -0800692 for (PortEvent portEvt : portsToRemove) {
Yuta HIGUCHI317bf542014-02-17 11:02:39 -0800693 // XXX calling removePortEvent() may trigger duplicate event, once at prepare phase, second time here
694 // If event can be squashed, ignored etc. at receiver side it shouldn't be a problem, but if not
695 // need to re-visit this issue.
696
697 // Note: removePortEvent() implies removal of attached Device, etc.
698 // if we decide not to call removePortEvent(), Device needs to be handled properly
699 removePortEvent(portEvt);
Yuta HIGUCHI76df2472014-02-12 22:36:51 -0800700 }
701
702 boolean removed = switches.remove(swEvt.getDpid(), sw);
703 if (removed) {
704 log.warn(
705 "Switch instance was replaced concurrently while removing {}. Something is not right.",
706 sw);
707 }
708 }
709
710 void putPort(PortEvent portEvt) {
711 if (portEvt == null) {
712 throw new IllegalArgumentException("Port cannot be null");
713 }
714 Switch sw = switches.get(portEvt.getDpid());
715 if (sw == null) {
716 throw new BrokenInvariantException(String.format(
717 "Switch with dpid %s did not exist.",
718 new Dpid(portEvt.getDpid())));
719 }
720 Port p = sw.getPort(portEvt.getNumber());
721 PortImpl port = null;
722 if (p != null) {
723 port = getPortImpl(p);
724 }
725
726 if (port == null) {
727 port = new PortImpl(this, sw, portEvt.getNumber());
728 }
729
730 // TODO update attributes
731
732 SwitchImpl s = getSwitchImpl(sw);
733 s.addPort(port);
734 }
735
736 void removePort(PortEvent portEvt) {
737 if (portEvt == null) {
738 throw new IllegalArgumentException("Port cannot be null");
739 }
740
741 Switch sw = switches.get(portEvt.getDpid());
742 if (sw == null) {
743 log.warn("Parent Switch for Port {} already removed, ignoring", portEvt);
744 return;
745 }
746
747 Port p = sw.getPort(portEvt.getNumber());
748 if (p == null) {
749 log.warn("Port {} already removed, ignoring", portEvt);
750 return;
751 }
752
Yuta HIGUCHIde040642014-02-17 11:03:39 -0800753 // Remove Link and Device Attachment
754 for (Device device : p.getDevices()) {
755 log.debug("Removing Device {} on Port {}", device, portEvt);
756 DeviceEvent devEvt = new DeviceEvent(device.getMacAddress());
757 devEvt.addAttachmentPoint(new SwitchPort(p.getSwitch().getDpid(), p.getNumber()));
Yuta HIGUCHI76df2472014-02-12 22:36:51 -0800758
Yuta HIGUCHIde040642014-02-17 11:03:39 -0800759 // XXX calling removeDeviceEvent() may trigger duplicate event, once at prepare phase, second time here
760 // If event can be squashed, ignored etc. at receiver side it shouldn't be a problem, but if not
761 // need to re-visit
762
763 // calling Discovery API to wipe from DB, etc.
764 removeDeviceEvent(devEvt);
Yuta HIGUCHI76df2472014-02-12 22:36:51 -0800765 }
Yuta HIGUCHIde040642014-02-17 11:03:39 -0800766 Set<Link> links = new HashSet<>();
767 links.add(p.getOutgoingLink());
768 links.add(p.getIncomingLink());
769 ArrayList<LinkEvent> linksToRemove = new ArrayList<>();
770 for (Link link : links) {
771 if (link == null) {
772 continue;
773 }
774 log.debug("Removing Link {} on Port {}", link, portEvt);
775 LinkEvent linkEvent = new LinkEvent(link.getSourceSwitchDpid(), link.getSourcePortNumber(), link.getDestinationSwitchDpid(), link.getDestinationPortNumber());
776 linksToRemove.add(linkEvent);
Yuta HIGUCHI76df2472014-02-12 22:36:51 -0800777 }
Yuta HIGUCHIde040642014-02-17 11:03:39 -0800778 for (LinkEvent linkEvent : linksToRemove) {
779 // XXX calling removeLinkEvent() may trigger duplicate event, once at prepare phase, second time here
780 // If event can be squashed, ignored etc. at receiver side it shouldn't be a problem, but if not
781 // need to re-visit
782
783 // calling Discovery API to wipe from DB, etc.
784 removeLinkEvent(linkEvent);
Yuta HIGUCHI76df2472014-02-12 22:36:51 -0800785 }
786
787 // remove Port from Switch
788 SwitchImpl s = getSwitchImpl(sw);
789 s.removePort(p);
790 }
791
792 void putLink(LinkEvent linkEvt) {
793 if (linkEvt == null) {
794 throw new IllegalArgumentException("Link cannot be null");
795 }
796
797 Switch srcSw = switches.get(linkEvt.getSrc().dpid);
798 if (srcSw == null) {
799 throw new BrokenInvariantException(
800 String.format(
801 "Switch with dpid %s did not exist.",
802 new Dpid(linkEvt.getSrc().dpid)));
803 }
804
805 Switch dstSw = switches.get(linkEvt.getDst().dpid);
806 if (dstSw == null) {
807 throw new BrokenInvariantException(
808 String.format(
809 "Switch with dpid %s did not exist.",
810 new Dpid(linkEvt.getDst().dpid)));
811 }
812
813 Port srcPort = srcSw.getPort(linkEvt.getSrc().number);
814 if (srcPort == null) {
815 throw new BrokenInvariantException(
816 String.format(
817 "Src Port %s of a Link did not exist.",
818 linkEvt.getSrc() ));
819 }
820
821 Port dstPort = dstSw.getPort(linkEvt.getDst().number);
822 if (dstPort == null) {
823 throw new BrokenInvariantException(
824 String.format(
825 "Dst Port %s of a Link did not exist.",
826 linkEvt.getDst() ));
827 }
828
829 // getting Link instance from destination port incoming Link
830 Link l = dstPort.getIncomingLink();
831 LinkImpl link = null;
832 assert( l == srcPort.getOutgoingLink() );
833 if (l != null) {
834 link = getLinkImpl(l);
835 }
836
837 if (link == null) {
838 link = new LinkImpl(this, srcPort, dstPort);
839 }
840
841
842 PortImpl dstPortMem = getPortImpl(dstPort);
843 PortImpl srcPortMem = getPortImpl(srcPort);
844
845 // Add Link first to avoid further Device addition
846
847 // add Link to Port
848 dstPortMem.setIncomingLink(link);
849 srcPortMem.setOutgoingLink(link);
850
851 // remove Device Pointing to Port if any
852 for(Device d : dstPortMem.getDevices() ) {
853 log.error("Device {} on Port {} should have been removed prior to adding Link {}", d, dstPort, linkEvt);
854 DeviceImpl dev = getDeviceImpl(d);
855 dev.removeAttachmentPoint(dstPort);
Yuta HIGUCHI407261a2014-02-13 16:34:06 -0800856 // This implies that change is made to Device Object.
857 // sending Device attachment point removed event
858 DeviceEvent rmEvent = new DeviceEvent(d.getMacAddress());
859 rmEvent.addAttachmentPoint(new SwitchPort(dstPort.getDpid(), dstPort.getNumber()));
860 removeDeviceEvent(rmEvent);
Yuta HIGUCHI76df2472014-02-12 22:36:51 -0800861 }
862 dstPortMem.removeAllDevice();
863 for(Device d : srcPortMem.getDevices() ) {
864 log.error("Device {} on Port {} should have been removed prior to adding Link {}", d, srcPort, linkEvt);
865 DeviceImpl dev = getDeviceImpl(d);
866 dev.removeAttachmentPoint(srcPort);
Yuta HIGUCHI407261a2014-02-13 16:34:06 -0800867 // This implies that change is made to Device Object.
868 // sending Device attachment point removed event
869 DeviceEvent rmEvent = new DeviceEvent(d.getMacAddress());
870 rmEvent.addAttachmentPoint(new SwitchPort(dstPort.getDpid(), dstPort.getNumber()));
871 removeDeviceEvent(rmEvent);
Yuta HIGUCHI76df2472014-02-12 22:36:51 -0800872 }
873 srcPortMem.removeAllDevice();
874
875 }
876
877 void removeLink(LinkEvent linkEvt) {
878 if (linkEvt == null) {
879 throw new IllegalArgumentException("Link cannot be null");
880 }
881
882 Switch srcSw = switches.get(linkEvt.getSrc().dpid);
883 if (srcSw == null) {
884 log.warn("Src Switch for Link {} already removed, ignoring", linkEvt);
885 return;
886 }
887
888 Switch dstSw = switches.get(linkEvt.getDst().dpid);
889 if (dstSw == null) {
890 log.warn("Dst Switch for Link {} already removed, ignoring", linkEvt);
891 return;
892 }
893
894 Port srcPort = srcSw.getPort(linkEvt.getSrc().number);
895 if (srcPort == null) {
896 log.warn("Src Port for Link {} already removed, ignoring", linkEvt);
897 return;
898 }
899
900 Port dstPort = dstSw.getPort(linkEvt.getDst().number);
901 if (dstPort == null) {
902 log.warn("Dst Port for Link {} already removed, ignoring", linkEvt);
903 return;
904 }
905
906 Link l = dstPort.getIncomingLink();
907 if ( l == null ) {
908 log.warn("Link {} already removed on destination Port", linkEvt);
909 }
910 l = srcPort.getOutgoingLink();
911 if ( l == null ) {
912 log.warn("Link {} already removed on src Port", linkEvt);
913 }
914
915 getPortImpl(dstPort).setIncomingLink(null);
916 getPortImpl(srcPort).setOutgoingLink(null);
917 }
918
919 // XXX Need to rework Device related
920 void putDevice(DeviceEvent deviceEvt) {
921 if (deviceEvt == null) {
922 throw new IllegalArgumentException("Device cannot be null");
923 }
924
925 Device device = getDeviceByMac(deviceEvt.getMac());
926 if ( device == null ) {
927 device = new DeviceImpl(this, deviceEvt.getMac());
928 Device existing = mac2Device.putIfAbsent(deviceEvt.getMac(), device);
929 if (existing != null) {
930 log.warn(
931 "Concurrent putDevice seems to be in action. Continuing updating {}",
932 existing);
933 device = existing;
934 }
935 }
936 DeviceImpl memDevice = getDeviceImpl(device);
937
938 // for each attachment point
939 for (SwitchPort swp : deviceEvt.getAttachmentPoints() ) {
940 // Attached Ports' Parent Switch must exist
941 Switch sw = getSwitch(swp.dpid);
942 if ( sw == null ) {
Yuta HIGUCHI25719052014-02-13 14:42:06 -0800943 log.warn("Switch for the attachment point {} did not exist. skipping mutation", swp);
Yuta HIGUCHI76df2472014-02-12 22:36:51 -0800944 continue;
945 }
946 // Attached Ports must exist
947 Port port = sw.getPort(swp.number);
948 if ( port == null ) {
Yuta HIGUCHI25719052014-02-13 14:42:06 -0800949 log.warn("Port for the attachment point {} did not exist. skipping mutation", swp);
Yuta HIGUCHI76df2472014-02-12 22:36:51 -0800950 continue;
951 }
952 // Attached Ports must not have Link
953 if ( port.getOutgoingLink() != null || port.getIncomingLink() != null ) {
954 log.warn("Link (Out:{},In:{}) exist on the attachment point, skipping mutation.", port.getOutgoingLink(), port.getIncomingLink());
955 continue;
956 }
957
958 // finally add Device <-> Port on In-memory structure
959 PortImpl memPort = getPortImpl(port);
960 memPort.addDevice(device);
961 memDevice.addAttachmentPoint(port);
962 }
963
964 // for each IP address
965 for( InetAddress ipAddr : deviceEvt.getIpAddresses() ) {
966 // Add Device -> IP
967 memDevice.addIpAddress(ipAddr);
968
969 // Add IP -> Set<Device>
970 boolean updated = false;
971 do {
972 Set<Device> devices = this.addr2Device.get(ipAddr);
973 if ( devices == null ) {
974 devices = new HashSet<>();
975 Set<Device> existing = this.addr2Device.putIfAbsent(ipAddr, devices);
976 if ( existing == null ) {
977 // success
978 updated = true;
979 }
980 } else {
981 Set<Device> updateDevices = new HashSet<>(devices);
982 updateDevices.add(device);
983 updated = this.addr2Device.replace(ipAddr, devices, updateDevices);
984 }
985 if (!updated) {
986 log.debug("Collision detected, updating IP to Device mapping retrying.");
987 }
988 } while( !updated );
989 }
990 }
991
992 void removeDevice(DeviceEvent deviceEvt) {
993 if (deviceEvt == null) {
994 throw new IllegalArgumentException("Device cannot be null");
995 }
996
997 Device device = getDeviceByMac(deviceEvt.getMac());
998 if ( device == null ) {
999 log.warn("Device {} already removed, ignoring", deviceEvt);
1000 return;
1001 }
1002 DeviceImpl memDevice = getDeviceImpl(device);
1003
1004 // for each attachment point
1005 for (SwitchPort swp : deviceEvt.getAttachmentPoints() ) {
1006 // Attached Ports' Parent Switch must exist
1007 Switch sw = getSwitch(swp.dpid);
1008 if ( sw == null ) {
Yuta HIGUCHI25719052014-02-13 14:42:06 -08001009 log.warn("Switch for the attachment point {} did not exist. skipping attachment point mutation", swp);
Yuta HIGUCHI76df2472014-02-12 22:36:51 -08001010 continue;
1011 }
1012 // Attached Ports must exist
1013 Port port = sw.getPort(swp.number);
1014 if ( port == null ) {
Yuta HIGUCHI25719052014-02-13 14:42:06 -08001015 log.warn("Port for the attachment point {} did not exist. skipping attachment point mutation", swp);
Yuta HIGUCHI76df2472014-02-12 22:36:51 -08001016 continue;
1017 }
1018
1019 // finally remove Device <-> Port on In-memory structure
1020 PortImpl memPort = getPortImpl(port);
1021 memPort.removeDevice(device);
1022 memDevice.removeAttachmentPoint(port);
1023 }
1024
1025 // for each IP address
1026 for( InetAddress ipAddr : deviceEvt.getIpAddresses() ) {
1027 // Remove Device -> IP
1028 memDevice.removeIpAddress(ipAddr);
1029
1030 // Remove IP -> Set<Device>
1031 boolean updated = false;
1032 do {
1033 Set<Device> devices = this.addr2Device.get(ipAddr);
1034 if ( devices == null ) {
1035 // already empty set, nothing to do
1036 updated = true;
1037 } else {
1038 Set<Device> updateDevices = new HashSet<>(devices);
1039 updateDevices.remove(device);
1040 updated = this.addr2Device.replace(ipAddr, devices, updateDevices);
1041 }
1042 if (!updated) {
1043 log.debug("Collision detected, updating IP to Device mapping retrying.");
1044 }
1045 } while( !updated );
1046 }
1047 }
1048
1049 private SwitchImpl getSwitchImpl(Switch sw) {
1050 if (sw instanceof SwitchImpl) {
1051 return (SwitchImpl) sw;
1052 }
1053 throw new ClassCastException("SwitchImpl expected, but found: " + sw);
1054 }
1055
1056 private PortImpl getPortImpl(Port p) {
1057 if (p instanceof PortImpl) {
1058 return (PortImpl) p;
1059 }
1060 throw new ClassCastException("PortImpl expected, but found: " + p);
1061 }
1062
1063 private LinkImpl getLinkImpl(Link l) {
1064 if (l instanceof LinkImpl) {
1065 return (LinkImpl) l;
1066 }
1067 throw new ClassCastException("LinkImpl expected, but found: " + l);
1068 }
1069
1070 private DeviceImpl getDeviceImpl(Device d) {
1071 if (d instanceof DeviceImpl) {
1072 return (DeviceImpl) d;
1073 }
1074 throw new ClassCastException("DeviceImpl expected, but found: " + d);
1075 }
1076
1077 @Deprecated
1078 public void loadWholeTopologyFromDB() {
Yuta HIGUCHI0a4bd192014-02-17 13:52:34 -08001079 // XXX May need to clear whole topology first, depending on
1080 // how we initially subscribe to replication events
Yuta HIGUCHI76df2472014-02-12 22:36:51 -08001081
1082 for (RCSwitch sw : RCSwitch.getAllSwitches()) {
1083 if ( sw.getStatus() != RCSwitch.STATUS.ACTIVE ) {
1084 continue;
1085 }
1086 putSwitchReplicationEvent(new SwitchEvent(sw.getDpid()));
1087 }
1088
1089 for (RCPort p : RCPort.getAllPorts()) {
1090 if (p.getStatus() != RCPort.STATUS.ACTIVE) {
1091 continue;
1092 }
1093 putPortReplicationEvent(new PortEvent(p.getDpid(), p.getNumber() ));
1094 }
1095
1096 // TODO Is Device going to be in DB? If so, read from DB.
1097 // for (RCDevice d : RCDevice.getAllDevices()) {
1098 // DeviceEvent devEvent = new DeviceEvent( MACAddress.valueOf(d.getMac()) );
1099 // for (byte[] portId : d.getAllPortIds() ) {
1100 // devEvent.addAttachmentPoint( new SwitchPort( RCPort.getDpidFromKey(portId), RCPort.getNumberFromKey(portId) ));
1101 // }
1102 // }
1103
1104 for (RCLink l : RCLink.getAllLinks()) {
Yuta HIGUCHI0a4bd192014-02-17 13:52:34 -08001105 // TODO check if src/dst switch/port exist before triggering event
Yuta HIGUCHI76df2472014-02-12 22:36:51 -08001106 putLinkReplicationEvent( new LinkEvent(l.getSrc().dpid, l.getSrc().number, l.getDst().dpid, l.getDst().number));
1107 }
1108 }
Jonathan Hart062a2e82014-02-03 09:41:57 -08001109}