blob: fc57b3bbf7eaccdf8f52a173bfffbefe89ddde01 [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) {
Pavlin Radoslavov06df22a2014-02-18 19:16:27 -0800416 Port port = networkGraph.getPort(portEvt.getDpid(),
417 portEvt.getNumber());
Yuta HIGUCHI8d762e92014-02-12 14:10:25 -0800418 if ( port == null ) {
419 log.debug("Port already removed? {}", portEvt);
420 // let it pass
421 return true;
422 }
423
424 // Prep: Remove Link and Device Attachment
Yuta HIGUCHI240bf072014-02-17 10:55:21 -0800425 ArrayList<DeviceEvent> deviceEvts = new ArrayList<>();
Yuta HIGUCHI8d762e92014-02-12 14:10:25 -0800426 for (Device device : port.getDevices()) {
Yuta HIGUCHI88be0f22014-02-14 17:20:43 -0800427 log.debug("Removing Device {} on Port {}", device, portEvt);
Yuta HIGUCHI8d762e92014-02-12 14:10:25 -0800428 DeviceEvent devEvt = new DeviceEvent(device.getMacAddress());
429 devEvt.addAttachmentPoint(new SwitchPort(port.getSwitch().getDpid(), port.getNumber()));
Yuta HIGUCHI240bf072014-02-17 10:55:21 -0800430 deviceEvts.add(devEvt);
431 }
432 for (DeviceEvent devEvt : deviceEvts) {
Yuta HIGUCHI8d762e92014-02-12 14:10:25 -0800433 // calling Discovery API to wipe from DB, etc.
434 removeDeviceEvent(devEvt);
435 }
Yuta HIGUCHI240bf072014-02-17 10:55:21 -0800436
Yuta HIGUCHI8d762e92014-02-12 14:10:25 -0800437 Set<Link> links = new HashSet<>();
438 links.add(port.getOutgoingLink());
439 links.add(port.getIncomingLink());
440 for ( Link link : links) {
441 if (link == null ) {
442 continue;
443 }
Yuta HIGUCHI88be0f22014-02-14 17:20:43 -0800444 log.debug("Removing Link {} on Port {}", link, portEvt);
Yuta HIGUCHI8d762e92014-02-12 14:10:25 -0800445 LinkEvent linkEvent = new LinkEvent(link.getSourceSwitchDpid(), link.getSourcePortNumber(), link.getDestinationSwitchDpid(), link.getDestinationPortNumber());
446 // calling Discovery API to wipe from DB, etc.
Yuta HIGUCHI71e7a052014-02-17 22:14:15 -0800447
448 // Call internal remove Link, which will check
449 // ownership of DST dpid and modify DB only if it is the owner
450 removeLinkEvent(linkEvent, true);
Yuta HIGUCHI8d762e92014-02-12 14:10:25 -0800451 }
Jonathan Hart22eb9882014-02-11 15:52:59 -0800452 return true;
453 }
Yuta HIGUCHIcd922f42014-02-11 18:59:11 -0800454
Yuta HIGUCHId02e9282014-02-12 09:24:41 -0800455 private boolean prepareForAddLinkEvent(LinkEvent linkEvt) {
Yuta HIGUCHI8d762e92014-02-12 14:10:25 -0800456 // Src/Dst Port must exist
Pavlin Radoslavov06df22a2014-02-18 19:16:27 -0800457 Port srcPort = networkGraph.getPort(linkEvt.getSrc().dpid,
458 linkEvt.getSrc().number);
459 Port dstPort = networkGraph.getPort(linkEvt.getDst().dpid,
460 linkEvt.getDst().number);
Yuta HIGUCHI8d762e92014-02-12 14:10:25 -0800461 if ( srcPort == null || dstPort == null ) {
Jonathan Hart0a4846e2014-02-18 11:03:40 -0800462 log.warn("Dropping add link event because port doesn't exist: {}",
463 linkEvt);
Yuta HIGUCHI8d762e92014-02-12 14:10:25 -0800464 return false;
465 }
466
467 // Prep: remove Device attachment on both Ports
Yuta HIGUCHI240bf072014-02-17 10:55:21 -0800468 ArrayList<DeviceEvent> deviceEvents = new ArrayList<>();
Yuta HIGUCHI8d762e92014-02-12 14:10:25 -0800469 for (Device device : srcPort.getDevices()) {
470 DeviceEvent devEvt = new DeviceEvent(device.getMacAddress());
471 devEvt.addAttachmentPoint(new SwitchPort(srcPort.getSwitch().getDpid(), srcPort.getNumber()));
Yuta HIGUCHI240bf072014-02-17 10:55:21 -0800472 deviceEvents.add(devEvt);
Yuta HIGUCHI8d762e92014-02-12 14:10:25 -0800473 }
474 for (Device device : dstPort.getDevices()) {
475 DeviceEvent devEvt = new DeviceEvent(device.getMacAddress());
476 devEvt.addAttachmentPoint(new SwitchPort(dstPort.getSwitch().getDpid(), dstPort.getNumber()));
Yuta HIGUCHI240bf072014-02-17 10:55:21 -0800477 deviceEvents.add(devEvt);
478 }
479 for (DeviceEvent devEvt : deviceEvents) {
Yuta HIGUCHI8d762e92014-02-12 14:10:25 -0800480 // calling Discovery API to wipe from DB, etc.
481 removeDeviceEvent(devEvt);
482 }
483
484 return true;
Jonathan Hart22eb9882014-02-11 15:52:59 -0800485 }
Yuta HIGUCHIcd922f42014-02-11 18:59:11 -0800486
Yuta HIGUCHId02e9282014-02-12 09:24:41 -0800487 private boolean prepareForRemoveLinkEvent(LinkEvent linkEvt) {
Yuta HIGUCHI8d762e92014-02-12 14:10:25 -0800488 // Src/Dst Port must exist
Pavlin Radoslavov06df22a2014-02-18 19:16:27 -0800489 Port srcPort = networkGraph.getPort(linkEvt.getSrc().dpid,
490 linkEvt.getSrc().number);
491 Port dstPort = networkGraph.getPort(linkEvt.getDst().dpid,
492 linkEvt.getDst().number);
Yuta HIGUCHI8d762e92014-02-12 14:10:25 -0800493 if ( srcPort == null || dstPort == null ) {
Jonathan Hart0a4846e2014-02-18 11:03:40 -0800494 log.warn("Dropping remove link event because port doesn't exist {}", linkEvt);
Yuta HIGUCHI8d762e92014-02-12 14:10:25 -0800495 return false;
496 }
497
Yuta HIGUCHI125c7df2014-02-14 12:28:10 -0800498 Link link = srcPort.getOutgoingLink();
499
500 // Link is already gone, or different Link exist in memory
501 // XXX Check if we should reject or just accept these cases.
502 // it should be harmless to remove the Link on event from DB anyways
503 if (link == null ||
504 !link.getDestinationPortNumber().equals(linkEvt.getDst().number)
505 || !link.getDestinationSwitchDpid().equals(linkEvt.getDst().dpid)) {
Jonathan Hart0a4846e2014-02-18 11:03:40 -0800506 log.warn("Dropping remove link event because link doesn't exist: {}", linkEvt);
Yuta HIGUCHI125c7df2014-02-14 12:28:10 -0800507 return false;
508 }
Yuta HIGUCHI8d762e92014-02-12 14:10:25 -0800509 // Prep: None
510 return true;
Jonathan Hart22eb9882014-02-11 15:52:59 -0800511 }
Yuta HIGUCHIcd922f42014-02-11 18:59:11 -0800512
Yuta HIGUCHI8d762e92014-02-12 14:10:25 -0800513 /**
514 *
515 * @param deviceEvt Event will be modified to remove inapplicable attachemntPoints/ipAddress
516 * @return false if this event should be dropped.
517 */
Yuta HIGUCHId02e9282014-02-12 09:24:41 -0800518 private boolean prepareForAddDeviceEvent(DeviceEvent deviceEvt) {
Yuta HIGUCHI8d762e92014-02-12 14:10:25 -0800519 boolean preconditionBroken = false;
520 ArrayList<PortEvent.SwitchPort> failedSwitchPort = new ArrayList<>();
521 for ( PortEvent.SwitchPort swp : deviceEvt.getAttachmentPoints() ) {
Yuta HIGUCHId02e9282014-02-12 09:24:41 -0800522 // Attached Ports must exist
Pavlin Radoslavov06df22a2014-02-18 19:16:27 -0800523 Port port = networkGraph.getPort(swp.dpid, swp.number);
Yuta HIGUCHI8d762e92014-02-12 14:10:25 -0800524 if ( port == null ) {
525 preconditionBroken = true;
526 failedSwitchPort.add(swp);
527 continue;
528 }
Yuta HIGUCHId02e9282014-02-12 09:24:41 -0800529 // Attached Ports must not have Link
Yuta HIGUCHI8d762e92014-02-12 14:10:25 -0800530 if ( port.getOutgoingLink() != null || port.getIncomingLink() != null ) {
531 preconditionBroken = true;
532 failedSwitchPort.add(swp);
533 continue;
534 }
535 }
Yuta HIGUCHId02e9282014-02-12 09:24:41 -0800536
Yuta HIGUCHI8d762e92014-02-12 14:10:25 -0800537 // Rewriting event to exclude failed attachmentPoint
538 // XXX Assumption behind this is that inapplicable device event should
539 // be dropped, not deferred. If we decide to defer Device event,
540 // rewriting can become a problem
541 List<SwitchPort> attachmentPoints = deviceEvt.getAttachmentPoints();
542 attachmentPoints.removeAll(failedSwitchPort);
543 deviceEvt.setAttachmentPoints(attachmentPoints);
544
545 if ( deviceEvt.getAttachmentPoints().isEmpty() && deviceEvt.getIpAddresses().isEmpty() ) {
Yuta HIGUCHI125c7df2014-02-14 12:28:10 -0800546 // return false to represent: Nothing left to do for this event. Caller should drop event
Yuta HIGUCHI8d762e92014-02-12 14:10:25 -0800547 return false;
548 }
549
550 // Should we return false to tell caller that the event was trimmed?
551 // if ( preconditionBroken ) {
552 // return false;
553 // }
554
555 return true;
Jonathan Hart22eb9882014-02-11 15:52:59 -0800556 }
Yuta HIGUCHIcd922f42014-02-11 18:59:11 -0800557
Yuta HIGUCHId02e9282014-02-12 09:24:41 -0800558 private boolean prepareForRemoveDeviceEvent(DeviceEvent deviceEvt) {
Yuta HIGUCHId02e9282014-02-12 09:24:41 -0800559 // No show stopping precondition?
560 // Prep: none
Jonathan Hart22eb9882014-02-11 15:52:59 -0800561 return true;
562 }
Yuta HIGUCHI928fa682014-02-11 19:07:57 -0800563
Yuta HIGUCHI76df2472014-02-12 22:36:51 -0800564 /* ******************************
565 * NetworkGraphReplicationInterface methods
566 * ******************************/
567
Yuta HIGUCHI928fa682014-02-11 19:07:57 -0800568 @Override
569 public void putSwitchReplicationEvent(SwitchEvent switchEvent) {
Yuta HIGUCHI9fc10ac2014-02-12 17:18:57 -0800570 if (prepareForAddSwitchEvent(switchEvent)) {
571 putSwitch(switchEvent);
572 }
573 // TODO handle invariant violation
Yuta HIGUCHIa536e762014-02-17 21:47:28 -0800574 // trigger instance local topology event handler
575 dispatchPutSwitchEvent(switchEvent);
Yuta HIGUCHI928fa682014-02-11 19:07:57 -0800576 }
577
578 @Override
579 public void removeSwitchReplicationEvent(SwitchEvent switchEvent) {
Yuta HIGUCHI9fc10ac2014-02-12 17:18:57 -0800580 if (prepareForRemoveSwitchEvent(switchEvent)) {
581 removeSwitch(switchEvent);
582 }
Yuta HIGUCHI125c7df2014-02-14 12:28:10 -0800583 // TODO handle invariant violation
Yuta HIGUCHIa536e762014-02-17 21:47:28 -0800584 // trigger instance local topology event handler
585 dispatchRemoveSwitchEvent(switchEvent);
Yuta HIGUCHI928fa682014-02-11 19:07:57 -0800586 }
587
588 @Override
589 public void putPortReplicationEvent(PortEvent portEvent) {
Yuta HIGUCHI9fc10ac2014-02-12 17:18:57 -0800590 if (prepareForAddPortEvent(portEvent)) {
591 putPort(portEvent);
592 }
Yuta HIGUCHI125c7df2014-02-14 12:28:10 -0800593 // TODO handle invariant violation
Yuta HIGUCHIa536e762014-02-17 21:47:28 -0800594 // trigger instance local topology event handler
595 dispatchPutPortEvent(portEvent);
Yuta HIGUCHI928fa682014-02-11 19:07:57 -0800596 }
597
598 @Override
599 public void removePortReplicationEvent(PortEvent portEvent) {
Yuta HIGUCHI9fc10ac2014-02-12 17:18:57 -0800600 if (prepareForRemovePortEvent(portEvent)) {
601 removePort(portEvent);
602 }
Yuta HIGUCHI125c7df2014-02-14 12:28:10 -0800603 // TODO handle invariant violation
Yuta HIGUCHIa536e762014-02-17 21:47:28 -0800604 // trigger instance local topology event handler
605 dispatchRemovePortEvent(portEvent);
Yuta HIGUCHI928fa682014-02-11 19:07:57 -0800606 }
607
608 @Override
609 public void putLinkReplicationEvent(LinkEvent linkEvent) {
Yuta HIGUCHI9fc10ac2014-02-12 17:18:57 -0800610 if (prepareForAddLinkEvent(linkEvent)) {
611 putLink(linkEvent);
612 }
Yuta HIGUCHI125c7df2014-02-14 12:28:10 -0800613 // TODO handle invariant violation
Yuta HIGUCHIa536e762014-02-17 21:47:28 -0800614 // trigger instance local topology event handler
615 dispatchPutLinkEvent(linkEvent);
Yuta HIGUCHI928fa682014-02-11 19:07:57 -0800616 }
617
618 @Override
619 public void removeLinkReplicationEvent(LinkEvent linkEvent) {
Yuta HIGUCHI9fc10ac2014-02-12 17:18:57 -0800620 if (prepareForRemoveLinkEvent(linkEvent)) {
621 removeLink(linkEvent);
622 }
Yuta HIGUCHI125c7df2014-02-14 12:28:10 -0800623 // TODO handle invariant violation
Yuta HIGUCHIa536e762014-02-17 21:47:28 -0800624 // trigger instance local topology event handler
625 dispatchRemoveLinkEvent(linkEvent);
Yuta HIGUCHI928fa682014-02-11 19:07:57 -0800626 }
627
628 @Override
629 public void putDeviceReplicationEvent(DeviceEvent deviceEvent) {
Yuta HIGUCHI9fc10ac2014-02-12 17:18:57 -0800630 if (prepareForAddDeviceEvent(deviceEvent)) {
631 putDevice(deviceEvent);
632 }
Yuta HIGUCHI125c7df2014-02-14 12:28:10 -0800633 // TODO handle invariant violation
Yuta HIGUCHIa536e762014-02-17 21:47:28 -0800634 // trigger instance local topology event handler
635 dispatchPutDeviceEvent(deviceEvent);
Yuta HIGUCHI928fa682014-02-11 19:07:57 -0800636 }
637
638 @Override
639 public void removeDeviceReplicationEvent(DeviceEvent deviceEvent) {
Yuta HIGUCHI9fc10ac2014-02-12 17:18:57 -0800640 if (prepareForRemoveDeviceEvent(deviceEvent)) {
641 removeDevice(deviceEvent);
642 }
Yuta HIGUCHI125c7df2014-02-14 12:28:10 -0800643 // TODO handle invariant violation
Yuta HIGUCHIa536e762014-02-17 21:47:28 -0800644 // trigger instance local topology event handler
645 dispatchRemoveDeviceEvent(deviceEvent);
Yuta HIGUCHI928fa682014-02-11 19:07:57 -0800646 }
Yuta HIGUCHI76df2472014-02-12 22:36:51 -0800647
648 /* ************************************************
649 * Internal In-memory object mutation methods.
650 * ************************************************/
651
652 void putSwitch(SwitchEvent swEvt) {
653 if (swEvt == null) {
654 throw new IllegalArgumentException("Switch cannot be null");
655 }
656
Pavlin Radoslavov6d224ee2014-02-18 16:43:15 -0800657 Switch sw = networkGraph.getSwitch(swEvt.getDpid());
Yuta HIGUCHI76df2472014-02-12 22:36:51 -0800658
659 if (sw == null) {
Pavlin Radoslavov6d224ee2014-02-18 16:43:15 -0800660 sw = new SwitchImpl(networkGraph, swEvt.getDpid());
661 networkGraph.putSwitch(sw);
Yuta HIGUCHI76df2472014-02-12 22:36:51 -0800662 }
663
664 // Update when more attributes are added to Event object
665 // no attribute to update for now
666
667 // TODO handle child Port event properly for performance
668 for (PortEvent portEvt : swEvt.getPorts() ) {
669 putPort(portEvt);
670 }
671
672 }
673
674 void removeSwitch(SwitchEvent swEvt) {
675 if (swEvt == null) {
676 throw new IllegalArgumentException("Switch cannot be null");
677 }
678
679 // TODO handle child Port event properly for performance
680 for (PortEvent portEvt : swEvt.getPorts() ) {
681 removePort(portEvt);
682 }
683
Pavlin Radoslavov6d224ee2014-02-18 16:43:15 -0800684 Switch sw = networkGraph.getSwitch(swEvt.getDpid());
Yuta HIGUCHI76df2472014-02-12 22:36:51 -0800685
686 if (sw == null) {
687 log.warn("Switch {} already removed, ignoring", swEvt);
688 return;
689 }
690
Yuta HIGUCHI317bf542014-02-17 11:02:39 -0800691 // remove all ports if there still exist
692 ArrayList<PortEvent> portsToRemove = new ArrayList<>();
693 for (Port port : sw.getPorts()) {
Yuta HIGUCHI76df2472014-02-12 22:36:51 -0800694 log.warn(
Yuta HIGUCHI317bf542014-02-17 11:02:39 -0800695 "Port {} on Switch {} should be removed prior to removing Switch. Removing Port now",
696 port, swEvt);
697 PortEvent portEvt = new PortEvent(port.getDpid(), port.getNumber());
698 portsToRemove.add(portEvt);
Yuta HIGUCHI76df2472014-02-12 22:36:51 -0800699 }
Yuta HIGUCHI0a4bd192014-02-17 13:52:34 -0800700 for (PortEvent portEvt : portsToRemove) {
Yuta HIGUCHI317bf542014-02-17 11:02:39 -0800701 // XXX calling removePortEvent() may trigger duplicate event, once at prepare phase, second time here
702 // If event can be squashed, ignored etc. at receiver side it shouldn't be a problem, but if not
703 // need to re-visit this issue.
704
705 // Note: removePortEvent() implies removal of attached Device, etc.
706 // if we decide not to call removePortEvent(), Device needs to be handled properly
707 removePortEvent(portEvt);
Yuta HIGUCHI76df2472014-02-12 22:36:51 -0800708 }
709
Pavlin Radoslavov6d224ee2014-02-18 16:43:15 -0800710 networkGraph.removeSwitch(swEvt.getDpid());
Yuta HIGUCHI76df2472014-02-12 22:36:51 -0800711 }
712
713 void putPort(PortEvent portEvt) {
714 if (portEvt == null) {
715 throw new IllegalArgumentException("Port cannot be null");
716 }
Pavlin Radoslavov6d224ee2014-02-18 16:43:15 -0800717 Switch sw = networkGraph.getSwitch(portEvt.getDpid());
Yuta HIGUCHI76df2472014-02-12 22:36:51 -0800718 if (sw == null) {
719 throw new BrokenInvariantException(String.format(
720 "Switch with dpid %s did not exist.",
721 new Dpid(portEvt.getDpid())));
722 }
723 Port p = sw.getPort(portEvt.getNumber());
724 PortImpl port = null;
725 if (p != null) {
726 port = getPortImpl(p);
727 }
728
729 if (port == null) {
Pavlin Radoslavov6d224ee2014-02-18 16:43:15 -0800730 port = new PortImpl(networkGraph, sw, portEvt.getNumber());
Yuta HIGUCHI76df2472014-02-12 22:36:51 -0800731 }
732
733 // TODO update attributes
734
735 SwitchImpl s = getSwitchImpl(sw);
736 s.addPort(port);
737 }
738
739 void removePort(PortEvent portEvt) {
740 if (portEvt == null) {
741 throw new IllegalArgumentException("Port cannot be null");
742 }
743
Pavlin Radoslavov6d224ee2014-02-18 16:43:15 -0800744 Switch sw = networkGraph.getSwitch(portEvt.getDpid());
Yuta HIGUCHI76df2472014-02-12 22:36:51 -0800745 if (sw == null) {
746 log.warn("Parent Switch for Port {} already removed, ignoring", portEvt);
747 return;
748 }
749
750 Port p = sw.getPort(portEvt.getNumber());
751 if (p == null) {
752 log.warn("Port {} already removed, ignoring", portEvt);
753 return;
754 }
755
Yuta HIGUCHIde040642014-02-17 11:03:39 -0800756 // Remove Link and Device Attachment
757 for (Device device : p.getDevices()) {
758 log.debug("Removing Device {} on Port {}", device, portEvt);
759 DeviceEvent devEvt = new DeviceEvent(device.getMacAddress());
760 devEvt.addAttachmentPoint(new SwitchPort(p.getSwitch().getDpid(), p.getNumber()));
Yuta HIGUCHI76df2472014-02-12 22:36:51 -0800761
Yuta HIGUCHIde040642014-02-17 11:03:39 -0800762 // XXX calling removeDeviceEvent() may trigger duplicate event, once at prepare phase, second time here
763 // If event can be squashed, ignored etc. at receiver side it shouldn't be a problem, but if not
764 // need to re-visit
765
766 // calling Discovery API to wipe from DB, etc.
767 removeDeviceEvent(devEvt);
Yuta HIGUCHI76df2472014-02-12 22:36:51 -0800768 }
Yuta HIGUCHIde040642014-02-17 11:03:39 -0800769 Set<Link> links = new HashSet<>();
770 links.add(p.getOutgoingLink());
771 links.add(p.getIncomingLink());
772 ArrayList<LinkEvent> linksToRemove = new ArrayList<>();
773 for (Link link : links) {
774 if (link == null) {
775 continue;
776 }
777 log.debug("Removing Link {} on Port {}", link, portEvt);
778 LinkEvent linkEvent = new LinkEvent(link.getSourceSwitchDpid(), link.getSourcePortNumber(), link.getDestinationSwitchDpid(), link.getDestinationPortNumber());
779 linksToRemove.add(linkEvent);
Yuta HIGUCHI76df2472014-02-12 22:36:51 -0800780 }
Yuta HIGUCHIde040642014-02-17 11:03:39 -0800781 for (LinkEvent linkEvent : linksToRemove) {
782 // XXX calling removeLinkEvent() may trigger duplicate event, once at prepare phase, second time here
783 // If event can be squashed, ignored etc. at receiver side it shouldn't be a problem, but if not
784 // need to re-visit
785
786 // calling Discovery API to wipe from DB, etc.
787 removeLinkEvent(linkEvent);
Yuta HIGUCHI76df2472014-02-12 22:36:51 -0800788 }
789
790 // remove Port from Switch
791 SwitchImpl s = getSwitchImpl(sw);
792 s.removePort(p);
793 }
794
795 void putLink(LinkEvent linkEvt) {
796 if (linkEvt == null) {
797 throw new IllegalArgumentException("Link cannot be null");
798 }
799
Pavlin Radoslavov06df22a2014-02-18 19:16:27 -0800800 Port srcPort = networkGraph.getPort(linkEvt.getSrc().dpid,
801 linkEvt.getSrc().number);
Yuta HIGUCHI76df2472014-02-12 22:36:51 -0800802 if (srcPort == null) {
803 throw new BrokenInvariantException(
804 String.format(
805 "Src Port %s of a Link did not exist.",
806 linkEvt.getSrc() ));
807 }
808
Pavlin Radoslavov06df22a2014-02-18 19:16:27 -0800809 Port dstPort = networkGraph.getPort(linkEvt.getDst().dpid,
810 linkEvt.getDst().number);
Yuta HIGUCHI76df2472014-02-12 22:36:51 -0800811 if (dstPort == null) {
812 throw new BrokenInvariantException(
813 String.format(
814 "Dst Port %s of a Link did not exist.",
815 linkEvt.getDst() ));
816 }
817
818 // getting Link instance from destination port incoming Link
819 Link l = dstPort.getIncomingLink();
820 LinkImpl link = null;
821 assert( l == srcPort.getOutgoingLink() );
822 if (l != null) {
823 link = getLinkImpl(l);
824 }
825
826 if (link == null) {
Pavlin Radoslavov6d224ee2014-02-18 16:43:15 -0800827 link = new LinkImpl(networkGraph, srcPort, dstPort);
Yuta HIGUCHI76df2472014-02-12 22:36:51 -0800828 }
829
830
831 PortImpl dstPortMem = getPortImpl(dstPort);
832 PortImpl srcPortMem = getPortImpl(srcPort);
833
834 // Add Link first to avoid further Device addition
835
836 // add Link to Port
837 dstPortMem.setIncomingLink(link);
838 srcPortMem.setOutgoingLink(link);
839
840 // remove Device Pointing to Port if any
841 for(Device d : dstPortMem.getDevices() ) {
842 log.error("Device {} on Port {} should have been removed prior to adding Link {}", d, dstPort, linkEvt);
843 DeviceImpl dev = getDeviceImpl(d);
844 dev.removeAttachmentPoint(dstPort);
Yuta HIGUCHI407261a2014-02-13 16:34:06 -0800845 // This implies that change is made to Device Object.
846 // sending Device attachment point removed event
847 DeviceEvent rmEvent = new DeviceEvent(d.getMacAddress());
848 rmEvent.addAttachmentPoint(new SwitchPort(dstPort.getDpid(), dstPort.getNumber()));
849 removeDeviceEvent(rmEvent);
Yuta HIGUCHI76df2472014-02-12 22:36:51 -0800850 }
851 dstPortMem.removeAllDevice();
852 for(Device d : srcPortMem.getDevices() ) {
853 log.error("Device {} on Port {} should have been removed prior to adding Link {}", d, srcPort, linkEvt);
854 DeviceImpl dev = getDeviceImpl(d);
855 dev.removeAttachmentPoint(srcPort);
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 srcPortMem.removeAllDevice();
863
864 }
865
866 void removeLink(LinkEvent linkEvt) {
867 if (linkEvt == null) {
868 throw new IllegalArgumentException("Link cannot be null");
869 }
870
Pavlin Radoslavov06df22a2014-02-18 19:16:27 -0800871 Port srcPort = networkGraph.getPort(linkEvt.getSrc().dpid,
872 linkEvt.getSrc().number);
Yuta HIGUCHI76df2472014-02-12 22:36:51 -0800873 if (srcPort == null) {
874 log.warn("Src Port for Link {} already removed, ignoring", linkEvt);
875 return;
876 }
877
Pavlin Radoslavov06df22a2014-02-18 19:16:27 -0800878 Port dstPort = networkGraph.getPort(linkEvt.getDst().dpid,
879 linkEvt.getDst().number);
Yuta HIGUCHI76df2472014-02-12 22:36:51 -0800880 if (dstPort == null) {
881 log.warn("Dst Port for Link {} already removed, ignoring", linkEvt);
882 return;
883 }
884
885 Link l = dstPort.getIncomingLink();
886 if ( l == null ) {
887 log.warn("Link {} already removed on destination Port", linkEvt);
888 }
889 l = srcPort.getOutgoingLink();
890 if ( l == null ) {
891 log.warn("Link {} already removed on src Port", linkEvt);
892 }
893
894 getPortImpl(dstPort).setIncomingLink(null);
895 getPortImpl(srcPort).setOutgoingLink(null);
896 }
897
898 // XXX Need to rework Device related
899 void putDevice(DeviceEvent deviceEvt) {
900 if (deviceEvt == null) {
901 throw new IllegalArgumentException("Device cannot be null");
902 }
903
Pavlin Radoslavov6d224ee2014-02-18 16:43:15 -0800904 Device device = networkGraph.getDeviceByMac(deviceEvt.getMac());
Yuta HIGUCHI76df2472014-02-12 22:36:51 -0800905 if ( device == null ) {
Pavlin Radoslavov6d224ee2014-02-18 16:43:15 -0800906 device = new DeviceImpl(networkGraph, deviceEvt.getMac());
Yuta HIGUCHI76df2472014-02-12 22:36:51 -0800907 }
908 DeviceImpl memDevice = getDeviceImpl(device);
909
Pavlin Radoslavov6d224ee2014-02-18 16:43:15 -0800910 // for each IP address
911 for( InetAddress ipAddr : deviceEvt.getIpAddresses() ) {
912 memDevice.addIpAddress(ipAddr);
913 }
914
915 networkGraph.putDevice(device);
916
Yuta HIGUCHI76df2472014-02-12 22:36:51 -0800917 // for each attachment point
918 for (SwitchPort swp : deviceEvt.getAttachmentPoints() ) {
Yuta HIGUCHI76df2472014-02-12 22:36:51 -0800919 // Attached Ports must exist
Pavlin Radoslavov06df22a2014-02-18 19:16:27 -0800920 Port port = networkGraph.getPort(swp.dpid, swp.number);
Yuta HIGUCHI76df2472014-02-12 22:36:51 -0800921 if ( port == null ) {
Yuta HIGUCHI25719052014-02-13 14:42:06 -0800922 log.warn("Port for the attachment point {} did not exist. skipping mutation", swp);
Yuta HIGUCHI76df2472014-02-12 22:36:51 -0800923 continue;
924 }
925 // Attached Ports must not have Link
926 if ( port.getOutgoingLink() != null || port.getIncomingLink() != null ) {
927 log.warn("Link (Out:{},In:{}) exist on the attachment point, skipping mutation.", port.getOutgoingLink(), port.getIncomingLink());
928 continue;
929 }
930
931 // finally add Device <-> Port on In-memory structure
932 PortImpl memPort = getPortImpl(port);
933 memPort.addDevice(device);
934 memDevice.addAttachmentPoint(port);
935 }
Yuta HIGUCHI76df2472014-02-12 22:36:51 -0800936 }
937
938 void removeDevice(DeviceEvent deviceEvt) {
939 if (deviceEvt == null) {
940 throw new IllegalArgumentException("Device cannot be null");
941 }
942
Pavlin Radoslavov6d224ee2014-02-18 16:43:15 -0800943 Device device = networkGraph.getDeviceByMac(deviceEvt.getMac());
Yuta HIGUCHI76df2472014-02-12 22:36:51 -0800944 if ( device == null ) {
945 log.warn("Device {} already removed, ignoring", deviceEvt);
946 return;
947 }
948 DeviceImpl memDevice = getDeviceImpl(device);
949
950 // for each attachment point
951 for (SwitchPort swp : deviceEvt.getAttachmentPoints() ) {
Yuta HIGUCHI76df2472014-02-12 22:36:51 -0800952 // Attached Ports must exist
Pavlin Radoslavov06df22a2014-02-18 19:16:27 -0800953 Port port = networkGraph.getPort(swp.dpid, swp.number);
Yuta HIGUCHI76df2472014-02-12 22:36:51 -0800954 if ( port == null ) {
Yuta HIGUCHI25719052014-02-13 14:42:06 -0800955 log.warn("Port for the attachment point {} did not exist. skipping attachment point mutation", swp);
Yuta HIGUCHI76df2472014-02-12 22:36:51 -0800956 continue;
957 }
958
959 // finally remove Device <-> Port on In-memory structure
960 PortImpl memPort = getPortImpl(port);
961 memPort.removeDevice(device);
962 memDevice.removeAttachmentPoint(port);
963 }
Pavlin Radoslavov6d224ee2014-02-18 16:43:15 -0800964 networkGraph.removeDevice(device);
Yuta HIGUCHI76df2472014-02-12 22:36:51 -0800965 }
966
Yuta HIGUCHIa536e762014-02-17 21:47:28 -0800967 private void dispatchPutSwitchEvent(SwitchEvent switchEvent) {
968 for (INetworkGraphListener listener : this.networkGraphListeners) {
969 // TODO Should copy before handing them over to listener
970 listener.putSwitchEvent(switchEvent);
971 }
972 }
973
974 private void dispatchRemoveSwitchEvent(SwitchEvent switchEvent) {
975 for (INetworkGraphListener listener : this.networkGraphListeners) {
976 // TODO Should copy before handing them over to listener
977 listener.removeSwitchEvent(switchEvent);
978 }
979 }
980
981 private void dispatchPutPortEvent(PortEvent portEvent) {
982 for (INetworkGraphListener listener : this.networkGraphListeners) {
983 // TODO Should copy before handing them over to listener
984 listener.putPortEvent(portEvent);
985 }
986 }
987
988 private void dispatchRemovePortEvent(PortEvent portEvent) {
989 for (INetworkGraphListener listener : this.networkGraphListeners) {
990 // TODO Should copy before handing them over to listener
991 listener.removePortEvent(portEvent);
992 }
993 }
994
995 private void dispatchPutLinkEvent(LinkEvent linkEvent) {
996 for (INetworkGraphListener listener : this.networkGraphListeners) {
997 // TODO Should copy before handing them over to listener
998 listener.putLinkEvent(linkEvent);
999 }
1000 }
1001
1002 private void dispatchRemoveLinkEvent(LinkEvent linkEvent) {
1003 for (INetworkGraphListener listener : this.networkGraphListeners) {
1004 // TODO Should copy before handing them over to listener
1005 listener.removeLinkEvent(linkEvent);
1006 }
1007 }
1008
1009 private void dispatchPutDeviceEvent(DeviceEvent deviceEvent) {
1010 for (INetworkGraphListener listener : this.networkGraphListeners) {
1011 // TODO Should copy before handing them over to listener
1012 listener.putDeviceEvent(deviceEvent);;
1013 }
1014 }
1015
1016 private void dispatchRemoveDeviceEvent(DeviceEvent deviceEvent) {
1017 for (INetworkGraphListener listener : this.networkGraphListeners) {
1018 // TODO Should copy before handing them over to listener
1019 listener.removeDeviceEvent(deviceEvent);
1020 }
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
Pavlin Radoslavov06df22a2014-02-18 19:16:27 -08001080 Port srcPort = networkGraph.getPort(l.getSrc().dpid,
1081 l.getSrc().number);
1082 Port dstPort = networkGraph.getPort(l.getDst().dpid,
1083 l.getDst().number);
Yuta HIGUCHIdab94692014-02-18 09:12:02 -08001084 if ( srcPort == null || dstPort == null ) {
1085 continue;
1086 }
Yuta HIGUCHI76df2472014-02-12 22:36:51 -08001087 putLinkReplicationEvent( new LinkEvent(l.getSrc().dpid, l.getSrc().number, l.getDst().dpid, l.getDst().number));
1088 }
1089 }
Jonathan Hart062a2e82014-02-03 09:41:57 -08001090}