blob: fcf3caa985719891da08a49aa6d25bc52d40f73a [file] [log] [blame]
Jonathan Hart472062d2014-04-03 10:56:48 -07001package net.onrc.onos.core.topology;
Yuta HIGUCHI80829d12014-02-05 20:16:56 -08002
Yuta HIGUCHI8313f0b2014-07-09 16:36:03 -07003import java.util.ArrayList;
Yuta HIGUCHIfa742842014-07-03 22:35:13 -07004import java.util.Collection;
Yuta HIGUCHI80829d12014-02-05 20:16:56 -08005import java.util.Collections;
Yuta HIGUCHI8313f0b2014-07-09 16:36:03 -07006import java.util.Iterator;
7import java.util.List;
8import java.util.Map;
Yuta HIGUCHI8b389a72014-07-18 13:50:00 -07009import java.util.Map.Entry;
Yuta HIGUCHI80829d12014-02-05 20:16:56 -080010import java.util.concurrent.ConcurrentHashMap;
11import java.util.concurrent.ConcurrentMap;
Jonathan Hart26f291b2014-02-18 16:57:24 -080012import java.util.concurrent.locks.Lock;
13import java.util.concurrent.locks.ReadWriteLock;
14import java.util.concurrent.locks.ReentrantReadWriteLock;
Yuta HIGUCHI80829d12014-02-05 20:16:56 -080015
Yuta HIGUCHI8313f0b2014-07-09 16:36:03 -070016import javax.annotation.concurrent.GuardedBy;
17
Yuta HIGUCHI80829d12014-02-05 20:16:56 -080018import net.floodlightcontroller.util.MACAddress;
Yuta HIGUCHI8f3dfa32014-06-25 00:14:25 -070019import net.onrc.onos.core.util.Dpid;
Yuta HIGUCHI8b389a72014-07-18 13:50:00 -070020import net.onrc.onos.core.util.LinkTuple;
Yuta HIGUCHI8f3dfa32014-06-25 00:14:25 -070021import net.onrc.onos.core.util.PortNumber;
Jonathan Hart25bd53e2014-04-30 23:44:09 -070022import net.onrc.onos.core.util.SwitchPort;
Yuta HIGUCHI80829d12014-02-05 20:16:56 -080023
24import org.slf4j.Logger;
25import org.slf4j.LoggerFactory;
26
Yuta HIGUCHIfa742842014-07-03 22:35:13 -070027import com.google.common.collect.HashMultimap;
28import com.google.common.collect.Multimap;
29import com.google.common.collect.Multimaps;
30
Yuta HIGUCHI8b389a72014-07-18 13:50:00 -070031
32/**
33 * Class to represent an instance of Topology Snapshot.
34 */
35public class TopologyImpl implements Topology, TopologyInternal {
36
Jonathan Harte37e4e22014-05-13 19:12:02 -070037 private static final Logger log = LoggerFactory.getLogger(TopologyImpl.class);
Yuta HIGUCHI80829d12014-02-05 20:16:56 -080038
Yuta HIGUCHI8b389a72014-07-18 13:50:00 -070039 // TODO Revisit Map types after implementing CoW/lock-free
40
Ray Milkey269ffb92014-04-03 14:43:30 -070041 // DPID -> Switch
Yuta HIGUCHI8b389a72014-07-18 13:50:00 -070042 private final ConcurrentMap<Dpid, SwitchEvent> switches;
43 private final ConcurrentMap<Dpid, ConcurrentMap<PortNumber, PortEvent>> ports;
Yuta HIGUCHIfa742842014-07-03 22:35:13 -070044
Yuta HIGUCHIbfc77f02014-07-14 22:50:25 -070045 // Index from Port to Host
Yuta HIGUCHI8b389a72014-07-18 13:50:00 -070046 private final Multimap<SwitchPort, HostEvent> hosts;
47 private final ConcurrentMap<MACAddress, HostEvent> mac2Host;
Jonathan Hart25bd53e2014-04-30 23:44:09 -070048
Yuta HIGUCHI8313f0b2014-07-09 16:36:03 -070049 // SwitchPort -> (type -> Link)
Yuta HIGUCHI8b389a72014-07-18 13:50:00 -070050 private final ConcurrentMap<SwitchPort, ConcurrentMap<String, LinkEvent>> outgoingLinks;
51 private final ConcurrentMap<SwitchPort, ConcurrentMap<String, LinkEvent>> incomingLinks;
Yuta HIGUCHI5d2d8d42014-02-20 22:22:53 -080052
Ray Milkey269ffb92014-04-03 14:43:30 -070053 private ReadWriteLock readWriteLock = new ReentrantReadWriteLock();
54 private Lock readLock = readWriteLock.readLock();
55 // TODO use the write lock after refactor
56 private Lock writeLock = readWriteLock.writeLock();
Yuta HIGUCHI80829d12014-02-05 20:16:56 -080057
Yuta HIGUCHI8b389a72014-07-18 13:50:00 -070058 /**
59 * Create an empty Topology.
60 */
Jonathan Harte37e4e22014-05-13 19:12:02 -070061 public TopologyImpl() {
Ray Milkey269ffb92014-04-03 14:43:30 -070062 // TODO: Does these object need to be stored in Concurrent Collection?
63 switches = new ConcurrentHashMap<>();
Yuta HIGUCHIfa742842014-07-03 22:35:13 -070064 ports = new ConcurrentHashMap<>();
Yuta HIGUCHIbfc77f02014-07-14 22:50:25 -070065 hosts = Multimaps.synchronizedMultimap(
Yuta HIGUCHI8b389a72014-07-18 13:50:00 -070066 HashMultimap.<SwitchPort, HostEvent>create());
Yuta HIGUCHIbfc77f02014-07-14 22:50:25 -070067 mac2Host = new ConcurrentHashMap<>();
Jonathan Hart25bd53e2014-04-30 23:44:09 -070068 outgoingLinks = new ConcurrentHashMap<>();
69 incomingLinks = new ConcurrentHashMap<>();
Ray Milkey269ffb92014-04-03 14:43:30 -070070 }
Yuta HIGUCHI80829d12014-02-05 20:16:56 -080071
Yuta HIGUCHI8b389a72014-07-18 13:50:00 -070072 /**
73 * Create a shallow copy of given Topology.
74 *
75 * @param original Topology
76 */
77 public TopologyImpl(TopologyImpl original) {
78 original.acquireReadLock();
79 try {
80 this.switches = new ConcurrentHashMap<>(original.switches);
81
82 // shallow copy Map in Map
83 this.ports = new ConcurrentHashMap<>(original.ports.size());
84 for (Entry<Dpid, ConcurrentMap<PortNumber, PortEvent>> entry
85 : original.ports.entrySet()) {
86 this.ports.put(entry.getKey(), new ConcurrentHashMap<>(entry.getValue()));
87 }
88
89 this.hosts = Multimaps.synchronizedMultimap(
90 HashMultimap.<SwitchPort, HostEvent>create(original.hosts));
91 this.mac2Host = new ConcurrentHashMap<>(original.mac2Host);
92
93 // shallow copy Map in Map
94 this.outgoingLinks = new ConcurrentHashMap<>(original.outgoingLinks.size());
95 for (Entry<SwitchPort, ConcurrentMap<String, LinkEvent>> entry
96 : original.outgoingLinks.entrySet()) {
97 this.outgoingLinks.put(entry.getKey(), new ConcurrentHashMap<>(entry.getValue()));
98 }
99
100 // shallow copy Map in Map
101 this.incomingLinks = new ConcurrentHashMap<>(original.incomingLinks.size());
102 for (Entry<SwitchPort, ConcurrentMap<String, LinkEvent>> entry
103 : original.incomingLinks.entrySet()) {
104 this.incomingLinks.put(entry.getKey(), new ConcurrentHashMap<>(entry.getValue()));
105 }
106 } finally {
107 original.releaseReadLock();
108 }
109 }
110
Ray Milkey269ffb92014-04-03 14:43:30 -0700111 @Override
Yuta HIGUCHI8f3dfa32014-06-25 00:14:25 -0700112 public Switch getSwitch(Dpid dpid) {
Yuta HIGUCHI8b389a72014-07-18 13:50:00 -0700113 final SwitchEvent sw = switches.get(dpid);
114 if (sw != null) {
115 return new SwitchImpl(this, dpid);
116 } else {
117 return null;
Yuta HIGUCHIfa742842014-07-03 22:35:13 -0700118 }
Ray Milkey269ffb92014-04-03 14:43:30 -0700119 }
Pavlin Radoslavov6d224ee2014-02-18 16:43:15 -0800120
Ray Milkey269ffb92014-04-03 14:43:30 -0700121 @Override
122 public Iterable<Switch> getSwitches() {
Yuta HIGUCHI8b389a72014-07-18 13:50:00 -0700123 List<Switch> list = new ArrayList<>(switches.size());
124 for (SwitchEvent elm : switches.values()) {
125 list.add(new SwitchImpl(this, elm.getDpid()));
126 }
127 return list;
Ray Milkey269ffb92014-04-03 14:43:30 -0700128 }
Yuta HIGUCHI80829d12014-02-05 20:16:56 -0800129
Ray Milkey269ffb92014-04-03 14:43:30 -0700130 @Override
Yuta HIGUCHI8f3dfa32014-06-25 00:14:25 -0700131 public Port getPort(Dpid dpid, PortNumber number) {
Yuta HIGUCHI8b389a72014-07-18 13:50:00 -0700132 ConcurrentMap<PortNumber, PortEvent> portMap = ports.get(dpid);
Yuta HIGUCHIfa742842014-07-03 22:35:13 -0700133 if (portMap != null) {
Yuta HIGUCHI8b389a72014-07-18 13:50:00 -0700134 final PortEvent port = portMap.get(number);
135 if (port != null) {
136 return new PortImpl(this, port.getSwitchPort());
137 }
Ray Milkey269ffb92014-04-03 14:43:30 -0700138 }
139 return null;
140 }
Pavlin Radoslavov06df22a2014-02-18 19:16:27 -0800141
Ray Milkey269ffb92014-04-03 14:43:30 -0700142 @Override
Yuta HIGUCHI8f3dfa32014-06-25 00:14:25 -0700143 public Port getPort(SwitchPort port) {
144 return getPort(port.dpid(), port.port());
Jonathan Hart25bd53e2014-04-30 23:44:09 -0700145 }
146
147 @Override
Yuta HIGUCHIfa742842014-07-03 22:35:13 -0700148 public Collection<Port> getPorts(Dpid dpid) {
Yuta HIGUCHI8b389a72014-07-18 13:50:00 -0700149 ConcurrentMap<PortNumber, PortEvent> portMap = ports.get(dpid);
Yuta HIGUCHIfa742842014-07-03 22:35:13 -0700150 if (portMap == null) {
151 return Collections.emptyList();
152 }
Yuta HIGUCHI8b389a72014-07-18 13:50:00 -0700153 List<Port> list = new ArrayList<>(portMap.size());
154 for (PortEvent elm : portMap.values()) {
155 list.add(new PortImpl(this, elm.getSwitchPort()));
156 }
157 return list;
Yuta HIGUCHIfa742842014-07-03 22:35:13 -0700158 }
159
160 @Override
Yuta HIGUCHI8f3dfa32014-06-25 00:14:25 -0700161 public Link getOutgoingLink(Dpid dpid, PortNumber number) {
Yuta HIGUCHI8313f0b2014-07-09 16:36:03 -0700162 return getOutgoingLink(new SwitchPort(dpid, number));
Ray Milkey269ffb92014-04-03 14:43:30 -0700163 }
Pavlin Radoslavov7c8f69a2014-02-19 19:01:45 -0800164
Ray Milkey269ffb92014-04-03 14:43:30 -0700165 @Override
Yuta HIGUCHI8f3dfa32014-06-25 00:14:25 -0700166 public Link getOutgoingLink(SwitchPort port) {
Yuta HIGUCHI8b389a72014-07-18 13:50:00 -0700167 Map<String, LinkEvent> links = outgoingLinks.get(port);
Yuta HIGUCHI8313f0b2014-07-09 16:36:03 -0700168 return getPacketLinkIfExists(links);
169 }
170
171 // TODO remove when we no longer need packet fall back behavior
172 /**
Yuta HIGUCHI8b389a72014-07-18 13:50:00 -0700173 * Gets the "packet" link if such exists,
174 * if not return whichever link is found first.
Yuta HIGUCHI8313f0b2014-07-09 16:36:03 -0700175 *
176 * @param links Collection of links to search from
177 * @return Link instance found or null if no link exists
178 */
Yuta HIGUCHI8b389a72014-07-18 13:50:00 -0700179 private Link getPacketLinkIfExists(Map<String, LinkEvent> links) {
Yuta HIGUCHI8313f0b2014-07-09 16:36:03 -0700180
181 if (links == null) {
182 return null;
183 }
184
Yuta HIGUCHI8b389a72014-07-18 13:50:00 -0700185 LinkEvent link = links.get(TopologyElement.TYPE_PACKET_LAYER);
Yuta HIGUCHI8313f0b2014-07-09 16:36:03 -0700186 if (link != null) {
187 // return packet link
Yuta HIGUCHI8b389a72014-07-18 13:50:00 -0700188 return new LinkImpl(this, link.getLinkTuple());
Yuta HIGUCHI8313f0b2014-07-09 16:36:03 -0700189 } else {
190 // return whatever found
Yuta HIGUCHI8b389a72014-07-18 13:50:00 -0700191 Iterator<LinkEvent> it = links.values().iterator();
Yuta HIGUCHI8313f0b2014-07-09 16:36:03 -0700192 if (it.hasNext()) {
Yuta HIGUCHI8b389a72014-07-18 13:50:00 -0700193 return new LinkImpl(this, it.next().getLinkTuple());
Yuta HIGUCHI8313f0b2014-07-09 16:36:03 -0700194 }
195 }
196 return null;
197 }
198
199 @Override
200 public Link getOutgoingLink(Dpid dpid, PortNumber number, String type) {
201 return getOutgoingLink(new SwitchPort(dpid, number), type);
202 }
203
204 @Override
205 public Link getOutgoingLink(SwitchPort port, String type) {
Yuta HIGUCHI8b389a72014-07-18 13:50:00 -0700206 Map<String, LinkEvent> links = outgoingLinks.get(port);
207 final LinkEvent link = links.get(type);
208 if (link != null) {
209 return new LinkImpl(this, link.getLinkTuple());
210 }
211 return null;
Yuta HIGUCHI8313f0b2014-07-09 16:36:03 -0700212 }
213
214 @Override
215 public Collection<Link> getOutgoingLinks(SwitchPort port) {
Yuta HIGUCHI8b389a72014-07-18 13:50:00 -0700216 ConcurrentMap<String, LinkEvent> typeMap = outgoingLinks.get(port);
217 if (typeMap == null) {
218 return Collections.emptyList();
219 }
220 return toLinkImpls(typeMap.values());
221 }
222
223 /**
224 * Converts collection of LinkEvent to collection of LinkImpls.
225 *
226 * @param links collection of LinkEvent
227 * @return collection of LinkImpls
228 */
229 private Collection<Link> toLinkImpls(final Collection<LinkEvent> links) {
230 if (links == null) {
231 return Collections.emptyList();
232 }
233 List<Link> list = new ArrayList<>(links.size());
234 for (LinkEvent elm : links) {
235 list.add(new LinkImpl(this, elm.getLinkTuple()));
236 }
237 return list;
Yuta HIGUCHI8f3dfa32014-06-25 00:14:25 -0700238 }
239
240 @Override
241 public Link getIncomingLink(Dpid dpid, PortNumber number) {
Yuta HIGUCHI8313f0b2014-07-09 16:36:03 -0700242 return getIncomingLink(new SwitchPort(dpid, number));
Yuta HIGUCHI8f3dfa32014-06-25 00:14:25 -0700243 }
244
245 @Override
246 public Link getIncomingLink(SwitchPort port) {
Yuta HIGUCHI8b389a72014-07-18 13:50:00 -0700247 Map<String, LinkEvent> links = incomingLinks.get(port);
Yuta HIGUCHI8313f0b2014-07-09 16:36:03 -0700248 return getPacketLinkIfExists(links);
249 }
250
251 @Override
252 public Link getIncomingLink(Dpid dpid, PortNumber number, String type) {
253 return getIncomingLink(new SwitchPort(dpid, number), type);
254 }
255
256 @Override
257 public Link getIncomingLink(SwitchPort port, String type) {
Yuta HIGUCHI8b389a72014-07-18 13:50:00 -0700258 Map<String, LinkEvent> links = incomingLinks.get(port);
259 final LinkEvent link = links.get(type);
260 if (link != null) {
261 return new LinkImpl(this, link.getLinkTuple());
262 }
263 return null;
Yuta HIGUCHI8313f0b2014-07-09 16:36:03 -0700264 }
265
266 @Override
267 public Collection<Link> getIncomingLinks(SwitchPort port) {
Yuta HIGUCHI8b389a72014-07-18 13:50:00 -0700268 ConcurrentMap<String, LinkEvent> typeMap = incomingLinks.get(port);
269 if (typeMap == null) {
270 return Collections.emptyList();
271 }
272 return toLinkImpls(typeMap.values());
Yuta HIGUCHI8f3dfa32014-06-25 00:14:25 -0700273 }
274
275 @Override
276 public Link getLink(Dpid srcDpid, PortNumber srcNumber,
277 Dpid dstDpid, PortNumber dstNumber) {
278
Yuta HIGUCHI8313f0b2014-07-09 16:36:03 -0700279 final SwitchPort dstSwitchPort = new SwitchPort(dstDpid, dstNumber);
280 Collection<Link> links = getOutgoingLinks(new SwitchPort(srcDpid, srcNumber));
281 for (Link link : links) {
282 if (link == null) {
283 continue;
284 }
Yuta HIGUCHIcd14dda2014-07-24 09:57:22 -0700285 if (link.getDstPort().getSwitchPort().equals(dstSwitchPort)) {
Yuta HIGUCHI8313f0b2014-07-09 16:36:03 -0700286 return link;
287 }
288 }
289 return null;
290 }
291
292 @Override
293 public Link getLink(Dpid srcDpid, PortNumber srcNumber,
294 Dpid dstDpid, PortNumber dstNumber,
295 String type) {
296
297 Link link = getOutgoingLink(srcDpid, srcNumber, type);
Ray Milkeyb29e6262014-04-09 16:02:14 -0700298 if (link == null) {
Ray Milkey269ffb92014-04-03 14:43:30 -0700299 return null;
Ray Milkeyb29e6262014-04-09 16:02:14 -0700300 }
301 if (!link.getDstSwitch().getDpid().equals(dstDpid)) {
Ray Milkey269ffb92014-04-03 14:43:30 -0700302 return null;
Ray Milkeyb29e6262014-04-09 16:02:14 -0700303 }
304 if (!link.getDstPort().getNumber().equals(dstNumber)) {
Ray Milkey269ffb92014-04-03 14:43:30 -0700305 return null;
Ray Milkeyb29e6262014-04-09 16:02:14 -0700306 }
Ray Milkey269ffb92014-04-03 14:43:30 -0700307 return link;
308 }
Pavlin Radoslavov7c8f69a2014-02-19 19:01:45 -0800309
Ray Milkey269ffb92014-04-03 14:43:30 -0700310 @Override
311 public Iterable<Link> getLinks() {
Yuta HIGUCHI8313f0b2014-07-09 16:36:03 -0700312 List<Link> links = new ArrayList<>();
313
Yuta HIGUCHI8b389a72014-07-18 13:50:00 -0700314 for (Map<String, LinkEvent> portLinks : outgoingLinks.values()) {
315 if (portLinks == null) {
316 continue;
317 }
318 for (LinkEvent elm : portLinks.values()) {
319 links.add(new LinkImpl(this, elm.getLinkTuple()));
320 }
Yuta HIGUCHI8313f0b2014-07-09 16:36:03 -0700321 }
322 return links;
Jonathan Hart25bd53e2014-04-30 23:44:09 -0700323 }
Toshio Koide2f570c12014-02-06 16:55:32 -0800324
Yuta HIGUCHI8b389a72014-07-18 13:50:00 -0700325 @Override
326 public Host getHostByMac(MACAddress address) {
327 HostEvent host = mac2Host.get(address);
328 if (host != null) {
329 return new HostImpl(this, address);
330 }
331 return null;
332 }
333
334 @Override
335 public Iterable<Host> getHosts() {
336 return toHostImpls(mac2Host.values());
337 }
338
339 /**
340 * Converts collection of HostEvent to collection of HostImpl.
341 *
342 * @param events collection of HostEvent
343 * @return collection of HostImpl
344 */
345 private List<Host> toHostImpls(Collection<HostEvent> events) {
346 if (events == null) {
347 return Collections.emptyList();
348 }
349 List<Host> list = new ArrayList<>(events.size());
350 for (HostEvent elm : events) {
351 list.add(new HostImpl(this, elm.getMac()));
352 }
353 return list;
354 }
355
356 @Override
357 public Collection<Host> getHosts(SwitchPort port) {
358 return toHostImpls(hosts.get(port));
359 }
360
361 @Override
362 public SwitchEvent getSwitchEvent(final Dpid dpid) {
363 return this.switches.get(dpid);
364 }
365
366 @Override
367 public PortEvent getPortEvent(final SwitchPort port) {
368 ConcurrentMap<PortNumber, PortEvent> portMap = this.ports.get(port.getDpid());
369 if (portMap != null) {
370 return portMap.get(port.getPortNumber());
371 }
372 return null;
373 }
374
375 @Override
376 public LinkEvent getLinkEvent(final LinkTuple linkId) {
377 ConcurrentMap<String, LinkEvent> links = this.outgoingLinks.get(linkId.getSrc());
378 if (links == null) {
379 return null;
380 }
381
382 // TODO Should we look for Packet link first?
383 // Not unless invariant is broken.
384
385 for (LinkEvent link : links.values()) {
386 if (link.getDst().equals(linkId.getDst())) {
387 return link;
388 }
389 }
390 return null;
391 }
392
393 @Override
394 public LinkEvent getLinkEvent(final LinkTuple linkId, final String type) {
395 ConcurrentMap<String, LinkEvent> links = this.outgoingLinks.get(linkId.getSrc());
396 if (links == null) {
397 return null;
398 }
399 return links.get(type);
400 }
401
402 @Override
403 public Collection<LinkEvent> getLinkEvents(final LinkTuple linkId) {
404 ConcurrentMap<String, LinkEvent> links = this.outgoingLinks.get(linkId.getSrc());
405 if (links == null) {
406 return Collections.emptyList();
407 }
408
409 // unless invariant is broken, this should contain at most 1 element.
410 return Collections.unmodifiableCollection(links.values());
411 }
412
413 @Override
414 public HostEvent getHostEvent(final MACAddress mac) {
415 return this.mac2Host.get(mac);
416 }
417
418 /**
419 * Puts a SwitchEvent.
420 *
421 * @param sw Switch to add. (Will be frozen if not already)
422 */
423 @GuardedBy("writeLock")
424 protected void putSwitch(SwitchEvent sw) {
425 // TODO isFrozen check once we implement CoW/lock-free
426 switches.put(sw.getDpid(), sw.freeze());
427 ports.putIfAbsent(sw.getDpid(), new ConcurrentHashMap<PortNumber, PortEvent>());
428 }
429
430 /**
431 * Removes a SwitchEvent from this snapshot.
432 * <p/>
433 * Will also remove ports, if it has not been removed already.
434 *
435 * @param dpid Switch DPID
436 */
437 @GuardedBy("writeLock")
438 protected void removeSwitch(Dpid dpid) {
439 // TODO isFrozen check once we implement CoW/lock-free
440 switches.remove(dpid);
441 ConcurrentMap<PortNumber, PortEvent> removedPorts = ports.remove(dpid);
442 if (removedPorts != null && !removedPorts.isEmpty()) {
443 log.warn("Some ports were removed as side-effect of #removeSwitch({})", dpid);
444 }
445 }
446
447 /**
448 * Puts a PortEvent.
449 *
450 * @param port Port to add. (Will be frozen if not already)
451 */
452 @GuardedBy("writeLock")
453 protected void putPort(PortEvent port) {
454
455 ConcurrentMap<PortNumber, PortEvent> portMap = ports.get(port.getDpid());
456 if (portMap == null) {
457 portMap = new ConcurrentHashMap<>();
458 ConcurrentMap<PortNumber, PortEvent> existing
459 = ports.putIfAbsent(port.getDpid(), portMap);
460 if (existing != null) {
461 // port map was added concurrently, using theirs
462 portMap = existing;
463 }
464 }
465 portMap.put(port.getPortNumber(), port.freeze());
466 }
467
468 /**
469 * Removes a PortEvent from this snapshot.
470 *
471 * @param port SwitchPort to remove
472 */
473 @GuardedBy("writeLock")
474 protected void removePort(SwitchPort port) {
475 removePort(port.getDpid(), port.getPortNumber());
476 }
477
478 /**
479 * Removes a PortEvent from this snapshot.
480 * <p/>
481 * Will also remove ports, if it has not been removed already.
482 *
483 * @param dpid Switch DPID
484 * @param number PortNumber
485 */
486 @GuardedBy("writeLock")
487 protected void removePort(Dpid dpid, PortNumber number) {
488 // TODO sanity check Host attachment point.
489 ConcurrentMap<PortNumber, PortEvent> portMap = ports.get(dpid);
490 if (portMap != null) {
491 portMap.remove(number);
492 }
493 }
494
495 /**
496 * Puts a LinkEvent.
497 *
498 * @param link LinkEvent
499 */
500 @GuardedBy("writeLock")
501 protected void putLink(LinkEvent link) {
502 // TODO Do sanity check?
503 // - There cannot be 2 links in same direction between a port pair.
504 putLinkMap(outgoingLinks, link.getSrc(), link);
505 putLinkMap(incomingLinks, link.getDst(), link);
Jonathan Hart25bd53e2014-04-30 23:44:09 -0700506 }
507
Yuta HIGUCHI8313f0b2014-07-09 16:36:03 -0700508 /**
509 * Helper method to update outgoingLinks, incomingLinks.
510 *
Yuta HIGUCHI8b389a72014-07-18 13:50:00 -0700511 * @param linkMap outgoingLinks or incomingLinks to update
512 * @param port {@code linkMap} key to update
Yuta HIGUCHI8313f0b2014-07-09 16:36:03 -0700513 * @param link Link to add
514 */
Yuta HIGUCHI8b389a72014-07-18 13:50:00 -0700515 @GuardedBy("writeLock")
516 private void putLinkMap(ConcurrentMap<SwitchPort, ConcurrentMap<String, LinkEvent>> linkMap,
517 SwitchPort port, LinkEvent link) {
518
519 ConcurrentMap<String, LinkEvent> linksOnPort = linkMap.get(port);
520 if (linksOnPort == null) {
521 linksOnPort = new ConcurrentHashMap<>(4);
522 ConcurrentMap<String, LinkEvent> existing
523 = linkMap.putIfAbsent(
Yuta HIGUCHI8313f0b2014-07-09 16:36:03 -0700524 port,
Yuta HIGUCHI8b389a72014-07-18 13:50:00 -0700525 linksOnPort);
526
527 if (existing != null) {
528 linksOnPort = existing;
529 }
Yuta HIGUCHI8313f0b2014-07-09 16:36:03 -0700530 }
Yuta HIGUCHI8b389a72014-07-18 13:50:00 -0700531 linksOnPort.put(link.getType(), link);
Yuta HIGUCHI8313f0b2014-07-09 16:36:03 -0700532 }
533
Yuta HIGUCHI8b389a72014-07-18 13:50:00 -0700534 /**
535 * Removes a LinkEvent from this snapshot.
536 *
537 * @param link Link to remove
538 * @param type type of link to remove
539 */
540 @GuardedBy("writeLock")
541 protected void removeLink(LinkTuple link, String type) {
542 ConcurrentMap<String, LinkEvent> portLinks
543 = outgoingLinks.get(link.getSrc());
Yuta HIGUCHI8313f0b2014-07-09 16:36:03 -0700544 if (portLinks != null) {
545 // no conditional update here
Yuta HIGUCHI8b389a72014-07-18 13:50:00 -0700546 portLinks.remove(type);
Yuta HIGUCHI8313f0b2014-07-09 16:36:03 -0700547 }
Yuta HIGUCHI8b389a72014-07-18 13:50:00 -0700548 portLinks
549 = incomingLinks.get(link.getDst());
Yuta HIGUCHI8313f0b2014-07-09 16:36:03 -0700550 if (portLinks != null) {
551 // no conditional update here
Yuta HIGUCHI8b389a72014-07-18 13:50:00 -0700552 portLinks.remove(type);
Yuta HIGUCHI8313f0b2014-07-09 16:36:03 -0700553 }
Ray Milkey269ffb92014-04-03 14:43:30 -0700554 }
Yuta HIGUCHI80829d12014-02-05 20:16:56 -0800555
Yuta HIGUCHI8b389a72014-07-18 13:50:00 -0700556 /**
557 * Removes a LinkEvent from this snapshot.
558 *
559 * @param link Link to remove
560 */
561 @GuardedBy("writeLock")
562 protected void removeLink(LinkTuple link) {
563 Collection<LinkEvent> links = getLinkEvents(link);
564 for (LinkEvent l : links) {
565 removeLink(link, l.getType());
Yuta HIGUCHIfa742842014-07-03 22:35:13 -0700566 }
Yuta HIGUCHI8b389a72014-07-18 13:50:00 -0700567 }
568
569 /**
570 * Puts a HostEvent.
571 * <p/>
572 * Removes attachment points for previous HostEvent and update
573 * them with new HostEvent
574 *
575 * @param host HostEvent
576 */
577 @GuardedBy("writeLock")
578 protected void putHost(HostEvent host) {
579 // Host cannot be simply put() to replace instance since it has mobility.
580 // Simply remove -> put for now.
581
582 // remove old attachment points
583 removeHost(host.getMac());
584
Yuta HIGUCHIfa742842014-07-03 22:35:13 -0700585 // add new attachment points
Yuta HIGUCHI8b389a72014-07-18 13:50:00 -0700586 for (SwitchPort port : host.getAttachmentPoints()) {
587 hosts.put(port, host);
Yuta HIGUCHIfa742842014-07-03 22:35:13 -0700588 }
Yuta HIGUCHI8b389a72014-07-18 13:50:00 -0700589 mac2Host.put(host.getMac(), host);
Ray Milkey269ffb92014-04-03 14:43:30 -0700590 }
Pavlin Radoslavov6d224ee2014-02-18 16:43:15 -0800591
Yuta HIGUCHI8b389a72014-07-18 13:50:00 -0700592 /**
593 * Removes a HostEvent from this snapshot.
594 *
595 * @param mac MACAddress of the Host to remove
596 */
597 @GuardedBy("writeLock")
598 protected void removeHost(MACAddress mac) {
599 HostEvent host = mac2Host.remove(mac);
600 if (host != null) {
601 for (SwitchPort port : host.getAttachmentPoints()) {
602 hosts.remove(port, host);
603 }
Yuta HIGUCHIfa742842014-07-03 22:35:13 -0700604 }
Ray Milkey269ffb92014-04-03 14:43:30 -0700605 }
Jonathan Hart26f291b2014-02-18 16:57:24 -0800606
Yuta HIGUCHI8b389a72014-07-18 13:50:00 -0700607
Ray Milkey269ffb92014-04-03 14:43:30 -0700608 @Override
609 public void acquireReadLock() {
610 readLock.lock();
611 }
Jonathan Hart26f291b2014-02-18 16:57:24 -0800612
Ray Milkey269ffb92014-04-03 14:43:30 -0700613 @Override
614 public void releaseReadLock() {
615 readLock.unlock();
616 }
Pavlin Radoslavov8ffb8bf2014-02-20 15:34:26 -0800617
Ray Milkey269ffb92014-04-03 14:43:30 -0700618 protected void acquireWriteLock() {
619 writeLock.lock();
620 }
Pavlin Radoslavov8ffb8bf2014-02-20 15:34:26 -0800621
Ray Milkey269ffb92014-04-03 14:43:30 -0700622 protected void releaseWriteLock() {
623 writeLock.unlock();
624 }
Yuta HIGUCHI80829d12014-02-05 20:16:56 -0800625}