blob: bab8f4b69d3a01b94f0038d1ff743b27277b1c4e [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;
5import java.util.HashSet;
6import java.util.List;
7import java.util.Set;
8
Yuta HIGUCHI765cd0d2014-02-06 12:46:41 -08009import net.onrc.onos.datastore.topology.RCLink;
Jonathan Hart062a2e82014-02-03 09:41:57 -080010import net.onrc.onos.datastore.topology.RCPort;
11import net.onrc.onos.datastore.topology.RCSwitch;
Yuta HIGUCHI8d762e92014-02-12 14:10:25 -080012import net.onrc.onos.ofcontroller.networkgraph.PortEvent.SwitchPort;
Yuta HIGUCHI765cd0d2014-02-06 12:46:41 -080013import net.onrc.onos.ofcontroller.util.Dpid;
Jonathan Hart062a2e82014-02-03 09:41:57 -080014
15import org.slf4j.Logger;
16import org.slf4j.LoggerFactory;
17
Yuta HIGUCHI181d34d2014-02-05 15:05:46 -080018/**
19 * The "NB" read-only Network Map.
20 *
Yuta HIGUCHI4bfdd532014-02-07 13:47:36 -080021 * - Maintain Invariant/Relationships between Topology Objects.
22 *
Yuta HIGUCHI765cd0d2014-02-06 12:46:41 -080023 * TODO To be synchronized based on TopologyEvent Notification.
Yuta HIGUCHI181d34d2014-02-05 15:05:46 -080024 *
Yuta HIGUCHIcb951982014-02-11 13:31:44 -080025 * TODO TBD: Caller is expected to maintain parent/child calling order. Parent
Yuta HIGUCHI1c700102014-02-12 16:30:52 -080026 * Object must exist before adding sub component(Add Switch -> Port).
Yuta HIGUCHIcb951982014-02-11 13:31:44 -080027 *
Yuta HIGUCHI4bfdd532014-02-07 13:47:36 -080028 * TODO TBD: This class may delay the requested change to handle event
29 * re-ordering. e.g.) Link Add came in, but Switch was not there.
Yuta HIGUCHIcb951982014-02-11 13:31:44 -080030 *
Yuta HIGUCHI181d34d2014-02-05 15:05:46 -080031 */
Yuta HIGUCHI928fa682014-02-11 19:07:57 -080032public class NetworkGraphImpl extends AbstractNetworkGraph implements
33 NetworkGraphDiscoveryInterface, NetworkGraphReplicationInterface {
Jonathan Hart062a2e82014-02-03 09:41:57 -080034
Yuta HIGUCHI80829d12014-02-05 20:16:56 -080035 private static final Logger log = LoggerFactory
36 .getLogger(NetworkGraphImpl.class);
Yuta HIGUCHIcd922f42014-02-11 18:59:11 -080037
Jonathan Hart22eb9882014-02-11 15:52:59 -080038 private final NetworkGraphDatastore datastore;
Yuta HIGUCHI181d34d2014-02-05 15:05:46 -080039
Yuta HIGUCHI80829d12014-02-05 20:16:56 -080040 public NetworkGraphImpl() {
41 super();
Jonathan Hart22eb9882014-02-11 15:52:59 -080042 datastore = new NetworkGraphDatastore(this);
Yuta HIGUCHI80829d12014-02-05 20:16:56 -080043 }
Yuta HIGUCHI181d34d2014-02-05 15:05:46 -080044
Yuta HIGUCHI4bfdd532014-02-07 13:47:36 -080045 /**
Yuta HIGUCHIcb951982014-02-11 13:31:44 -080046 * Exception to be thrown when Modification to the Network Graph cannot be continued due to broken invariant.
47 *
48 * XXX Should this be checked exception or RuntimeException
49 */
50 public static class BrokenInvariantException extends RuntimeException {
51 private static final long serialVersionUID = 1L;
52
53 public BrokenInvariantException() {
54 super();
55 }
56
57 public BrokenInvariantException(String message) {
58 super(message);
59 }
60 }
Jonathan Hart22eb9882014-02-11 15:52:59 -080061
62 /* ******************************
63 * NetworkGraphDiscoveryInterface methods
64 * ******************************/
Yuta HIGUCHIcd922f42014-02-11 18:59:11 -080065
Jonathan Hart22eb9882014-02-11 15:52:59 -080066 @Override
67 public void putSwitchEvent(SwitchEvent switchEvent) {
Yuta HIGUCHId02e9282014-02-12 09:24:41 -080068 if (prepareForAddSwitchEvent(switchEvent)) {
Jonathan Hart22eb9882014-02-11 15:52:59 -080069 datastore.addSwitch(switchEvent);
70 putSwitch(switchEvent);
Yuta HIGUCHId02e9282014-02-12 09:24:41 -080071 // TODO send out notification
Jonathan Hart22eb9882014-02-11 15:52:59 -080072 }
73 // TODO handle invariant violation
74 }
75
76 @Override
77 public void removeSwitchEvent(SwitchEvent switchEvent) {
Yuta HIGUCHId02e9282014-02-12 09:24:41 -080078 if (prepareForRemoveSwitchEvent(switchEvent)) {
Jonathan Hart22eb9882014-02-11 15:52:59 -080079 datastore.deactivateSwitch(switchEvent);
80 removeSwitch(switchEvent);
Yuta HIGUCHId02e9282014-02-12 09:24:41 -080081 // TODO send out notification
Jonathan Hart22eb9882014-02-11 15:52:59 -080082 }
83 // TODO handle invariant violation
84 }
85
86 @Override
87 public void putPortEvent(PortEvent portEvent) {
Jonathan Hart4c263272014-02-13 17:41:05 -080088 if (prepareForAddPortEvent(portEvent)) {
89 datastore.addPort(portEvent);
90 putPort(portEvent);
91 // TODO send out notification
92 }
Yuta HIGUCHI75c51ed2014-02-13 17:02:26 -080093 // TODO handle invariant violation
Jonathan Hart22eb9882014-02-11 15:52:59 -080094 }
95
96 @Override
97 public void removePortEvent(PortEvent portEvent) {
Jonathan Hart4c263272014-02-13 17:41:05 -080098 if (prepareForRemovePortEvent(portEvent)) {
99 datastore.deactivatePort(portEvent);
100 removePort(portEvent);
101 // TODO send out notification
102 }
Yuta HIGUCHI75c51ed2014-02-13 17:02:26 -0800103 // TODO handle invariant violation
Jonathan Hart22eb9882014-02-11 15:52:59 -0800104 }
105
106 @Override
107 public void putLinkEvent(LinkEvent linkEvent) {
Yuta HIGUCHId02e9282014-02-12 09:24:41 -0800108 if (prepareForAddLinkEvent(linkEvent)) {
Jonathan Hart22eb9882014-02-11 15:52:59 -0800109 datastore.addLink(linkEvent);
110 putLink(linkEvent);
Yuta HIGUCHId02e9282014-02-12 09:24:41 -0800111 // TODO send out notification
Jonathan Hart22eb9882014-02-11 15:52:59 -0800112 }
113 // TODO handle invariant violation
114 }
115
116 @Override
117 public void removeLinkEvent(LinkEvent linkEvent) {
Yuta HIGUCHId02e9282014-02-12 09:24:41 -0800118 if (prepareForRemoveLinkEvent(linkEvent)) {
Jonathan Hart22eb9882014-02-11 15:52:59 -0800119 datastore.removeLink(linkEvent);
120 removeLink(linkEvent);
Yuta HIGUCHId02e9282014-02-12 09:24:41 -0800121 // TODO send out notification
Jonathan Hart22eb9882014-02-11 15:52:59 -0800122 }
123 // TODO handle invariant violation
124 }
125
126 @Override
Yuta HIGUCHI586d33e2014-02-13 17:05:08 -0800127 public void putDeviceEvent(DeviceEvent deviceEvent) {
128 if (prepareForAddDeviceEvent(deviceEvent)) {
129// datastore.addDevice(deviceEvent);
130 // TODO send out notification
131 }
132 // TODO handle invariant violation
133 // XXX if prepareFor~ method returned false, event should be dropped
Jonathan Hart22eb9882014-02-11 15:52:59 -0800134 }
135
136 @Override
137 public void removeDeviceEvent(DeviceEvent deviceEvent) {
Yuta HIGUCHI586d33e2014-02-13 17:05:08 -0800138 if (prepareForRemoveDeviceEvent(deviceEvent)) {
139// datastore.removeDevice(deviceEvent);
140 // TODO send out notification
141 }
142 // TODO handle invariant violation
143 // XXX if prepareFor~ method returned false, event should be dropped
Jonathan Hart22eb9882014-02-11 15:52:59 -0800144 }
Yuta HIGUCHIcd922f42014-02-11 18:59:11 -0800145
Jonathan Hart22eb9882014-02-11 15:52:59 -0800146 /* *****************
Yuta HIGUCHId02e9282014-02-12 09:24:41 -0800147 * Internal methods to maintain invariants of the network graph
Jonathan Hart22eb9882014-02-11 15:52:59 -0800148 * *****************/
Yuta HIGUCHIcd922f42014-02-11 18:59:11 -0800149
Yuta HIGUCHId02e9282014-02-12 09:24:41 -0800150 /**
151 *
152 * @param swEvt
153 * @return true if ready to accept event.
154 */
155 private boolean prepareForAddSwitchEvent(SwitchEvent swEvt) {
Yuta HIGUCHI76df2472014-02-12 22:36:51 -0800156 // No show stopping precondition
Yuta HIGUCHI8d762e92014-02-12 14:10:25 -0800157 // Prep: remove(deactivate) Ports on Switch, which is not on event
158 removePortsNotOnEvent(swEvt);
159 return true;
Jonathan Hart22eb9882014-02-11 15:52:59 -0800160 }
Yuta HIGUCHIcd922f42014-02-11 18:59:11 -0800161
Yuta HIGUCHId02e9282014-02-12 09:24:41 -0800162 private boolean prepareForRemoveSwitchEvent(SwitchEvent swEvt) {
Yuta HIGUCHI76df2472014-02-12 22:36:51 -0800163 // No show stopping precondition
Yuta HIGUCHI8d762e92014-02-12 14:10:25 -0800164 // Prep: remove(deactivate) Ports on Switch, which is not on event
165 // XXX may be remove switch should imply wipe all ports
166 removePortsNotOnEvent(swEvt);
167 return true;
168 }
Yuta HIGUCHId02e9282014-02-12 09:24:41 -0800169
Yuta HIGUCHI8d762e92014-02-12 14:10:25 -0800170 private void removePortsNotOnEvent(SwitchEvent swEvt) {
171 Switch sw = switches.get( swEvt.getDpid() );
172 if ( sw != null ) {
173 Set<Long> port_noOnEvent = new HashSet<>();
174 for( PortEvent portEvent : swEvt.getPorts()) {
175 port_noOnEvent.add(portEvent.getNumber());
176 }
177 // Existing ports not on event should be removed.
178 // TODO Should batch eventually for performance?
179 for( Port p : sw.getPorts() ) {
180 if ( !port_noOnEvent.contains(p.getNumber()) ) {
181 PortEvent rmEvent = new PortEvent(p.getSwitch().getDpid(), p.getNumber());
182 // calling Discovery removePort() API to wipe from DB, etc.
183 removePortEvent(rmEvent);
184 }
185 }
186 }
Jonathan Hart22eb9882014-02-11 15:52:59 -0800187 }
Yuta HIGUCHIcd922f42014-02-11 18:59:11 -0800188
Yuta HIGUCHId02e9282014-02-12 09:24:41 -0800189 private boolean prepareForAddPortEvent(PortEvent portEvt) {
Yuta HIGUCHId02e9282014-02-12 09:24:41 -0800190 // Parent Switch must exist
191 if ( getSwitch(portEvt.getDpid()) == null) {
192 return false;
193 }
194 // Prep: None
Jonathan Hart22eb9882014-02-11 15:52:59 -0800195 return true;
196 }
Yuta HIGUCHIcd922f42014-02-11 18:59:11 -0800197
Yuta HIGUCHId02e9282014-02-12 09:24:41 -0800198 private boolean prepareForRemovePortEvent(PortEvent portEvt) {
Yuta HIGUCHId02e9282014-02-12 09:24:41 -0800199 // Parent Switch must exist
Yuta HIGUCHI8d762e92014-02-12 14:10:25 -0800200 Switch sw = getSwitch(portEvt.getDpid());
201 if ( sw == null ) {
Yuta HIGUCHI88be0f22014-02-14 17:20:43 -0800202 log.debug("Switch already removed? {}", portEvt);
Yuta HIGUCHId02e9282014-02-12 09:24:41 -0800203 return false;
204 }
Yuta HIGUCHI8d762e92014-02-12 14:10:25 -0800205 Port port = sw.getPort(portEvt.getNumber());
206 if ( port == null ) {
207 log.debug("Port already removed? {}", portEvt);
208 // let it pass
209 return true;
210 }
211
212 // Prep: Remove Link and Device Attachment
213 for (Device device : port.getDevices()) {
Yuta HIGUCHI88be0f22014-02-14 17:20:43 -0800214 log.debug("Removing Device {} on Port {}", device, portEvt);
Yuta HIGUCHI8d762e92014-02-12 14:10:25 -0800215 DeviceEvent devEvt = new DeviceEvent(device.getMacAddress());
216 devEvt.addAttachmentPoint(new SwitchPort(port.getSwitch().getDpid(), port.getNumber()));
217 // calling Discovery API to wipe from DB, etc.
218 removeDeviceEvent(devEvt);
219 }
220 Set<Link> links = new HashSet<>();
221 links.add(port.getOutgoingLink());
222 links.add(port.getIncomingLink());
223 for ( Link link : links) {
224 if (link == null ) {
225 continue;
226 }
Yuta HIGUCHI88be0f22014-02-14 17:20:43 -0800227 log.debug("Removing Link {} on Port {}", link, portEvt);
Yuta HIGUCHI8d762e92014-02-12 14:10:25 -0800228 LinkEvent linkEvent = new LinkEvent(link.getSourceSwitchDpid(), link.getSourcePortNumber(), link.getDestinationSwitchDpid(), link.getDestinationPortNumber());
229 // calling Discovery API to wipe from DB, etc.
230 removeLinkEvent(linkEvent);
231 }
Jonathan Hart22eb9882014-02-11 15:52:59 -0800232 return true;
233 }
Yuta HIGUCHIcd922f42014-02-11 18:59:11 -0800234
Yuta HIGUCHId02e9282014-02-12 09:24:41 -0800235 private boolean prepareForAddLinkEvent(LinkEvent linkEvt) {
Yuta HIGUCHI8d762e92014-02-12 14:10:25 -0800236 // Src/Dst Switch must exist
237 Switch srcSw = getSwitch(linkEvt.getSrc().dpid);
238 Switch dstSw = getSwitch(linkEvt.getDst().dpid);
239 if ( srcSw == null || dstSw == null ) {
240 return false;
241 }
242 // Src/Dst Port must exist
243 Port srcPort = srcSw.getPort(linkEvt.getSrc().number);
Jonathan Hart4c263272014-02-13 17:41:05 -0800244 Port dstPort = dstSw.getPort(linkEvt.getDst().number);
Yuta HIGUCHI8d762e92014-02-12 14:10:25 -0800245 if ( srcPort == null || dstPort == null ) {
246 return false;
247 }
248
249 // Prep: remove Device attachment on both Ports
250 for (Device device : srcPort.getDevices()) {
251 DeviceEvent devEvt = new DeviceEvent(device.getMacAddress());
252 devEvt.addAttachmentPoint(new SwitchPort(srcPort.getSwitch().getDpid(), srcPort.getNumber()));
253 // calling Discovery API to wipe from DB, etc.
254 removeDeviceEvent(devEvt);
255 }
256 for (Device device : dstPort.getDevices()) {
257 DeviceEvent devEvt = new DeviceEvent(device.getMacAddress());
258 devEvt.addAttachmentPoint(new SwitchPort(dstPort.getSwitch().getDpid(), dstPort.getNumber()));
259 // calling Discovery API to wipe from DB, etc.
260 removeDeviceEvent(devEvt);
261 }
262
263 return true;
Jonathan Hart22eb9882014-02-11 15:52:59 -0800264 }
Yuta HIGUCHIcd922f42014-02-11 18:59:11 -0800265
Yuta HIGUCHId02e9282014-02-12 09:24:41 -0800266 private boolean prepareForRemoveLinkEvent(LinkEvent linkEvt) {
Yuta HIGUCHI8d762e92014-02-12 14:10:25 -0800267 // Src/Dst Switch must exist
268 Switch srcSw = getSwitch(linkEvt.getSrc().dpid);
269 Switch dstSw = getSwitch(linkEvt.getDst().dpid);
270 if ( srcSw == null || dstSw == null ) {
Yuta HIGUCHI125c7df2014-02-14 12:28:10 -0800271 log.warn("Rejecting removeLink {} because switch doesn't exist", linkEvt);
Yuta HIGUCHI8d762e92014-02-12 14:10:25 -0800272 return false;
273 }
274 // Src/Dst Port must exist
275 Port srcPort = srcSw.getPort(linkEvt.getSrc().number);
Yuta HIGUCHI125c7df2014-02-14 12:28:10 -0800276 Port dstPort = dstSw.getPort(linkEvt.getDst().number);
Yuta HIGUCHI8d762e92014-02-12 14:10:25 -0800277 if ( srcPort == null || dstPort == null ) {
Yuta HIGUCHI125c7df2014-02-14 12:28:10 -0800278 log.warn("Rejecting removeLink {} because port doesn't exist", linkEvt);
Yuta HIGUCHI8d762e92014-02-12 14:10:25 -0800279 return false;
280 }
281
Yuta HIGUCHI125c7df2014-02-14 12:28:10 -0800282 Link link = srcPort.getOutgoingLink();
283
284 // Link is already gone, or different Link exist in memory
285 // XXX Check if we should reject or just accept these cases.
286 // it should be harmless to remove the Link on event from DB anyways
287 if (link == null ||
288 !link.getDestinationPortNumber().equals(linkEvt.getDst().number)
289 || !link.getDestinationSwitchDpid().equals(linkEvt.getDst().dpid)) {
290 log.warn("Rejecting removeLink {} because link doesn't exist", linkEvt);
291 return false;
292 }
Yuta HIGUCHI8d762e92014-02-12 14:10:25 -0800293 // Prep: None
294 return true;
Jonathan Hart22eb9882014-02-11 15:52:59 -0800295 }
Yuta HIGUCHIcd922f42014-02-11 18:59:11 -0800296
Yuta HIGUCHI8d762e92014-02-12 14:10:25 -0800297 /**
298 *
299 * @param deviceEvt Event will be modified to remove inapplicable attachemntPoints/ipAddress
300 * @return false if this event should be dropped.
301 */
Yuta HIGUCHId02e9282014-02-12 09:24:41 -0800302 private boolean prepareForAddDeviceEvent(DeviceEvent deviceEvt) {
Yuta HIGUCHI8d762e92014-02-12 14:10:25 -0800303 boolean preconditionBroken = false;
304 ArrayList<PortEvent.SwitchPort> failedSwitchPort = new ArrayList<>();
305 for ( PortEvent.SwitchPort swp : deviceEvt.getAttachmentPoints() ) {
Yuta HIGUCHId02e9282014-02-12 09:24:41 -0800306 // Attached Ports' Parent Switch must exist
Yuta HIGUCHI8d762e92014-02-12 14:10:25 -0800307 Switch sw = getSwitch(swp.dpid);
308 if ( sw == null ) {
309 preconditionBroken = true;
310 failedSwitchPort.add(swp);
311 continue;
312 }
Yuta HIGUCHId02e9282014-02-12 09:24:41 -0800313 // Attached Ports must exist
Yuta HIGUCHI8d762e92014-02-12 14:10:25 -0800314 Port port = sw.getPort(swp.number);
315 if ( port == null ) {
316 preconditionBroken = true;
317 failedSwitchPort.add(swp);
318 continue;
319 }
Yuta HIGUCHId02e9282014-02-12 09:24:41 -0800320 // Attached Ports must not have Link
Yuta HIGUCHI8d762e92014-02-12 14:10:25 -0800321 if ( port.getOutgoingLink() != null || port.getIncomingLink() != null ) {
322 preconditionBroken = true;
323 failedSwitchPort.add(swp);
324 continue;
325 }
326 }
Yuta HIGUCHId02e9282014-02-12 09:24:41 -0800327
Yuta HIGUCHI8d762e92014-02-12 14:10:25 -0800328 // Rewriting event to exclude failed attachmentPoint
329 // XXX Assumption behind this is that inapplicable device event should
330 // be dropped, not deferred. If we decide to defer Device event,
331 // rewriting can become a problem
332 List<SwitchPort> attachmentPoints = deviceEvt.getAttachmentPoints();
333 attachmentPoints.removeAll(failedSwitchPort);
334 deviceEvt.setAttachmentPoints(attachmentPoints);
335
336 if ( deviceEvt.getAttachmentPoints().isEmpty() && deviceEvt.getIpAddresses().isEmpty() ) {
Yuta HIGUCHI125c7df2014-02-14 12:28:10 -0800337 // return false to represent: Nothing left to do for this event. Caller should drop event
Yuta HIGUCHI8d762e92014-02-12 14:10:25 -0800338 return false;
339 }
340
341 // Should we return false to tell caller that the event was trimmed?
342 // if ( preconditionBroken ) {
343 // return false;
344 // }
345
346 return true;
Jonathan Hart22eb9882014-02-11 15:52:59 -0800347 }
Yuta HIGUCHIcd922f42014-02-11 18:59:11 -0800348
Yuta HIGUCHId02e9282014-02-12 09:24:41 -0800349 private boolean prepareForRemoveDeviceEvent(DeviceEvent deviceEvt) {
Yuta HIGUCHId02e9282014-02-12 09:24:41 -0800350 // No show stopping precondition?
351 // Prep: none
Jonathan Hart22eb9882014-02-11 15:52:59 -0800352 return true;
353 }
Yuta HIGUCHI928fa682014-02-11 19:07:57 -0800354
Yuta HIGUCHI76df2472014-02-12 22:36:51 -0800355 /* ******************************
356 * NetworkGraphReplicationInterface methods
357 * ******************************/
358
Yuta HIGUCHI928fa682014-02-11 19:07:57 -0800359 @Override
360 public void putSwitchReplicationEvent(SwitchEvent switchEvent) {
Yuta HIGUCHI9fc10ac2014-02-12 17:18:57 -0800361 if (prepareForAddSwitchEvent(switchEvent)) {
362 putSwitch(switchEvent);
363 }
364 // TODO handle invariant violation
Yuta HIGUCHI928fa682014-02-11 19:07:57 -0800365 }
366
367 @Override
368 public void removeSwitchReplicationEvent(SwitchEvent switchEvent) {
Yuta HIGUCHI9fc10ac2014-02-12 17:18:57 -0800369 if (prepareForRemoveSwitchEvent(switchEvent)) {
370 removeSwitch(switchEvent);
371 }
Yuta HIGUCHI125c7df2014-02-14 12:28:10 -0800372 // TODO handle invariant violation
Yuta HIGUCHI928fa682014-02-11 19:07:57 -0800373 }
374
375 @Override
376 public void putPortReplicationEvent(PortEvent portEvent) {
Yuta HIGUCHI9fc10ac2014-02-12 17:18:57 -0800377 if (prepareForAddPortEvent(portEvent)) {
378 putPort(portEvent);
379 }
Yuta HIGUCHI125c7df2014-02-14 12:28:10 -0800380 // TODO handle invariant violation
Yuta HIGUCHI928fa682014-02-11 19:07:57 -0800381 }
382
383 @Override
384 public void removePortReplicationEvent(PortEvent portEvent) {
Yuta HIGUCHI9fc10ac2014-02-12 17:18:57 -0800385 if (prepareForRemovePortEvent(portEvent)) {
386 removePort(portEvent);
387 }
Yuta HIGUCHI125c7df2014-02-14 12:28:10 -0800388 // TODO handle invariant violation
Yuta HIGUCHI928fa682014-02-11 19:07:57 -0800389 }
390
391 @Override
392 public void putLinkReplicationEvent(LinkEvent linkEvent) {
Yuta HIGUCHI9fc10ac2014-02-12 17:18:57 -0800393 if (prepareForAddLinkEvent(linkEvent)) {
394 putLink(linkEvent);
395 }
Yuta HIGUCHI125c7df2014-02-14 12:28:10 -0800396 // TODO handle invariant violation
Yuta HIGUCHI928fa682014-02-11 19:07:57 -0800397 }
398
399 @Override
400 public void removeLinkReplicationEvent(LinkEvent linkEvent) {
Yuta HIGUCHI9fc10ac2014-02-12 17:18:57 -0800401 if (prepareForRemoveLinkEvent(linkEvent)) {
402 removeLink(linkEvent);
403 }
Yuta HIGUCHI125c7df2014-02-14 12:28:10 -0800404 // TODO handle invariant violation
Yuta HIGUCHI928fa682014-02-11 19:07:57 -0800405 }
406
407 @Override
408 public void putDeviceReplicationEvent(DeviceEvent deviceEvent) {
Yuta HIGUCHI9fc10ac2014-02-12 17:18:57 -0800409 if (prepareForAddDeviceEvent(deviceEvent)) {
410 putDevice(deviceEvent);
411 }
Yuta HIGUCHI125c7df2014-02-14 12:28:10 -0800412 // TODO handle invariant violation
Yuta HIGUCHI928fa682014-02-11 19:07:57 -0800413 }
414
415 @Override
416 public void removeDeviceReplicationEvent(DeviceEvent deviceEvent) {
Yuta HIGUCHI9fc10ac2014-02-12 17:18:57 -0800417 if (prepareForRemoveDeviceEvent(deviceEvent)) {
418 removeDevice(deviceEvent);
419 }
Yuta HIGUCHI125c7df2014-02-14 12:28:10 -0800420 // TODO handle invariant violation
Yuta HIGUCHI928fa682014-02-11 19:07:57 -0800421 }
Yuta HIGUCHI76df2472014-02-12 22:36:51 -0800422
423 /* ************************************************
424 * Internal In-memory object mutation methods.
425 * ************************************************/
426
427 void putSwitch(SwitchEvent swEvt) {
428 if (swEvt == null) {
429 throw new IllegalArgumentException("Switch cannot be null");
430 }
431
432 Switch sw = switches.get(swEvt.getDpid());
433
434 if (sw == null) {
435 sw = new SwitchImpl(this, swEvt.getDpid());
436 Switch existing = switches.putIfAbsent(swEvt.getDpid(), sw);
437 if (existing != null) {
438 log.warn(
439 "Concurrent putSwitch not expected. Continuing updating {}",
440 existing);
441 sw = existing;
442 }
443 }
444
445 // Update when more attributes are added to Event object
446 // no attribute to update for now
447
448 // TODO handle child Port event properly for performance
449 for (PortEvent portEvt : swEvt.getPorts() ) {
450 putPort(portEvt);
451 }
452
453 }
454
455 void removeSwitch(SwitchEvent swEvt) {
456 if (swEvt == null) {
457 throw new IllegalArgumentException("Switch cannot be null");
458 }
459
460 // TODO handle child Port event properly for performance
461 for (PortEvent portEvt : swEvt.getPorts() ) {
462 removePort(portEvt);
463 }
464
465 Switch sw = switches.get(swEvt.getDpid());
466
467 if (sw == null) {
468 log.warn("Switch {} already removed, ignoring", swEvt);
469 return;
470 }
471
472 // Sanity check
473 if (!sw.getPorts().isEmpty()) {
474 log.warn(
475 "Ports on Switch {} should be removed prior to removing Switch. Removing Switch anyways",
476 swEvt);
477 // XXX Should we remove Port?
478 }
479 if (!sw.getDevices().isEmpty()) {
480 log.warn(
481 "Devices on Switch {} should be removed prior to removing Switch. Removing Switch anyways",
482 swEvt);
483 // XXX Should we remove Device to Switch relation?
484 }
485 if (!sw.getIncomingLinks().iterator().hasNext()) {
486 log.warn(
487 "IncomingLinks on Switch {} should be removed prior to removing Switch. Removing Switch anyways",
488 swEvt);
489 // XXX Should we remove Link?
490 }
491 if (!sw.getOutgoingLinks().iterator().hasNext()) {
492 log.warn(
493 "OutgoingLinks on Switch {} should be removed prior to removing Switch. Removing Switch anyways",
494 swEvt);
495 // XXX Should we remove Link?
496 }
497
498 boolean removed = switches.remove(swEvt.getDpid(), sw);
499 if (removed) {
500 log.warn(
501 "Switch instance was replaced concurrently while removing {}. Something is not right.",
502 sw);
503 }
504 }
505
506 void putPort(PortEvent portEvt) {
507 if (portEvt == null) {
508 throw new IllegalArgumentException("Port cannot be null");
509 }
510 Switch sw = switches.get(portEvt.getDpid());
511 if (sw == null) {
512 throw new BrokenInvariantException(String.format(
513 "Switch with dpid %s did not exist.",
514 new Dpid(portEvt.getDpid())));
515 }
516 Port p = sw.getPort(portEvt.getNumber());
517 PortImpl port = null;
518 if (p != null) {
519 port = getPortImpl(p);
520 }
521
522 if (port == null) {
523 port = new PortImpl(this, sw, portEvt.getNumber());
524 }
525
526 // TODO update attributes
527
528 SwitchImpl s = getSwitchImpl(sw);
529 s.addPort(port);
530 }
531
532 void removePort(PortEvent portEvt) {
533 if (portEvt == null) {
534 throw new IllegalArgumentException("Port cannot be null");
535 }
536
537 Switch sw = switches.get(portEvt.getDpid());
538 if (sw == null) {
539 log.warn("Parent Switch for Port {} already removed, ignoring", portEvt);
540 return;
541 }
542
543 Port p = sw.getPort(portEvt.getNumber());
544 if (p == null) {
545 log.warn("Port {} already removed, ignoring", portEvt);
546 return;
547 }
548
549 // check if there is something referring to this Port
550
551 if (!p.getDevices().iterator().hasNext()) {
552 log.warn(
553 "Devices on Port {} should be removed prior to removing Port. Removing Port anyways",
554 portEvt);
555 // XXX Should we remove Device to Port relation?
556 }
557 if (p.getIncomingLink() != null) {
558 log.warn(
559 "IncomingLinks on Port {} should be removed prior to removing Port. Removing Port anyways",
560 portEvt);
561 // XXX Should we remove Link?
562 }
563 if (p.getOutgoingLink() != null) {
564 log.warn(
565 "OutgoingLinks on Port {} should be removed prior to removing Port. Removing Port anyways",
566 portEvt);
567 // XXX Should we remove Link?
568 }
569
570 // remove Port from Switch
571 SwitchImpl s = getSwitchImpl(sw);
572 s.removePort(p);
573 }
574
575 void putLink(LinkEvent linkEvt) {
576 if (linkEvt == null) {
577 throw new IllegalArgumentException("Link cannot be null");
578 }
579
580 Switch srcSw = switches.get(linkEvt.getSrc().dpid);
581 if (srcSw == null) {
582 throw new BrokenInvariantException(
583 String.format(
584 "Switch with dpid %s did not exist.",
585 new Dpid(linkEvt.getSrc().dpid)));
586 }
587
588 Switch dstSw = switches.get(linkEvt.getDst().dpid);
589 if (dstSw == null) {
590 throw new BrokenInvariantException(
591 String.format(
592 "Switch with dpid %s did not exist.",
593 new Dpid(linkEvt.getDst().dpid)));
594 }
595
596 Port srcPort = srcSw.getPort(linkEvt.getSrc().number);
597 if (srcPort == null) {
598 throw new BrokenInvariantException(
599 String.format(
600 "Src Port %s of a Link did not exist.",
601 linkEvt.getSrc() ));
602 }
603
604 Port dstPort = dstSw.getPort(linkEvt.getDst().number);
605 if (dstPort == null) {
606 throw new BrokenInvariantException(
607 String.format(
608 "Dst Port %s of a Link did not exist.",
609 linkEvt.getDst() ));
610 }
611
612 // getting Link instance from destination port incoming Link
613 Link l = dstPort.getIncomingLink();
614 LinkImpl link = null;
615 assert( l == srcPort.getOutgoingLink() );
616 if (l != null) {
617 link = getLinkImpl(l);
618 }
619
620 if (link == null) {
621 link = new LinkImpl(this, srcPort, dstPort);
622 }
623
624
625 PortImpl dstPortMem = getPortImpl(dstPort);
626 PortImpl srcPortMem = getPortImpl(srcPort);
627
628 // Add Link first to avoid further Device addition
629
630 // add Link to Port
631 dstPortMem.setIncomingLink(link);
632 srcPortMem.setOutgoingLink(link);
633
634 // remove Device Pointing to Port if any
635 for(Device d : dstPortMem.getDevices() ) {
636 log.error("Device {} on Port {} should have been removed prior to adding Link {}", d, dstPort, linkEvt);
637 DeviceImpl dev = getDeviceImpl(d);
638 dev.removeAttachmentPoint(dstPort);
Yuta HIGUCHI407261a2014-02-13 16:34:06 -0800639 // This implies that change is made to Device Object.
640 // sending Device attachment point removed event
641 DeviceEvent rmEvent = new DeviceEvent(d.getMacAddress());
642 rmEvent.addAttachmentPoint(new SwitchPort(dstPort.getDpid(), dstPort.getNumber()));
643 removeDeviceEvent(rmEvent);
Yuta HIGUCHI76df2472014-02-12 22:36:51 -0800644 }
645 dstPortMem.removeAllDevice();
646 for(Device d : srcPortMem.getDevices() ) {
647 log.error("Device {} on Port {} should have been removed prior to adding Link {}", d, srcPort, linkEvt);
648 DeviceImpl dev = getDeviceImpl(d);
649 dev.removeAttachmentPoint(srcPort);
Yuta HIGUCHI407261a2014-02-13 16:34:06 -0800650 // This implies that change is made to Device Object.
651 // sending Device attachment point removed event
652 DeviceEvent rmEvent = new DeviceEvent(d.getMacAddress());
653 rmEvent.addAttachmentPoint(new SwitchPort(dstPort.getDpid(), dstPort.getNumber()));
654 removeDeviceEvent(rmEvent);
Yuta HIGUCHI76df2472014-02-12 22:36:51 -0800655 }
656 srcPortMem.removeAllDevice();
657
658 }
659
660 void removeLink(LinkEvent linkEvt) {
661 if (linkEvt == null) {
662 throw new IllegalArgumentException("Link cannot be null");
663 }
664
665 Switch srcSw = switches.get(linkEvt.getSrc().dpid);
666 if (srcSw == null) {
667 log.warn("Src Switch for Link {} already removed, ignoring", linkEvt);
668 return;
669 }
670
671 Switch dstSw = switches.get(linkEvt.getDst().dpid);
672 if (dstSw == null) {
673 log.warn("Dst Switch for Link {} already removed, ignoring", linkEvt);
674 return;
675 }
676
677 Port srcPort = srcSw.getPort(linkEvt.getSrc().number);
678 if (srcPort == null) {
679 log.warn("Src Port for Link {} already removed, ignoring", linkEvt);
680 return;
681 }
682
683 Port dstPort = dstSw.getPort(linkEvt.getDst().number);
684 if (dstPort == null) {
685 log.warn("Dst Port for Link {} already removed, ignoring", linkEvt);
686 return;
687 }
688
689 Link l = dstPort.getIncomingLink();
690 if ( l == null ) {
691 log.warn("Link {} already removed on destination Port", linkEvt);
692 }
693 l = srcPort.getOutgoingLink();
694 if ( l == null ) {
695 log.warn("Link {} already removed on src Port", linkEvt);
696 }
697
698 getPortImpl(dstPort).setIncomingLink(null);
699 getPortImpl(srcPort).setOutgoingLink(null);
700 }
701
702 // XXX Need to rework Device related
703 void putDevice(DeviceEvent deviceEvt) {
704 if (deviceEvt == null) {
705 throw new IllegalArgumentException("Device cannot be null");
706 }
707
708 Device device = getDeviceByMac(deviceEvt.getMac());
709 if ( device == null ) {
710 device = new DeviceImpl(this, deviceEvt.getMac());
711 Device existing = mac2Device.putIfAbsent(deviceEvt.getMac(), device);
712 if (existing != null) {
713 log.warn(
714 "Concurrent putDevice seems to be in action. Continuing updating {}",
715 existing);
716 device = existing;
717 }
718 }
719 DeviceImpl memDevice = getDeviceImpl(device);
720
721 // for each attachment point
722 for (SwitchPort swp : deviceEvt.getAttachmentPoints() ) {
723 // Attached Ports' Parent Switch must exist
724 Switch sw = getSwitch(swp.dpid);
725 if ( sw == null ) {
Yuta HIGUCHI25719052014-02-13 14:42:06 -0800726 log.warn("Switch for the attachment point {} did not exist. skipping mutation", swp);
Yuta HIGUCHI76df2472014-02-12 22:36:51 -0800727 continue;
728 }
729 // Attached Ports must exist
730 Port port = sw.getPort(swp.number);
731 if ( port == null ) {
Yuta HIGUCHI25719052014-02-13 14:42:06 -0800732 log.warn("Port for the attachment point {} did not exist. skipping mutation", swp);
Yuta HIGUCHI76df2472014-02-12 22:36:51 -0800733 continue;
734 }
735 // Attached Ports must not have Link
736 if ( port.getOutgoingLink() != null || port.getIncomingLink() != null ) {
737 log.warn("Link (Out:{},In:{}) exist on the attachment point, skipping mutation.", port.getOutgoingLink(), port.getIncomingLink());
738 continue;
739 }
740
741 // finally add Device <-> Port on In-memory structure
742 PortImpl memPort = getPortImpl(port);
743 memPort.addDevice(device);
744 memDevice.addAttachmentPoint(port);
745 }
746
747 // for each IP address
748 for( InetAddress ipAddr : deviceEvt.getIpAddresses() ) {
749 // Add Device -> IP
750 memDevice.addIpAddress(ipAddr);
751
752 // Add IP -> Set<Device>
753 boolean updated = false;
754 do {
755 Set<Device> devices = this.addr2Device.get(ipAddr);
756 if ( devices == null ) {
757 devices = new HashSet<>();
758 Set<Device> existing = this.addr2Device.putIfAbsent(ipAddr, devices);
759 if ( existing == null ) {
760 // success
761 updated = true;
762 }
763 } else {
764 Set<Device> updateDevices = new HashSet<>(devices);
765 updateDevices.add(device);
766 updated = this.addr2Device.replace(ipAddr, devices, updateDevices);
767 }
768 if (!updated) {
769 log.debug("Collision detected, updating IP to Device mapping retrying.");
770 }
771 } while( !updated );
772 }
773 }
774
775 void removeDevice(DeviceEvent deviceEvt) {
776 if (deviceEvt == null) {
777 throw new IllegalArgumentException("Device cannot be null");
778 }
779
780 Device device = getDeviceByMac(deviceEvt.getMac());
781 if ( device == null ) {
782 log.warn("Device {} already removed, ignoring", deviceEvt);
783 return;
784 }
785 DeviceImpl memDevice = getDeviceImpl(device);
786
787 // for each attachment point
788 for (SwitchPort swp : deviceEvt.getAttachmentPoints() ) {
789 // Attached Ports' Parent Switch must exist
790 Switch sw = getSwitch(swp.dpid);
791 if ( sw == null ) {
Yuta HIGUCHI25719052014-02-13 14:42:06 -0800792 log.warn("Switch for the attachment point {} did not exist. skipping attachment point mutation", swp);
Yuta HIGUCHI76df2472014-02-12 22:36:51 -0800793 continue;
794 }
795 // Attached Ports must exist
796 Port port = sw.getPort(swp.number);
797 if ( port == null ) {
Yuta HIGUCHI25719052014-02-13 14:42:06 -0800798 log.warn("Port for the attachment point {} did not exist. skipping attachment point mutation", swp);
Yuta HIGUCHI76df2472014-02-12 22:36:51 -0800799 continue;
800 }
801
802 // finally remove Device <-> Port on In-memory structure
803 PortImpl memPort = getPortImpl(port);
804 memPort.removeDevice(device);
805 memDevice.removeAttachmentPoint(port);
806 }
807
808 // for each IP address
809 for( InetAddress ipAddr : deviceEvt.getIpAddresses() ) {
810 // Remove Device -> IP
811 memDevice.removeIpAddress(ipAddr);
812
813 // Remove IP -> Set<Device>
814 boolean updated = false;
815 do {
816 Set<Device> devices = this.addr2Device.get(ipAddr);
817 if ( devices == null ) {
818 // already empty set, nothing to do
819 updated = true;
820 } else {
821 Set<Device> updateDevices = new HashSet<>(devices);
822 updateDevices.remove(device);
823 updated = this.addr2Device.replace(ipAddr, devices, updateDevices);
824 }
825 if (!updated) {
826 log.debug("Collision detected, updating IP to Device mapping retrying.");
827 }
828 } while( !updated );
829 }
830 }
831
832 private SwitchImpl getSwitchImpl(Switch sw) {
833 if (sw instanceof SwitchImpl) {
834 return (SwitchImpl) sw;
835 }
836 throw new ClassCastException("SwitchImpl expected, but found: " + sw);
837 }
838
839 private PortImpl getPortImpl(Port p) {
840 if (p instanceof PortImpl) {
841 return (PortImpl) p;
842 }
843 throw new ClassCastException("PortImpl expected, but found: " + p);
844 }
845
846 private LinkImpl getLinkImpl(Link l) {
847 if (l instanceof LinkImpl) {
848 return (LinkImpl) l;
849 }
850 throw new ClassCastException("LinkImpl expected, but found: " + l);
851 }
852
853 private DeviceImpl getDeviceImpl(Device d) {
854 if (d instanceof DeviceImpl) {
855 return (DeviceImpl) d;
856 }
857 throw new ClassCastException("DeviceImpl expected, but found: " + d);
858 }
859
860 @Deprecated
861 public void loadWholeTopologyFromDB() {
862 // XXX clear everything first?
863
864 for (RCSwitch sw : RCSwitch.getAllSwitches()) {
865 if ( sw.getStatus() != RCSwitch.STATUS.ACTIVE ) {
866 continue;
867 }
868 putSwitchReplicationEvent(new SwitchEvent(sw.getDpid()));
869 }
870
871 for (RCPort p : RCPort.getAllPorts()) {
872 if (p.getStatus() != RCPort.STATUS.ACTIVE) {
873 continue;
874 }
875 putPortReplicationEvent(new PortEvent(p.getDpid(), p.getNumber() ));
876 }
877
878 // TODO Is Device going to be in DB? If so, read from DB.
879 // for (RCDevice d : RCDevice.getAllDevices()) {
880 // DeviceEvent devEvent = new DeviceEvent( MACAddress.valueOf(d.getMac()) );
881 // for (byte[] portId : d.getAllPortIds() ) {
882 // devEvent.addAttachmentPoint( new SwitchPort( RCPort.getDpidFromKey(portId), RCPort.getNumberFromKey(portId) ));
883 // }
884 // }
885
886 for (RCLink l : RCLink.getAllLinks()) {
887 putLinkReplicationEvent( new LinkEvent(l.getSrc().dpid, l.getSrc().number, l.getDst().dpid, l.getDst().number));
888 }
889 }
Jonathan Hart062a2e82014-02-03 09:41:57 -0800890}