blob: 4d56fedc0ebabd41dcb4084dacab82e782b33e82 [file] [log] [blame]
Jonathan Hart062a2e82014-02-03 09:41:57 -08001package net.onrc.onos.ofcontroller.networkgraph;
2
Yuta HIGUCHI1c700102014-02-12 16:30:52 -08003import java.net.InetAddress;
Yuta HIGUCHI8d762e92014-02-12 14:10:25 -08004import java.util.ArrayList;
Pavlin Radoslavov721a2e02014-02-14 23:40:14 -08005import java.util.Collection;
Yuta HIGUCHI8d762e92014-02-12 14:10:25 -08006import java.util.HashSet;
Pavlin Radoslavov721a2e02014-02-14 23:40:14 -08007import java.util.LinkedList;
Yuta HIGUCHI8d762e92014-02-12 14:10:25 -08008import java.util.List;
9import java.util.Set;
Pavlin Radoslavov721a2e02014-02-14 23:40:14 -080010import java.util.concurrent.BlockingQueue;
Yuta HIGUCHIa536e762014-02-17 21:47:28 -080011import java.util.concurrent.CopyOnWriteArrayList;
Pavlin Radoslavov721a2e02014-02-14 23:40:14 -080012import java.util.concurrent.LinkedBlockingQueue;
Yuta HIGUCHI8d762e92014-02-12 14:10:25 -080013
Pavlin Radoslavov721a2e02014-02-14 23:40:14 -080014import net.onrc.onos.datagrid.IDatagridService;
15import net.onrc.onos.datagrid.IEventChannel;
16import net.onrc.onos.datagrid.IEventChannelListener;
Yuta HIGUCHI765cd0d2014-02-06 12:46:41 -080017import net.onrc.onos.datastore.topology.RCLink;
Jonathan Hart062a2e82014-02-03 09:41:57 -080018import net.onrc.onos.datastore.topology.RCPort;
19import net.onrc.onos.datastore.topology.RCSwitch;
Yuta HIGUCHI8d762e92014-02-12 14:10:25 -080020import net.onrc.onos.ofcontroller.networkgraph.PortEvent.SwitchPort;
Pavlin Radoslavov721a2e02014-02-14 23:40:14 -080021import net.onrc.onos.ofcontroller.util.EventEntry;
Yuta HIGUCHI765cd0d2014-02-06 12:46:41 -080022import net.onrc.onos.ofcontroller.util.Dpid;
Yuta HIGUCHI170229f2014-02-17 15:47:54 -080023import net.onrc.onos.registry.controller.IControllerRegistryService;
Jonathan Hart062a2e82014-02-03 09:41:57 -080024
25import org.slf4j.Logger;
26import org.slf4j.LoggerFactory;
27
Yuta HIGUCHI181d34d2014-02-05 15:05:46 -080028/**
29 * The "NB" read-only Network Map.
30 *
Yuta HIGUCHI4bfdd532014-02-07 13:47:36 -080031 * - Maintain Invariant/Relationships between Topology Objects.
32 *
Yuta HIGUCHI765cd0d2014-02-06 12:46:41 -080033 * TODO To be synchronized based on TopologyEvent Notification.
Yuta HIGUCHI181d34d2014-02-05 15:05:46 -080034 *
Yuta HIGUCHIcb951982014-02-11 13:31:44 -080035 * TODO TBD: Caller is expected to maintain parent/child calling order. Parent
Yuta HIGUCHI1c700102014-02-12 16:30:52 -080036 * Object must exist before adding sub component(Add Switch -> Port).
Yuta HIGUCHIcb951982014-02-11 13:31:44 -080037 *
Yuta HIGUCHI4bfdd532014-02-07 13:47:36 -080038 * TODO TBD: This class may delay the requested change to handle event
39 * re-ordering. e.g.) Link Add came in, but Switch was not there.
Yuta HIGUCHIcb951982014-02-11 13:31:44 -080040 *
Yuta HIGUCHI181d34d2014-02-05 15:05:46 -080041 */
Pavlin Radoslavov6d224ee2014-02-18 16:43:15 -080042public class TopologyManager implements NetworkGraphDiscoveryInterface,
43 NetworkGraphReplicationInterface {
Jonathan Hart062a2e82014-02-03 09:41:57 -080044
Yuta HIGUCHI80829d12014-02-05 20:16:56 -080045 private static final Logger log = LoggerFactory
Pavlin Radoslavovdb7dbb22014-02-18 14:45:10 -080046 .getLogger(TopologyManager.class);
Yuta HIGUCHIcd922f42014-02-11 18:59:11 -080047
Pavlin Radoslavov721a2e02014-02-14 23:40:14 -080048 private IEventChannel<byte[], TopologyEvent> eventChannel;
49 private static final String EVENT_CHANNEL_NAME = "onos.topology";
50 private EventHandler eventHandler = new EventHandler();
51
Jonathan Hart22eb9882014-02-11 15:52:59 -080052 private final NetworkGraphDatastore datastore;
Pavlin Radoslavov6d224ee2014-02-18 16:43:15 -080053 private final NetworkGraphImpl networkGraph = new NetworkGraphImpl();
Yuta HIGUCHI170229f2014-02-17 15:47:54 -080054 private final IControllerRegistryService registryService;
Yuta HIGUCHIa536e762014-02-17 21:47:28 -080055 private CopyOnWriteArrayList<INetworkGraphListener> networkGraphListeners;
Yuta HIGUCHI181d34d2014-02-05 15:05:46 -080056
Pavlin Radoslavovdb7dbb22014-02-18 14:45:10 -080057 public TopologyManager(IControllerRegistryService registryService, CopyOnWriteArrayList<INetworkGraphListener> networkGraphListeners) {
Jonathan Hart22eb9882014-02-11 15:52:59 -080058 datastore = new NetworkGraphDatastore(this);
Yuta HIGUCHI170229f2014-02-17 15:47:54 -080059 this.registryService = registryService;
Yuta HIGUCHIa536e762014-02-17 21:47:28 -080060 this.networkGraphListeners = networkGraphListeners;
Yuta HIGUCHI80829d12014-02-05 20:16:56 -080061 }
Yuta HIGUCHI181d34d2014-02-05 15:05:46 -080062
Pavlin Radoslavov6d224ee2014-02-18 16:43:15 -080063 NetworkGraph getNetworkGraph() {
64 return networkGraph;
65 }
66
Yuta HIGUCHI4bfdd532014-02-07 13:47:36 -080067 /**
Pavlin Radoslavov721a2e02014-02-14 23:40:14 -080068 * Event handler class.
69 */
70 private class EventHandler extends Thread implements
71 IEventChannelListener<byte[], TopologyEvent> {
72 private BlockingQueue<EventEntry<TopologyEvent>> topologyEvents =
73 new LinkedBlockingQueue<EventEntry<TopologyEvent>>();
74
75 /**
76 * Startup processing.
77 */
78 private void startup() {
79 //
80 // TODO: Read all state from the database
81 // For now, as a shortcut we read it from the datagrid
82 //
83 Collection<TopologyEvent> topologyEvents =
84 eventChannel.getAllEntries();
85 Collection<EventEntry<TopologyEvent>> collection =
86 new LinkedList<EventEntry<TopologyEvent>>();
87
88 for (TopologyEvent topologyEvent : topologyEvents) {
89 EventEntry<TopologyEvent> eventEntry =
90 new EventEntry<TopologyEvent>(EventEntry.Type.ENTRY_ADD,
91 topologyEvent);
92 collection.add(eventEntry);
93 }
94 processEvents(collection);
95 }
96
97 /**
98 * Run the thread.
99 */
Yuta HIGUCHI240bf072014-02-17 10:55:21 -0800100 @Override
Pavlin Radoslavov721a2e02014-02-14 23:40:14 -0800101 public void run() {
102 Collection<EventEntry<TopologyEvent>> collection =
103 new LinkedList<EventEntry<TopologyEvent>>();
104
Pavlin Radoslavovdb7dbb22014-02-18 14:45:10 -0800105 this.setName("TopologyManager.EventHandler " + this.getId());
Pavlin Radoslavov721a2e02014-02-14 23:40:14 -0800106 startup();
107
108 //
109 // The main loop
110 //
111 try {
112 while (true) {
113 EventEntry<TopologyEvent> eventEntry = topologyEvents.take();
114 collection.add(eventEntry);
115 topologyEvents.drainTo(collection);
116
117 processEvents(collection);
118 collection.clear();
119 }
120 } catch (Exception exception) {
121 log.debug("Exception processing Topology Events: ", exception);
122 }
123 }
124
125 /**
126 * Process all topology events.
127 *
128 * @param events the events to process.
129 */
130 private void processEvents(Collection<EventEntry<TopologyEvent>> events) {
131 for (EventEntry<TopologyEvent> event : events) {
Yuta HIGUCHI170229f2014-02-17 15:47:54 -0800132 if (event.eventData().getOriginID().equals(registryService.getControllerId())) {
133 // ignore event triggered by myself
134 continue;
135 }
Pavlin Radoslavov721a2e02014-02-14 23:40:14 -0800136 TopologyEvent topologyEvent = event.eventData();
137 switch (event.eventType()) {
138 case ENTRY_ADD:
139 log.debug("Topology event ENTRY_ADD: {}", topologyEvent);
140 if (topologyEvent.switchEvent != null)
141 putSwitchReplicationEvent(topologyEvent.switchEvent);
142 if (topologyEvent.portEvent != null)
143 putPortReplicationEvent(topologyEvent.portEvent);
144 if (topologyEvent.linkEvent != null)
145 putLinkReplicationEvent(topologyEvent.linkEvent);
146 if (topologyEvent.deviceEvent != null)
147 putDeviceReplicationEvent(topologyEvent.deviceEvent);
148 break;
149 case ENTRY_REMOVE:
150 log.debug("Topology event ENTRY_REMOVE: {}", topologyEvent);
151 if (topologyEvent.switchEvent != null)
152 removeSwitchReplicationEvent(topologyEvent.switchEvent);
153 if (topologyEvent.portEvent != null)
154 removePortReplicationEvent(topologyEvent.portEvent);
155 if (topologyEvent.linkEvent != null)
156 removeLinkReplicationEvent(topologyEvent.linkEvent);
157 if (topologyEvent.deviceEvent != null)
158 removeDeviceReplicationEvent(topologyEvent.deviceEvent);
159 break;
160 }
161 }
162 }
163
164 /**
165 * Receive a notification that an entry is added.
166 *
167 * @param value the value for the entry.
168 */
169 @Override
170 public void entryAdded(TopologyEvent value) {
171 EventEntry<TopologyEvent> eventEntry =
172 new EventEntry<TopologyEvent>(EventEntry.Type.ENTRY_ADD,
173 value);
174 topologyEvents.add(eventEntry);
175 }
176
177 /**
178 * Receive a notification that an entry is removed.
179 *
180 * @param value the value for the entry.
181 */
182 @Override
183 public void entryRemoved(TopologyEvent value) {
184 EventEntry<TopologyEvent> eventEntry =
185 new EventEntry<TopologyEvent>(EventEntry.Type.ENTRY_REMOVE,
186 value);
187 topologyEvents.add(eventEntry);
188 }
189
190 /**
191 * Receive a notification that an entry is updated.
192 *
193 * @param value the value for the entry.
194 */
195 @Override
196 public void entryUpdated(TopologyEvent value) {
197 // NOTE: The ADD and UPDATE events are processed in same way
198 entryAdded(value);
199 }
200 }
201
202 /**
203 * Startup processing.
204 *
205 * @param datagridService the datagrid service to use.
206 */
207 void startup(IDatagridService datagridService) {
208 eventChannel = datagridService.addListener(EVENT_CHANNEL_NAME,
209 eventHandler,
210 byte[].class,
211 TopologyEvent.class);
212 eventHandler.start();
213 }
214
215 /**
Yuta HIGUCHIcb951982014-02-11 13:31:44 -0800216 * Exception to be thrown when Modification to the Network Graph cannot be continued due to broken invariant.
217 *
218 * XXX Should this be checked exception or RuntimeException
219 */
220 public static class BrokenInvariantException extends RuntimeException {
221 private static final long serialVersionUID = 1L;
222
223 public BrokenInvariantException() {
224 super();
225 }
226
227 public BrokenInvariantException(String message) {
228 super(message);
229 }
230 }
Jonathan Hart22eb9882014-02-11 15:52:59 -0800231
232 /* ******************************
233 * NetworkGraphDiscoveryInterface methods
234 * ******************************/
Yuta HIGUCHIcd922f42014-02-11 18:59:11 -0800235
Jonathan Hart22eb9882014-02-11 15:52:59 -0800236 @Override
237 public void putSwitchEvent(SwitchEvent switchEvent) {
Yuta HIGUCHId02e9282014-02-12 09:24:41 -0800238 if (prepareForAddSwitchEvent(switchEvent)) {
Jonathan Hart22eb9882014-02-11 15:52:59 -0800239 datastore.addSwitch(switchEvent);
240 putSwitch(switchEvent);
Pavlin Radoslavov721a2e02014-02-14 23:40:14 -0800241 // Send out notification
242 TopologyEvent topologyEvent =
Yuta HIGUCHI170229f2014-02-17 15:47:54 -0800243 new TopologyEvent(switchEvent, registryService.getControllerId());
Pavlin Radoslavov721a2e02014-02-14 23:40:14 -0800244 eventChannel.addEntry(topologyEvent.getID(),
245 topologyEvent);
Jonathan Hart22eb9882014-02-11 15:52:59 -0800246 }
247 // TODO handle invariant violation
248 }
249
250 @Override
251 public void removeSwitchEvent(SwitchEvent switchEvent) {
Yuta HIGUCHId02e9282014-02-12 09:24:41 -0800252 if (prepareForRemoveSwitchEvent(switchEvent)) {
Jonathan Hart22eb9882014-02-11 15:52:59 -0800253 datastore.deactivateSwitch(switchEvent);
254 removeSwitch(switchEvent);
Pavlin Radoslavov721a2e02014-02-14 23:40:14 -0800255 // Send out notification
256 eventChannel.removeEntry(switchEvent.getID());
Jonathan Hart22eb9882014-02-11 15:52:59 -0800257 }
258 // TODO handle invariant violation
259 }
260
261 @Override
262 public void putPortEvent(PortEvent portEvent) {
Jonathan Hart4c263272014-02-13 17:41:05 -0800263 if (prepareForAddPortEvent(portEvent)) {
264 datastore.addPort(portEvent);
265 putPort(portEvent);
Pavlin Radoslavov721a2e02014-02-14 23:40:14 -0800266 // Send out notification
267 TopologyEvent topologyEvent =
Yuta HIGUCHI170229f2014-02-17 15:47:54 -0800268 new TopologyEvent(portEvent, registryService.getControllerId());
Pavlin Radoslavov721a2e02014-02-14 23:40:14 -0800269 eventChannel.addEntry(topologyEvent.getID(),
270 topologyEvent);
Jonathan Hart4c263272014-02-13 17:41:05 -0800271 }
Yuta HIGUCHI75c51ed2014-02-13 17:02:26 -0800272 // TODO handle invariant violation
Jonathan Hart22eb9882014-02-11 15:52:59 -0800273 }
274
275 @Override
276 public void removePortEvent(PortEvent portEvent) {
Jonathan Hart4c263272014-02-13 17:41:05 -0800277 if (prepareForRemovePortEvent(portEvent)) {
278 datastore.deactivatePort(portEvent);
279 removePort(portEvent);
Pavlin Radoslavov721a2e02014-02-14 23:40:14 -0800280 // Send out notification
281 eventChannel.removeEntry(portEvent.getID());
Jonathan Hart4c263272014-02-13 17:41:05 -0800282 }
Yuta HIGUCHI75c51ed2014-02-13 17:02:26 -0800283 // TODO handle invariant violation
Jonathan Hart22eb9882014-02-11 15:52:59 -0800284 }
285
286 @Override
287 public void putLinkEvent(LinkEvent linkEvent) {
Yuta HIGUCHId02e9282014-02-12 09:24:41 -0800288 if (prepareForAddLinkEvent(linkEvent)) {
Jonathan Hart22eb9882014-02-11 15:52:59 -0800289 datastore.addLink(linkEvent);
290 putLink(linkEvent);
Pavlin Radoslavov721a2e02014-02-14 23:40:14 -0800291 // Send out notification
292 TopologyEvent topologyEvent =
Yuta HIGUCHI170229f2014-02-17 15:47:54 -0800293 new TopologyEvent(linkEvent, registryService.getControllerId());
Pavlin Radoslavov721a2e02014-02-14 23:40:14 -0800294 eventChannel.addEntry(topologyEvent.getID(),
295 topologyEvent);
Jonathan Hart22eb9882014-02-11 15:52:59 -0800296 }
297 // TODO handle invariant violation
298 }
299
300 @Override
301 public void removeLinkEvent(LinkEvent linkEvent) {
Yuta HIGUCHI71e7a052014-02-17 22:14:15 -0800302 removeLinkEvent(linkEvent, false);
303
304 }
305
306 private void removeLinkEvent(LinkEvent linkEvent, boolean dstCheckBeforeDBmodify) {
Yuta HIGUCHId02e9282014-02-12 09:24:41 -0800307 if (prepareForRemoveLinkEvent(linkEvent)) {
Yuta HIGUCHI71e7a052014-02-17 22:14:15 -0800308 if (dstCheckBeforeDBmodify) {
309 // write to DB only if it is owner of the dst dpid
310 if (registryService.hasControl(linkEvent.getDst().dpid)) {
311 datastore.removeLink(linkEvent);
312 }
313 } else {
314 datastore.removeLink(linkEvent);
315 }
Jonathan Hart22eb9882014-02-11 15:52:59 -0800316 removeLink(linkEvent);
Pavlin Radoslavov721a2e02014-02-14 23:40:14 -0800317 // Send out notification
318 eventChannel.removeEntry(linkEvent.getID());
Jonathan Hart22eb9882014-02-11 15:52:59 -0800319 }
320 // TODO handle invariant violation
321 }
322
323 @Override
Yuta HIGUCHI586d33e2014-02-13 17:05:08 -0800324 public void putDeviceEvent(DeviceEvent deviceEvent) {
325 if (prepareForAddDeviceEvent(deviceEvent)) {
326// datastore.addDevice(deviceEvent);
Yuta HIGUCHId457c052014-02-14 18:33:04 -0800327// putDevice(deviceEvent);
Pavlin Radoslavov721a2e02014-02-14 23:40:14 -0800328 // Send out notification
329 TopologyEvent topologyEvent =
Yuta HIGUCHI170229f2014-02-17 15:47:54 -0800330 new TopologyEvent(deviceEvent, registryService.getControllerId());
Pavlin Radoslavov721a2e02014-02-14 23:40:14 -0800331 eventChannel.addEntry(topologyEvent.getID(),
332 topologyEvent);
Yuta HIGUCHI586d33e2014-02-13 17:05:08 -0800333 }
334 // TODO handle invariant violation
335 // XXX if prepareFor~ method returned false, event should be dropped
Jonathan Hart22eb9882014-02-11 15:52:59 -0800336 }
337
338 @Override
339 public void removeDeviceEvent(DeviceEvent deviceEvent) {
Yuta HIGUCHI586d33e2014-02-13 17:05:08 -0800340 if (prepareForRemoveDeviceEvent(deviceEvent)) {
341// datastore.removeDevice(deviceEvent);
Yuta HIGUCHId457c052014-02-14 18:33:04 -0800342// removeDevice(deviceEvent);
Pavlin Radoslavov721a2e02014-02-14 23:40:14 -0800343 // Send out notification
344 eventChannel.removeEntry(deviceEvent.getID());
Yuta HIGUCHI586d33e2014-02-13 17:05:08 -0800345 }
346 // TODO handle invariant violation
347 // XXX if prepareFor~ method returned false, event should be dropped
Jonathan Hart22eb9882014-02-11 15:52:59 -0800348 }
Yuta HIGUCHIcd922f42014-02-11 18:59:11 -0800349
Jonathan Hart22eb9882014-02-11 15:52:59 -0800350 /* *****************
Yuta HIGUCHId02e9282014-02-12 09:24:41 -0800351 * Internal methods to maintain invariants of the network graph
Jonathan Hart22eb9882014-02-11 15:52:59 -0800352 * *****************/
Yuta HIGUCHIcd922f42014-02-11 18:59:11 -0800353
Yuta HIGUCHId02e9282014-02-12 09:24:41 -0800354 /**
355 *
356 * @param swEvt
357 * @return true if ready to accept event.
358 */
359 private boolean prepareForAddSwitchEvent(SwitchEvent swEvt) {
Yuta HIGUCHI76df2472014-02-12 22:36:51 -0800360 // No show stopping precondition
Yuta HIGUCHI8d762e92014-02-12 14:10:25 -0800361 // Prep: remove(deactivate) Ports on Switch, which is not on event
362 removePortsNotOnEvent(swEvt);
363 return true;
Jonathan Hart22eb9882014-02-11 15:52:59 -0800364 }
Yuta HIGUCHIcd922f42014-02-11 18:59:11 -0800365
Yuta HIGUCHId02e9282014-02-12 09:24:41 -0800366 private boolean prepareForRemoveSwitchEvent(SwitchEvent swEvt) {
Yuta HIGUCHI76df2472014-02-12 22:36:51 -0800367 // No show stopping precondition
Yuta HIGUCHI8d762e92014-02-12 14:10:25 -0800368 // Prep: remove(deactivate) Ports on Switch, which is not on event
369 // XXX may be remove switch should imply wipe all ports
370 removePortsNotOnEvent(swEvt);
371 return true;
372 }
Yuta HIGUCHId02e9282014-02-12 09:24:41 -0800373
Yuta HIGUCHI8d762e92014-02-12 14:10:25 -0800374 private void removePortsNotOnEvent(SwitchEvent swEvt) {
Pavlin Radoslavov6d224ee2014-02-18 16:43:15 -0800375 Switch sw = networkGraph.getSwitch(swEvt.getDpid());
Yuta HIGUCHI8d762e92014-02-12 14:10:25 -0800376 if ( sw != null ) {
377 Set<Long> port_noOnEvent = new HashSet<>();
378 for( PortEvent portEvent : swEvt.getPorts()) {
379 port_noOnEvent.add(portEvent.getNumber());
380 }
381 // Existing ports not on event should be removed.
382 // TODO Should batch eventually for performance?
Jonathan Hart480c5572014-02-14 18:28:16 -0800383 List<Port> portsToRemove = new ArrayList<Port>();
Yuta HIGUCHI8d762e92014-02-12 14:10:25 -0800384 for( Port p : sw.getPorts() ) {
385 if ( !port_noOnEvent.contains(p.getNumber()) ) {
Jonathan Hart480c5572014-02-14 18:28:16 -0800386 //PortEvent rmEvent = new PortEvent(p.getSwitch().getDpid(), p.getNumber());
387 // calling Discovery removePort() API to wipe from DB, etc.
388 //removePortEvent(rmEvent);
Yuta HIGUCHI240bf072014-02-17 10:55:21 -0800389
Jonathan Hart480c5572014-02-14 18:28:16 -0800390 // We can't remove ports here because this will trigger a remove
391 // from the switch's port list, which we are currently iterating
392 // over.
393 portsToRemove.add(p);
394 }
395 }
396 for (Port p : portsToRemove) {
Yuta HIGUCHI8d762e92014-02-12 14:10:25 -0800397 PortEvent rmEvent = new PortEvent(p.getSwitch().getDpid(), p.getNumber());
398 // calling Discovery removePort() API to wipe from DB, etc.
399 removePortEvent(rmEvent);
Yuta HIGUCHI8d762e92014-02-12 14:10:25 -0800400 }
401 }
Jonathan Hart22eb9882014-02-11 15:52:59 -0800402 }
Yuta HIGUCHIcd922f42014-02-11 18:59:11 -0800403
Yuta HIGUCHId02e9282014-02-12 09:24:41 -0800404 private boolean prepareForAddPortEvent(PortEvent portEvt) {
Yuta HIGUCHId02e9282014-02-12 09:24:41 -0800405 // Parent Switch must exist
Pavlin Radoslavov6d224ee2014-02-18 16:43:15 -0800406 if ( networkGraph.getSwitch(portEvt.getDpid()) == null) {
Jonathan Hart0a4846e2014-02-18 11:03:40 -0800407 log.warn("Dropping add port event because switch doesn't exist: {}",
408 portEvt);
Yuta HIGUCHId02e9282014-02-12 09:24:41 -0800409 return false;
410 }
411 // Prep: None
Jonathan Hart22eb9882014-02-11 15:52:59 -0800412 return true;
413 }
Yuta HIGUCHIcd922f42014-02-11 18:59:11 -0800414
Yuta HIGUCHId02e9282014-02-12 09:24:41 -0800415 private boolean prepareForRemovePortEvent(PortEvent portEvt) {
Yuta HIGUCHId5315c42014-02-18 09:35:48 -0800416 Port port = getPort(portEvt.getDpid(), portEvt.getNumber());
Yuta HIGUCHI8d762e92014-02-12 14:10:25 -0800417 if ( port == null ) {
418 log.debug("Port already removed? {}", portEvt);
419 // let it pass
420 return true;
421 }
422
423 // Prep: Remove Link and Device Attachment
Yuta HIGUCHI240bf072014-02-17 10:55:21 -0800424 ArrayList<DeviceEvent> deviceEvts = new ArrayList<>();
Yuta HIGUCHI8d762e92014-02-12 14:10:25 -0800425 for (Device device : port.getDevices()) {
Yuta HIGUCHI88be0f22014-02-14 17:20:43 -0800426 log.debug("Removing Device {} on Port {}", device, portEvt);
Yuta HIGUCHI8d762e92014-02-12 14:10:25 -0800427 DeviceEvent devEvt = new DeviceEvent(device.getMacAddress());
428 devEvt.addAttachmentPoint(new SwitchPort(port.getSwitch().getDpid(), port.getNumber()));
Yuta HIGUCHI240bf072014-02-17 10:55:21 -0800429 deviceEvts.add(devEvt);
430 }
431 for (DeviceEvent devEvt : deviceEvts) {
Yuta HIGUCHI8d762e92014-02-12 14:10:25 -0800432 // calling Discovery API to wipe from DB, etc.
433 removeDeviceEvent(devEvt);
434 }
Yuta HIGUCHI240bf072014-02-17 10:55:21 -0800435
Yuta HIGUCHI8d762e92014-02-12 14:10:25 -0800436 Set<Link> links = new HashSet<>();
437 links.add(port.getOutgoingLink());
438 links.add(port.getIncomingLink());
439 for ( Link link : links) {
440 if (link == null ) {
441 continue;
442 }
Yuta HIGUCHI88be0f22014-02-14 17:20:43 -0800443 log.debug("Removing Link {} on Port {}", link, portEvt);
Yuta HIGUCHI8d762e92014-02-12 14:10:25 -0800444 LinkEvent linkEvent = new LinkEvent(link.getSourceSwitchDpid(), link.getSourcePortNumber(), link.getDestinationSwitchDpid(), link.getDestinationPortNumber());
445 // calling Discovery API to wipe from DB, etc.
Yuta HIGUCHI71e7a052014-02-17 22:14:15 -0800446
447 // Call internal remove Link, which will check
448 // ownership of DST dpid and modify DB only if it is the owner
449 removeLinkEvent(linkEvent, true);
Yuta HIGUCHI8d762e92014-02-12 14:10:25 -0800450 }
Jonathan Hart22eb9882014-02-11 15:52:59 -0800451 return true;
452 }
Yuta HIGUCHIcd922f42014-02-11 18:59:11 -0800453
Yuta HIGUCHId02e9282014-02-12 09:24:41 -0800454 private boolean prepareForAddLinkEvent(LinkEvent linkEvt) {
Yuta HIGUCHI8d762e92014-02-12 14:10:25 -0800455 // Src/Dst Port must exist
Yuta HIGUCHId5315c42014-02-18 09:35:48 -0800456 Port srcPort = getPort(linkEvt.getSrc().dpid, linkEvt.getSrc().number);
457 Port dstPort = getPort(linkEvt.getDst().dpid, linkEvt.getDst().number);
Yuta HIGUCHI8d762e92014-02-12 14:10:25 -0800458 if ( srcPort == null || dstPort == null ) {
Jonathan Hart0a4846e2014-02-18 11:03:40 -0800459 log.warn("Dropping add link event because port doesn't exist: {}",
460 linkEvt);
Yuta HIGUCHI8d762e92014-02-12 14:10:25 -0800461 return false;
462 }
463
464 // Prep: remove Device attachment on both Ports
Yuta HIGUCHI240bf072014-02-17 10:55:21 -0800465 ArrayList<DeviceEvent> deviceEvents = new ArrayList<>();
Yuta HIGUCHI8d762e92014-02-12 14:10:25 -0800466 for (Device device : srcPort.getDevices()) {
467 DeviceEvent devEvt = new DeviceEvent(device.getMacAddress());
468 devEvt.addAttachmentPoint(new SwitchPort(srcPort.getSwitch().getDpid(), srcPort.getNumber()));
Yuta HIGUCHI240bf072014-02-17 10:55:21 -0800469 deviceEvents.add(devEvt);
Yuta HIGUCHI8d762e92014-02-12 14:10:25 -0800470 }
471 for (Device device : dstPort.getDevices()) {
472 DeviceEvent devEvt = new DeviceEvent(device.getMacAddress());
473 devEvt.addAttachmentPoint(new SwitchPort(dstPort.getSwitch().getDpid(), dstPort.getNumber()));
Yuta HIGUCHI240bf072014-02-17 10:55:21 -0800474 deviceEvents.add(devEvt);
475 }
476 for (DeviceEvent devEvt : deviceEvents) {
Yuta HIGUCHI8d762e92014-02-12 14:10:25 -0800477 // calling Discovery API to wipe from DB, etc.
478 removeDeviceEvent(devEvt);
479 }
480
481 return true;
Jonathan Hart22eb9882014-02-11 15:52:59 -0800482 }
Yuta HIGUCHIcd922f42014-02-11 18:59:11 -0800483
Yuta HIGUCHId02e9282014-02-12 09:24:41 -0800484 private boolean prepareForRemoveLinkEvent(LinkEvent linkEvt) {
Yuta HIGUCHI8d762e92014-02-12 14:10:25 -0800485 // Src/Dst Port must exist
Yuta HIGUCHId5315c42014-02-18 09:35:48 -0800486 Port srcPort = getPort(linkEvt.getSrc().dpid, linkEvt.getSrc().number);
487 Port dstPort = getPort(linkEvt.getDst().dpid, linkEvt.getDst().number);
Yuta HIGUCHI8d762e92014-02-12 14:10:25 -0800488 if ( srcPort == null || dstPort == null ) {
Jonathan Hart0a4846e2014-02-18 11:03:40 -0800489 log.warn("Dropping remove link event because port doesn't exist {}", linkEvt);
Yuta HIGUCHI8d762e92014-02-12 14:10:25 -0800490 return false;
491 }
492
Yuta HIGUCHI125c7df2014-02-14 12:28:10 -0800493 Link link = srcPort.getOutgoingLink();
494
495 // Link is already gone, or different Link exist in memory
496 // XXX Check if we should reject or just accept these cases.
497 // it should be harmless to remove the Link on event from DB anyways
498 if (link == null ||
499 !link.getDestinationPortNumber().equals(linkEvt.getDst().number)
500 || !link.getDestinationSwitchDpid().equals(linkEvt.getDst().dpid)) {
Jonathan Hart0a4846e2014-02-18 11:03:40 -0800501 log.warn("Dropping remove link event because link doesn't exist: {}", linkEvt);
Yuta HIGUCHI125c7df2014-02-14 12:28:10 -0800502 return false;
503 }
Yuta HIGUCHI8d762e92014-02-12 14:10:25 -0800504 // Prep: None
505 return true;
Jonathan Hart22eb9882014-02-11 15:52:59 -0800506 }
Yuta HIGUCHIcd922f42014-02-11 18:59:11 -0800507
Yuta HIGUCHI8d762e92014-02-12 14:10:25 -0800508 /**
509 *
510 * @param deviceEvt Event will be modified to remove inapplicable attachemntPoints/ipAddress
511 * @return false if this event should be dropped.
512 */
Yuta HIGUCHId02e9282014-02-12 09:24:41 -0800513 private boolean prepareForAddDeviceEvent(DeviceEvent deviceEvt) {
Yuta HIGUCHI8d762e92014-02-12 14:10:25 -0800514 boolean preconditionBroken = false;
515 ArrayList<PortEvent.SwitchPort> failedSwitchPort = new ArrayList<>();
516 for ( PortEvent.SwitchPort swp : deviceEvt.getAttachmentPoints() ) {
Yuta HIGUCHId02e9282014-02-12 09:24:41 -0800517 // Attached Ports must exist
Yuta HIGUCHId5315c42014-02-18 09:35:48 -0800518 Port port = getPort(swp.dpid, swp.number);
Yuta HIGUCHI8d762e92014-02-12 14:10:25 -0800519 if ( port == null ) {
520 preconditionBroken = true;
521 failedSwitchPort.add(swp);
522 continue;
523 }
Yuta HIGUCHId02e9282014-02-12 09:24:41 -0800524 // Attached Ports must not have Link
Yuta HIGUCHI8d762e92014-02-12 14:10:25 -0800525 if ( port.getOutgoingLink() != null || port.getIncomingLink() != null ) {
526 preconditionBroken = true;
527 failedSwitchPort.add(swp);
528 continue;
529 }
530 }
Yuta HIGUCHId02e9282014-02-12 09:24:41 -0800531
Yuta HIGUCHI8d762e92014-02-12 14:10:25 -0800532 // Rewriting event to exclude failed attachmentPoint
533 // XXX Assumption behind this is that inapplicable device event should
534 // be dropped, not deferred. If we decide to defer Device event,
535 // rewriting can become a problem
536 List<SwitchPort> attachmentPoints = deviceEvt.getAttachmentPoints();
537 attachmentPoints.removeAll(failedSwitchPort);
538 deviceEvt.setAttachmentPoints(attachmentPoints);
539
540 if ( deviceEvt.getAttachmentPoints().isEmpty() && deviceEvt.getIpAddresses().isEmpty() ) {
Yuta HIGUCHI125c7df2014-02-14 12:28:10 -0800541 // return false to represent: Nothing left to do for this event. Caller should drop event
Yuta HIGUCHI8d762e92014-02-12 14:10:25 -0800542 return false;
543 }
544
545 // Should we return false to tell caller that the event was trimmed?
546 // if ( preconditionBroken ) {
547 // return false;
548 // }
549
550 return true;
Jonathan Hart22eb9882014-02-11 15:52:59 -0800551 }
Yuta HIGUCHIcd922f42014-02-11 18:59:11 -0800552
Yuta HIGUCHId02e9282014-02-12 09:24:41 -0800553 private boolean prepareForRemoveDeviceEvent(DeviceEvent deviceEvt) {
Yuta HIGUCHId02e9282014-02-12 09:24:41 -0800554 // No show stopping precondition?
555 // Prep: none
Jonathan Hart22eb9882014-02-11 15:52:59 -0800556 return true;
557 }
Yuta HIGUCHI928fa682014-02-11 19:07:57 -0800558
Yuta HIGUCHI76df2472014-02-12 22:36:51 -0800559 /* ******************************
560 * NetworkGraphReplicationInterface methods
561 * ******************************/
562
Yuta HIGUCHI928fa682014-02-11 19:07:57 -0800563 @Override
564 public void putSwitchReplicationEvent(SwitchEvent switchEvent) {
Yuta HIGUCHI9fc10ac2014-02-12 17:18:57 -0800565 if (prepareForAddSwitchEvent(switchEvent)) {
566 putSwitch(switchEvent);
567 }
568 // TODO handle invariant violation
Yuta HIGUCHIa536e762014-02-17 21:47:28 -0800569 // trigger instance local topology event handler
570 dispatchPutSwitchEvent(switchEvent);
Yuta HIGUCHI928fa682014-02-11 19:07:57 -0800571 }
572
573 @Override
574 public void removeSwitchReplicationEvent(SwitchEvent switchEvent) {
Yuta HIGUCHI9fc10ac2014-02-12 17:18:57 -0800575 if (prepareForRemoveSwitchEvent(switchEvent)) {
576 removeSwitch(switchEvent);
577 }
Yuta HIGUCHI125c7df2014-02-14 12:28:10 -0800578 // TODO handle invariant violation
Yuta HIGUCHIa536e762014-02-17 21:47:28 -0800579 // trigger instance local topology event handler
580 dispatchRemoveSwitchEvent(switchEvent);
Yuta HIGUCHI928fa682014-02-11 19:07:57 -0800581 }
582
583 @Override
584 public void putPortReplicationEvent(PortEvent portEvent) {
Yuta HIGUCHI9fc10ac2014-02-12 17:18:57 -0800585 if (prepareForAddPortEvent(portEvent)) {
586 putPort(portEvent);
587 }
Yuta HIGUCHI125c7df2014-02-14 12:28:10 -0800588 // TODO handle invariant violation
Yuta HIGUCHIa536e762014-02-17 21:47:28 -0800589 // trigger instance local topology event handler
590 dispatchPutPortEvent(portEvent);
Yuta HIGUCHI928fa682014-02-11 19:07:57 -0800591 }
592
593 @Override
594 public void removePortReplicationEvent(PortEvent portEvent) {
Yuta HIGUCHI9fc10ac2014-02-12 17:18:57 -0800595 if (prepareForRemovePortEvent(portEvent)) {
596 removePort(portEvent);
597 }
Yuta HIGUCHI125c7df2014-02-14 12:28:10 -0800598 // TODO handle invariant violation
Yuta HIGUCHIa536e762014-02-17 21:47:28 -0800599 // trigger instance local topology event handler
600 dispatchRemovePortEvent(portEvent);
Yuta HIGUCHI928fa682014-02-11 19:07:57 -0800601 }
602
603 @Override
604 public void putLinkReplicationEvent(LinkEvent linkEvent) {
Yuta HIGUCHI9fc10ac2014-02-12 17:18:57 -0800605 if (prepareForAddLinkEvent(linkEvent)) {
606 putLink(linkEvent);
607 }
Yuta HIGUCHI125c7df2014-02-14 12:28:10 -0800608 // TODO handle invariant violation
Yuta HIGUCHIa536e762014-02-17 21:47:28 -0800609 // trigger instance local topology event handler
610 dispatchPutLinkEvent(linkEvent);
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 HIGUCHIa536e762014-02-17 21:47:28 -0800619 // trigger instance local topology event handler
620 dispatchRemoveLinkEvent(linkEvent);
Yuta HIGUCHI928fa682014-02-11 19:07:57 -0800621 }
622
623 @Override
624 public void putDeviceReplicationEvent(DeviceEvent deviceEvent) {
Yuta HIGUCHI9fc10ac2014-02-12 17:18:57 -0800625 if (prepareForAddDeviceEvent(deviceEvent)) {
626 putDevice(deviceEvent);
627 }
Yuta HIGUCHI125c7df2014-02-14 12:28:10 -0800628 // TODO handle invariant violation
Yuta HIGUCHIa536e762014-02-17 21:47:28 -0800629 // trigger instance local topology event handler
630 dispatchPutDeviceEvent(deviceEvent);
Yuta HIGUCHI928fa682014-02-11 19:07:57 -0800631 }
632
633 @Override
634 public void removeDeviceReplicationEvent(DeviceEvent deviceEvent) {
Yuta HIGUCHI9fc10ac2014-02-12 17:18:57 -0800635 if (prepareForRemoveDeviceEvent(deviceEvent)) {
636 removeDevice(deviceEvent);
637 }
Yuta HIGUCHI125c7df2014-02-14 12:28:10 -0800638 // TODO handle invariant violation
Yuta HIGUCHIa536e762014-02-17 21:47:28 -0800639 // trigger instance local topology event handler
640 dispatchRemoveDeviceEvent(deviceEvent);
Yuta HIGUCHI928fa682014-02-11 19:07:57 -0800641 }
Yuta HIGUCHI76df2472014-02-12 22:36:51 -0800642
643 /* ************************************************
644 * Internal In-memory object mutation methods.
645 * ************************************************/
646
647 void putSwitch(SwitchEvent swEvt) {
648 if (swEvt == null) {
649 throw new IllegalArgumentException("Switch cannot be null");
650 }
651
Pavlin Radoslavov6d224ee2014-02-18 16:43:15 -0800652 Switch sw = networkGraph.getSwitch(swEvt.getDpid());
Yuta HIGUCHI76df2472014-02-12 22:36:51 -0800653
654 if (sw == null) {
Pavlin Radoslavov6d224ee2014-02-18 16:43:15 -0800655 sw = new SwitchImpl(networkGraph, swEvt.getDpid());
656 networkGraph.putSwitch(sw);
Yuta HIGUCHI76df2472014-02-12 22:36:51 -0800657 }
658
659 // Update when more attributes are added to Event object
660 // no attribute to update for now
661
662 // TODO handle child Port event properly for performance
663 for (PortEvent portEvt : swEvt.getPorts() ) {
664 putPort(portEvt);
665 }
666
667 }
668
669 void removeSwitch(SwitchEvent swEvt) {
670 if (swEvt == null) {
671 throw new IllegalArgumentException("Switch cannot be null");
672 }
673
674 // TODO handle child Port event properly for performance
675 for (PortEvent portEvt : swEvt.getPorts() ) {
676 removePort(portEvt);
677 }
678
Pavlin Radoslavov6d224ee2014-02-18 16:43:15 -0800679 Switch sw = networkGraph.getSwitch(swEvt.getDpid());
Yuta HIGUCHI76df2472014-02-12 22:36:51 -0800680
681 if (sw == null) {
682 log.warn("Switch {} already removed, ignoring", swEvt);
683 return;
684 }
685
Yuta HIGUCHI317bf542014-02-17 11:02:39 -0800686 // remove all ports if there still exist
687 ArrayList<PortEvent> portsToRemove = new ArrayList<>();
688 for (Port port : sw.getPorts()) {
Yuta HIGUCHI76df2472014-02-12 22:36:51 -0800689 log.warn(
Yuta HIGUCHI317bf542014-02-17 11:02:39 -0800690 "Port {} on Switch {} should be removed prior to removing Switch. Removing Port now",
691 port, swEvt);
692 PortEvent portEvt = new PortEvent(port.getDpid(), port.getNumber());
693 portsToRemove.add(portEvt);
Yuta HIGUCHI76df2472014-02-12 22:36:51 -0800694 }
Yuta HIGUCHI0a4bd192014-02-17 13:52:34 -0800695 for (PortEvent portEvt : portsToRemove) {
Yuta HIGUCHI317bf542014-02-17 11:02:39 -0800696 // XXX calling removePortEvent() may trigger duplicate event, once at prepare phase, second time here
697 // If event can be squashed, ignored etc. at receiver side it shouldn't be a problem, but if not
698 // need to re-visit this issue.
699
700 // Note: removePortEvent() implies removal of attached Device, etc.
701 // if we decide not to call removePortEvent(), Device needs to be handled properly
702 removePortEvent(portEvt);
Yuta HIGUCHI76df2472014-02-12 22:36:51 -0800703 }
704
Pavlin Radoslavov6d224ee2014-02-18 16:43:15 -0800705 networkGraph.removeSwitch(swEvt.getDpid());
Yuta HIGUCHI76df2472014-02-12 22:36:51 -0800706 }
707
708 void putPort(PortEvent portEvt) {
709 if (portEvt == null) {
710 throw new IllegalArgumentException("Port cannot be null");
711 }
Pavlin Radoslavov6d224ee2014-02-18 16:43:15 -0800712 Switch sw = networkGraph.getSwitch(portEvt.getDpid());
Yuta HIGUCHI76df2472014-02-12 22:36:51 -0800713 if (sw == null) {
714 throw new BrokenInvariantException(String.format(
715 "Switch with dpid %s did not exist.",
716 new Dpid(portEvt.getDpid())));
717 }
718 Port p = sw.getPort(portEvt.getNumber());
719 PortImpl port = null;
720 if (p != null) {
721 port = getPortImpl(p);
722 }
723
724 if (port == null) {
Pavlin Radoslavov6d224ee2014-02-18 16:43:15 -0800725 port = new PortImpl(networkGraph, sw, portEvt.getNumber());
Yuta HIGUCHI76df2472014-02-12 22:36:51 -0800726 }
727
728 // TODO update attributes
729
730 SwitchImpl s = getSwitchImpl(sw);
731 s.addPort(port);
732 }
733
734 void removePort(PortEvent portEvt) {
735 if (portEvt == null) {
736 throw new IllegalArgumentException("Port cannot be null");
737 }
738
Pavlin Radoslavov6d224ee2014-02-18 16:43:15 -0800739 Switch sw = networkGraph.getSwitch(portEvt.getDpid());
Yuta HIGUCHI76df2472014-02-12 22:36:51 -0800740 if (sw == null) {
741 log.warn("Parent Switch for Port {} already removed, ignoring", portEvt);
742 return;
743 }
744
745 Port p = sw.getPort(portEvt.getNumber());
746 if (p == null) {
747 log.warn("Port {} already removed, ignoring", portEvt);
748 return;
749 }
750
Yuta HIGUCHIde040642014-02-17 11:03:39 -0800751 // Remove Link and Device Attachment
752 for (Device device : p.getDevices()) {
753 log.debug("Removing Device {} on Port {}", device, portEvt);
754 DeviceEvent devEvt = new DeviceEvent(device.getMacAddress());
755 devEvt.addAttachmentPoint(new SwitchPort(p.getSwitch().getDpid(), p.getNumber()));
Yuta HIGUCHI76df2472014-02-12 22:36:51 -0800756
Yuta HIGUCHIde040642014-02-17 11:03:39 -0800757 // XXX calling removeDeviceEvent() may trigger duplicate event, once at prepare phase, second time here
758 // If event can be squashed, ignored etc. at receiver side it shouldn't be a problem, but if not
759 // need to re-visit
760
761 // calling Discovery API to wipe from DB, etc.
762 removeDeviceEvent(devEvt);
Yuta HIGUCHI76df2472014-02-12 22:36:51 -0800763 }
Yuta HIGUCHIde040642014-02-17 11:03:39 -0800764 Set<Link> links = new HashSet<>();
765 links.add(p.getOutgoingLink());
766 links.add(p.getIncomingLink());
767 ArrayList<LinkEvent> linksToRemove = new ArrayList<>();
768 for (Link link : links) {
769 if (link == null) {
770 continue;
771 }
772 log.debug("Removing Link {} on Port {}", link, portEvt);
773 LinkEvent linkEvent = new LinkEvent(link.getSourceSwitchDpid(), link.getSourcePortNumber(), link.getDestinationSwitchDpid(), link.getDestinationPortNumber());
774 linksToRemove.add(linkEvent);
Yuta HIGUCHI76df2472014-02-12 22:36:51 -0800775 }
Yuta HIGUCHIde040642014-02-17 11:03:39 -0800776 for (LinkEvent linkEvent : linksToRemove) {
777 // XXX calling removeLinkEvent() may trigger duplicate event, once at prepare phase, second time here
778 // If event can be squashed, ignored etc. at receiver side it shouldn't be a problem, but if not
779 // need to re-visit
780
781 // calling Discovery API to wipe from DB, etc.
782 removeLinkEvent(linkEvent);
Yuta HIGUCHI76df2472014-02-12 22:36:51 -0800783 }
784
785 // remove Port from Switch
786 SwitchImpl s = getSwitchImpl(sw);
787 s.removePort(p);
788 }
789
790 void putLink(LinkEvent linkEvt) {
791 if (linkEvt == null) {
792 throw new IllegalArgumentException("Link cannot be null");
793 }
794
Yuta HIGUCHId5315c42014-02-18 09:35:48 -0800795 Port srcPort = getPort(linkEvt.getSrc().dpid, linkEvt.getSrc().number);
Yuta HIGUCHI76df2472014-02-12 22:36:51 -0800796 if (srcPort == null) {
797 throw new BrokenInvariantException(
798 String.format(
799 "Src Port %s of a Link did not exist.",
800 linkEvt.getSrc() ));
801 }
802
Yuta HIGUCHId5315c42014-02-18 09:35:48 -0800803 Port dstPort = getPort(linkEvt.getDst().dpid, linkEvt.getDst().number);
Yuta HIGUCHI76df2472014-02-12 22:36:51 -0800804 if (dstPort == null) {
805 throw new BrokenInvariantException(
806 String.format(
807 "Dst Port %s of a Link did not exist.",
808 linkEvt.getDst() ));
809 }
810
811 // getting Link instance from destination port incoming Link
812 Link l = dstPort.getIncomingLink();
813 LinkImpl link = null;
814 assert( l == srcPort.getOutgoingLink() );
815 if (l != null) {
816 link = getLinkImpl(l);
817 }
818
819 if (link == null) {
Pavlin Radoslavov6d224ee2014-02-18 16:43:15 -0800820 link = new LinkImpl(networkGraph, srcPort, dstPort);
Yuta HIGUCHI76df2472014-02-12 22:36:51 -0800821 }
822
823
824 PortImpl dstPortMem = getPortImpl(dstPort);
825 PortImpl srcPortMem = getPortImpl(srcPort);
826
827 // Add Link first to avoid further Device addition
828
829 // add Link to Port
830 dstPortMem.setIncomingLink(link);
831 srcPortMem.setOutgoingLink(link);
832
833 // remove Device Pointing to Port if any
834 for(Device d : dstPortMem.getDevices() ) {
835 log.error("Device {} on Port {} should have been removed prior to adding Link {}", d, dstPort, linkEvt);
836 DeviceImpl dev = getDeviceImpl(d);
837 dev.removeAttachmentPoint(dstPort);
Yuta HIGUCHI407261a2014-02-13 16:34:06 -0800838 // This implies that change is made to Device Object.
839 // sending Device attachment point removed event
840 DeviceEvent rmEvent = new DeviceEvent(d.getMacAddress());
841 rmEvent.addAttachmentPoint(new SwitchPort(dstPort.getDpid(), dstPort.getNumber()));
842 removeDeviceEvent(rmEvent);
Yuta HIGUCHI76df2472014-02-12 22:36:51 -0800843 }
844 dstPortMem.removeAllDevice();
845 for(Device d : srcPortMem.getDevices() ) {
846 log.error("Device {} on Port {} should have been removed prior to adding Link {}", d, srcPort, linkEvt);
847 DeviceImpl dev = getDeviceImpl(d);
848 dev.removeAttachmentPoint(srcPort);
Yuta HIGUCHI407261a2014-02-13 16:34:06 -0800849 // This implies that change is made to Device Object.
850 // sending Device attachment point removed event
851 DeviceEvent rmEvent = new DeviceEvent(d.getMacAddress());
852 rmEvent.addAttachmentPoint(new SwitchPort(dstPort.getDpid(), dstPort.getNumber()));
853 removeDeviceEvent(rmEvent);
Yuta HIGUCHI76df2472014-02-12 22:36:51 -0800854 }
855 srcPortMem.removeAllDevice();
856
857 }
858
859 void removeLink(LinkEvent linkEvt) {
860 if (linkEvt == null) {
861 throw new IllegalArgumentException("Link cannot be null");
862 }
863
Yuta HIGUCHId5315c42014-02-18 09:35:48 -0800864 Port srcPort = getPort(linkEvt.getSrc().dpid, linkEvt.getSrc().number);
Yuta HIGUCHI76df2472014-02-12 22:36:51 -0800865 if (srcPort == null) {
866 log.warn("Src Port for Link {} already removed, ignoring", linkEvt);
867 return;
868 }
869
Yuta HIGUCHId5315c42014-02-18 09:35:48 -0800870 Port dstPort = getPort(linkEvt.getDst().dpid, linkEvt.getDst().number);
Yuta HIGUCHI76df2472014-02-12 22:36:51 -0800871 if (dstPort == null) {
872 log.warn("Dst Port for Link {} already removed, ignoring", linkEvt);
873 return;
874 }
875
876 Link l = dstPort.getIncomingLink();
877 if ( l == null ) {
878 log.warn("Link {} already removed on destination Port", linkEvt);
879 }
880 l = srcPort.getOutgoingLink();
881 if ( l == null ) {
882 log.warn("Link {} already removed on src Port", linkEvt);
883 }
884
885 getPortImpl(dstPort).setIncomingLink(null);
886 getPortImpl(srcPort).setOutgoingLink(null);
887 }
888
889 // XXX Need to rework Device related
890 void putDevice(DeviceEvent deviceEvt) {
891 if (deviceEvt == null) {
892 throw new IllegalArgumentException("Device cannot be null");
893 }
894
Pavlin Radoslavov6d224ee2014-02-18 16:43:15 -0800895 Device device = networkGraph.getDeviceByMac(deviceEvt.getMac());
Yuta HIGUCHI76df2472014-02-12 22:36:51 -0800896 if ( device == null ) {
Pavlin Radoslavov6d224ee2014-02-18 16:43:15 -0800897 device = new DeviceImpl(networkGraph, deviceEvt.getMac());
Yuta HIGUCHI76df2472014-02-12 22:36:51 -0800898 }
899 DeviceImpl memDevice = getDeviceImpl(device);
900
Pavlin Radoslavov6d224ee2014-02-18 16:43:15 -0800901 // for each IP address
902 for( InetAddress ipAddr : deviceEvt.getIpAddresses() ) {
903 memDevice.addIpAddress(ipAddr);
904 }
905
906 networkGraph.putDevice(device);
907
Yuta HIGUCHI76df2472014-02-12 22:36:51 -0800908 // for each attachment point
909 for (SwitchPort swp : deviceEvt.getAttachmentPoints() ) {
Yuta HIGUCHI76df2472014-02-12 22:36:51 -0800910 // Attached Ports must exist
Yuta HIGUCHId5315c42014-02-18 09:35:48 -0800911 Port port = getPort(swp.dpid, swp.number);
Yuta HIGUCHI76df2472014-02-12 22:36:51 -0800912 if ( port == null ) {
Yuta HIGUCHI25719052014-02-13 14:42:06 -0800913 log.warn("Port for the attachment point {} did not exist. skipping mutation", swp);
Yuta HIGUCHI76df2472014-02-12 22:36:51 -0800914 continue;
915 }
916 // Attached Ports must not have Link
917 if ( port.getOutgoingLink() != null || port.getIncomingLink() != null ) {
918 log.warn("Link (Out:{},In:{}) exist on the attachment point, skipping mutation.", port.getOutgoingLink(), port.getIncomingLink());
919 continue;
920 }
921
922 // finally add Device <-> Port on In-memory structure
923 PortImpl memPort = getPortImpl(port);
924 memPort.addDevice(device);
925 memDevice.addAttachmentPoint(port);
926 }
Yuta HIGUCHI76df2472014-02-12 22:36:51 -0800927 }
928
929 void removeDevice(DeviceEvent deviceEvt) {
930 if (deviceEvt == null) {
931 throw new IllegalArgumentException("Device cannot be null");
932 }
933
Pavlin Radoslavov6d224ee2014-02-18 16:43:15 -0800934 Device device = networkGraph.getDeviceByMac(deviceEvt.getMac());
Yuta HIGUCHI76df2472014-02-12 22:36:51 -0800935 if ( device == null ) {
936 log.warn("Device {} already removed, ignoring", deviceEvt);
937 return;
938 }
939 DeviceImpl memDevice = getDeviceImpl(device);
940
941 // for each attachment point
942 for (SwitchPort swp : deviceEvt.getAttachmentPoints() ) {
Yuta HIGUCHI76df2472014-02-12 22:36:51 -0800943 // Attached Ports must exist
Yuta HIGUCHId5315c42014-02-18 09:35:48 -0800944 Port port = getPort(swp.dpid, swp.number);
Yuta HIGUCHI76df2472014-02-12 22:36:51 -0800945 if ( port == null ) {
Yuta HIGUCHI25719052014-02-13 14:42:06 -0800946 log.warn("Port for the attachment point {} did not exist. skipping attachment point mutation", swp);
Yuta HIGUCHI76df2472014-02-12 22:36:51 -0800947 continue;
948 }
949
950 // finally remove Device <-> Port on In-memory structure
951 PortImpl memPort = getPortImpl(port);
952 memPort.removeDevice(device);
953 memDevice.removeAttachmentPoint(port);
954 }
Pavlin Radoslavov6d224ee2014-02-18 16:43:15 -0800955 networkGraph.removeDevice(device);
Yuta HIGUCHI76df2472014-02-12 22:36:51 -0800956 }
957
Yuta HIGUCHIa536e762014-02-17 21:47:28 -0800958 private void dispatchPutSwitchEvent(SwitchEvent switchEvent) {
959 for (INetworkGraphListener listener : this.networkGraphListeners) {
960 // TODO Should copy before handing them over to listener
961 listener.putSwitchEvent(switchEvent);
962 }
963 }
964
965 private void dispatchRemoveSwitchEvent(SwitchEvent switchEvent) {
966 for (INetworkGraphListener listener : this.networkGraphListeners) {
967 // TODO Should copy before handing them over to listener
968 listener.removeSwitchEvent(switchEvent);
969 }
970 }
971
972 private void dispatchPutPortEvent(PortEvent portEvent) {
973 for (INetworkGraphListener listener : this.networkGraphListeners) {
974 // TODO Should copy before handing them over to listener
975 listener.putPortEvent(portEvent);
976 }
977 }
978
979 private void dispatchRemovePortEvent(PortEvent portEvent) {
980 for (INetworkGraphListener listener : this.networkGraphListeners) {
981 // TODO Should copy before handing them over to listener
982 listener.removePortEvent(portEvent);
983 }
984 }
985
986 private void dispatchPutLinkEvent(LinkEvent linkEvent) {
987 for (INetworkGraphListener listener : this.networkGraphListeners) {
988 // TODO Should copy before handing them over to listener
989 listener.putLinkEvent(linkEvent);
990 }
991 }
992
993 private void dispatchRemoveLinkEvent(LinkEvent linkEvent) {
994 for (INetworkGraphListener listener : this.networkGraphListeners) {
995 // TODO Should copy before handing them over to listener
996 listener.removeLinkEvent(linkEvent);
997 }
998 }
999
1000 private void dispatchPutDeviceEvent(DeviceEvent deviceEvent) {
1001 for (INetworkGraphListener listener : this.networkGraphListeners) {
1002 // TODO Should copy before handing them over to listener
1003 listener.putDeviceEvent(deviceEvent);;
1004 }
1005 }
1006
1007 private void dispatchRemoveDeviceEvent(DeviceEvent deviceEvent) {
1008 for (INetworkGraphListener listener : this.networkGraphListeners) {
1009 // TODO Should copy before handing them over to listener
1010 listener.removeDeviceEvent(deviceEvent);
1011 }
1012 }
1013
Yuta HIGUCHId5315c42014-02-18 09:35:48 -08001014 // we might want to include this in NetworkGraph interface
1015 private Port getPort(Long dpid, Long number) {
Pavlin Radoslavov6d224ee2014-02-18 16:43:15 -08001016 Switch sw = networkGraph.getSwitch(dpid);
Yuta HIGUCHId5315c42014-02-18 09:35:48 -08001017 if (sw != null) {
1018 return sw.getPort(number);
1019 }
1020 return null;
1021 }
1022
Yuta HIGUCHI76df2472014-02-12 22:36:51 -08001023 private SwitchImpl getSwitchImpl(Switch sw) {
1024 if (sw instanceof SwitchImpl) {
1025 return (SwitchImpl) sw;
1026 }
1027 throw new ClassCastException("SwitchImpl expected, but found: " + sw);
1028 }
1029
1030 private PortImpl getPortImpl(Port p) {
1031 if (p instanceof PortImpl) {
1032 return (PortImpl) p;
1033 }
1034 throw new ClassCastException("PortImpl expected, but found: " + p);
1035 }
1036
1037 private LinkImpl getLinkImpl(Link l) {
1038 if (l instanceof LinkImpl) {
1039 return (LinkImpl) l;
1040 }
1041 throw new ClassCastException("LinkImpl expected, but found: " + l);
1042 }
1043
1044 private DeviceImpl getDeviceImpl(Device d) {
1045 if (d instanceof DeviceImpl) {
1046 return (DeviceImpl) d;
1047 }
1048 throw new ClassCastException("DeviceImpl expected, but found: " + d);
1049 }
1050
1051 @Deprecated
1052 public void loadWholeTopologyFromDB() {
Yuta HIGUCHI0a4bd192014-02-17 13:52:34 -08001053 // XXX May need to clear whole topology first, depending on
1054 // how we initially subscribe to replication events
Yuta HIGUCHI76df2472014-02-12 22:36:51 -08001055
1056 for (RCSwitch sw : RCSwitch.getAllSwitches()) {
1057 if ( sw.getStatus() != RCSwitch.STATUS.ACTIVE ) {
1058 continue;
1059 }
1060 putSwitchReplicationEvent(new SwitchEvent(sw.getDpid()));
1061 }
1062
1063 for (RCPort p : RCPort.getAllPorts()) {
1064 if (p.getStatus() != RCPort.STATUS.ACTIVE) {
1065 continue;
1066 }
1067 putPortReplicationEvent(new PortEvent(p.getDpid(), p.getNumber() ));
1068 }
1069
1070 // TODO Is Device going to be in DB? If so, read from DB.
1071 // for (RCDevice d : RCDevice.getAllDevices()) {
1072 // DeviceEvent devEvent = new DeviceEvent( MACAddress.valueOf(d.getMac()) );
1073 // for (byte[] portId : d.getAllPortIds() ) {
1074 // devEvent.addAttachmentPoint( new SwitchPort( RCPort.getDpidFromKey(portId), RCPort.getNumberFromKey(portId) ));
1075 // }
1076 // }
1077
1078 for (RCLink l : RCLink.getAllLinks()) {
Yuta HIGUCHIdab94692014-02-18 09:12:02 -08001079 // check if src/dst switch/port exist before triggering event
Yuta HIGUCHId5315c42014-02-18 09:35:48 -08001080 Port srcPort = getPort(l.getSrc().dpid, l.getSrc().number);
1081 Port dstPort = getPort(l.getDst().dpid, l.getDst().number);
Yuta HIGUCHIdab94692014-02-18 09:12:02 -08001082 if ( srcPort == null || dstPort == null ) {
1083 continue;
1084 }
Yuta HIGUCHI76df2472014-02-12 22:36:51 -08001085 putLinkReplicationEvent( new LinkEvent(l.getSrc().dpid, l.getSrc().number, l.getDst().dpid, l.getDst().number));
1086 }
1087 }
Jonathan Hart062a2e82014-02-03 09:41:57 -08001088}