blob: a0248b78edcd979b9534fa97ec9a5250fee0c877 [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;
Pavlin Radoslavov054cd592014-08-07 20:57:16 -07007import java.util.LinkedList;
Yuta HIGUCHI8313f0b2014-07-09 16:36:03 -07008import java.util.List;
9import java.util.Map;
Yuta HIGUCHI8b389a72014-07-18 13:50:00 -070010import java.util.Map.Entry;
Yuta HIGUCHI80829d12014-02-05 20:16:56 -080011import java.util.concurrent.ConcurrentHashMap;
12import java.util.concurrent.ConcurrentMap;
Jonathan Hart26f291b2014-02-18 16:57:24 -080013import java.util.concurrent.locks.Lock;
14import java.util.concurrent.locks.ReadWriteLock;
15import java.util.concurrent.locks.ReentrantReadWriteLock;
Yuta HIGUCHI80829d12014-02-05 20:16:56 -080016
Yuta HIGUCHI8313f0b2014-07-09 16:36:03 -070017import javax.annotation.concurrent.GuardedBy;
18
Yuta HIGUCHI80829d12014-02-05 20:16:56 -080019import net.floodlightcontroller.util.MACAddress;
Yuta HIGUCHI8f3dfa32014-06-25 00:14:25 -070020import net.onrc.onos.core.util.Dpid;
Yuta HIGUCHI8b389a72014-07-18 13:50:00 -070021import net.onrc.onos.core.util.LinkTuple;
Yuta HIGUCHI8f3dfa32014-06-25 00:14:25 -070022import net.onrc.onos.core.util.PortNumber;
Jonathan Hart25bd53e2014-04-30 23:44:09 -070023import net.onrc.onos.core.util.SwitchPort;
Yuta HIGUCHI80829d12014-02-05 20:16:56 -080024
25import org.slf4j.Logger;
26import org.slf4j.LoggerFactory;
27
Yuta HIGUCHIfa742842014-07-03 22:35:13 -070028import com.google.common.collect.HashMultimap;
29import com.google.common.collect.Multimap;
30import com.google.common.collect.Multimaps;
31
Yuta HIGUCHI8b389a72014-07-18 13:50:00 -070032
33/**
34 * Class to represent an instance of Topology Snapshot.
35 */
36public class TopologyImpl implements Topology, TopologyInternal {
37
Jonathan Harte37e4e22014-05-13 19:12:02 -070038 private static final Logger log = LoggerFactory.getLogger(TopologyImpl.class);
Yuta HIGUCHI80829d12014-02-05 20:16:56 -080039
Yuta HIGUCHI8b389a72014-07-18 13:50:00 -070040 // TODO Revisit Map types after implementing CoW/lock-free
41
Ray Milkey269ffb92014-04-03 14:43:30 -070042 // DPID -> Switch
Yuta HIGUCHI8b389a72014-07-18 13:50:00 -070043 private final ConcurrentMap<Dpid, SwitchEvent> switches;
44 private final ConcurrentMap<Dpid, ConcurrentMap<PortNumber, PortEvent>> ports;
Yuta HIGUCHIfa742842014-07-03 22:35:13 -070045
Yuta HIGUCHIbfc77f02014-07-14 22:50:25 -070046 // Index from Port to Host
Yuta HIGUCHI8b389a72014-07-18 13:50:00 -070047 private final Multimap<SwitchPort, HostEvent> hosts;
48 private final ConcurrentMap<MACAddress, HostEvent> mac2Host;
Jonathan Hart25bd53e2014-04-30 23:44:09 -070049
Yuta HIGUCHI8313f0b2014-07-09 16:36:03 -070050 // SwitchPort -> (type -> Link)
Yuta HIGUCHI8b389a72014-07-18 13:50:00 -070051 private final ConcurrentMap<SwitchPort, ConcurrentMap<String, LinkEvent>> outgoingLinks;
52 private final ConcurrentMap<SwitchPort, ConcurrentMap<String, LinkEvent>> incomingLinks;
Yuta HIGUCHI5d2d8d42014-02-20 22:22:53 -080053
Ray Milkey269ffb92014-04-03 14:43:30 -070054 private ReadWriteLock readWriteLock = new ReentrantReadWriteLock();
55 private Lock readLock = readWriteLock.readLock();
56 // TODO use the write lock after refactor
57 private Lock writeLock = readWriteLock.writeLock();
Yuta HIGUCHI80829d12014-02-05 20:16:56 -080058
Yuta HIGUCHI8b389a72014-07-18 13:50:00 -070059 /**
60 * Create an empty Topology.
61 */
Jonathan Harte37e4e22014-05-13 19:12:02 -070062 public TopologyImpl() {
Ray Milkey269ffb92014-04-03 14:43:30 -070063 // TODO: Does these object need to be stored in Concurrent Collection?
64 switches = new ConcurrentHashMap<>();
Yuta HIGUCHIfa742842014-07-03 22:35:13 -070065 ports = new ConcurrentHashMap<>();
Yuta HIGUCHIbfc77f02014-07-14 22:50:25 -070066 hosts = Multimaps.synchronizedMultimap(
Yuta HIGUCHI8b389a72014-07-18 13:50:00 -070067 HashMultimap.<SwitchPort, HostEvent>create());
Yuta HIGUCHIbfc77f02014-07-14 22:50:25 -070068 mac2Host = new ConcurrentHashMap<>();
Jonathan Hart25bd53e2014-04-30 23:44:09 -070069 outgoingLinks = new ConcurrentHashMap<>();
70 incomingLinks = new ConcurrentHashMap<>();
Ray Milkey269ffb92014-04-03 14:43:30 -070071 }
Yuta HIGUCHI80829d12014-02-05 20:16:56 -080072
Yuta HIGUCHI8b389a72014-07-18 13:50:00 -070073 /**
74 * Create a shallow copy of given Topology.
75 *
76 * @param original Topology
77 */
78 public TopologyImpl(TopologyImpl original) {
79 original.acquireReadLock();
80 try {
81 this.switches = new ConcurrentHashMap<>(original.switches);
82
83 // shallow copy Map in Map
84 this.ports = new ConcurrentHashMap<>(original.ports.size());
85 for (Entry<Dpid, ConcurrentMap<PortNumber, PortEvent>> entry
86 : original.ports.entrySet()) {
87 this.ports.put(entry.getKey(), new ConcurrentHashMap<>(entry.getValue()));
88 }
89
90 this.hosts = Multimaps.synchronizedMultimap(
91 HashMultimap.<SwitchPort, HostEvent>create(original.hosts));
92 this.mac2Host = new ConcurrentHashMap<>(original.mac2Host);
93
94 // shallow copy Map in Map
95 this.outgoingLinks = new ConcurrentHashMap<>(original.outgoingLinks.size());
96 for (Entry<SwitchPort, ConcurrentMap<String, LinkEvent>> entry
97 : original.outgoingLinks.entrySet()) {
98 this.outgoingLinks.put(entry.getKey(), new ConcurrentHashMap<>(entry.getValue()));
99 }
100
101 // shallow copy Map in Map
102 this.incomingLinks = new ConcurrentHashMap<>(original.incomingLinks.size());
103 for (Entry<SwitchPort, ConcurrentMap<String, LinkEvent>> entry
104 : original.incomingLinks.entrySet()) {
105 this.incomingLinks.put(entry.getKey(), new ConcurrentHashMap<>(entry.getValue()));
106 }
107 } finally {
108 original.releaseReadLock();
109 }
110 }
111
Ray Milkey269ffb92014-04-03 14:43:30 -0700112 @Override
Yuta HIGUCHI8f3dfa32014-06-25 00:14:25 -0700113 public Switch getSwitch(Dpid dpid) {
Yuta HIGUCHI8b389a72014-07-18 13:50:00 -0700114 final SwitchEvent sw = switches.get(dpid);
115 if (sw != null) {
116 return new SwitchImpl(this, dpid);
117 } else {
118 return null;
Yuta HIGUCHIfa742842014-07-03 22:35:13 -0700119 }
Ray Milkey269ffb92014-04-03 14:43:30 -0700120 }
Pavlin Radoslavov6d224ee2014-02-18 16:43:15 -0800121
Ray Milkey269ffb92014-04-03 14:43:30 -0700122 @Override
123 public Iterable<Switch> getSwitches() {
Yuta HIGUCHI8b389a72014-07-18 13:50:00 -0700124 List<Switch> list = new ArrayList<>(switches.size());
125 for (SwitchEvent elm : switches.values()) {
126 list.add(new SwitchImpl(this, elm.getDpid()));
127 }
128 return list;
Ray Milkey269ffb92014-04-03 14:43:30 -0700129 }
Yuta HIGUCHI80829d12014-02-05 20:16:56 -0800130
Ray Milkey269ffb92014-04-03 14:43:30 -0700131 @Override
Yuta HIGUCHI8f3dfa32014-06-25 00:14:25 -0700132 public Port getPort(Dpid dpid, PortNumber number) {
Yuta HIGUCHI8b389a72014-07-18 13:50:00 -0700133 ConcurrentMap<PortNumber, PortEvent> portMap = ports.get(dpid);
Yuta HIGUCHIfa742842014-07-03 22:35:13 -0700134 if (portMap != null) {
Yuta HIGUCHI8b389a72014-07-18 13:50:00 -0700135 final PortEvent port = portMap.get(number);
136 if (port != null) {
137 return new PortImpl(this, port.getSwitchPort());
138 }
Ray Milkey269ffb92014-04-03 14:43:30 -0700139 }
140 return null;
141 }
Pavlin Radoslavov06df22a2014-02-18 19:16:27 -0800142
Ray Milkey269ffb92014-04-03 14:43:30 -0700143 @Override
Yuta HIGUCHI8f3dfa32014-06-25 00:14:25 -0700144 public Port getPort(SwitchPort port) {
145 return getPort(port.dpid(), port.port());
Jonathan Hart25bd53e2014-04-30 23:44:09 -0700146 }
147
148 @Override
Yuta HIGUCHIfa742842014-07-03 22:35:13 -0700149 public Collection<Port> getPorts(Dpid dpid) {
Yuta HIGUCHI8b389a72014-07-18 13:50:00 -0700150 ConcurrentMap<PortNumber, PortEvent> portMap = ports.get(dpid);
Yuta HIGUCHIfa742842014-07-03 22:35:13 -0700151 if (portMap == null) {
152 return Collections.emptyList();
153 }
Yuta HIGUCHI8b389a72014-07-18 13:50:00 -0700154 List<Port> list = new ArrayList<>(portMap.size());
155 for (PortEvent elm : portMap.values()) {
156 list.add(new PortImpl(this, elm.getSwitchPort()));
157 }
158 return list;
Yuta HIGUCHIfa742842014-07-03 22:35:13 -0700159 }
160
161 @Override
Yuta HIGUCHI8f3dfa32014-06-25 00:14:25 -0700162 public Link getOutgoingLink(Dpid dpid, PortNumber number) {
Yuta HIGUCHI8313f0b2014-07-09 16:36:03 -0700163 return getOutgoingLink(new SwitchPort(dpid, number));
Ray Milkey269ffb92014-04-03 14:43:30 -0700164 }
Pavlin Radoslavov7c8f69a2014-02-19 19:01:45 -0800165
Ray Milkey269ffb92014-04-03 14:43:30 -0700166 @Override
Yuta HIGUCHI8f3dfa32014-06-25 00:14:25 -0700167 public Link getOutgoingLink(SwitchPort port) {
Yuta HIGUCHI8b389a72014-07-18 13:50:00 -0700168 Map<String, LinkEvent> links = outgoingLinks.get(port);
Yuta HIGUCHI8313f0b2014-07-09 16:36:03 -0700169 return getPacketLinkIfExists(links);
170 }
171
172 // TODO remove when we no longer need packet fall back behavior
173 /**
Yuta HIGUCHI8b389a72014-07-18 13:50:00 -0700174 * Gets the "packet" link if such exists,
175 * if not return whichever link is found first.
Yuta HIGUCHI8313f0b2014-07-09 16:36:03 -0700176 *
177 * @param links Collection of links to search from
178 * @return Link instance found or null if no link exists
179 */
Yuta HIGUCHI8b389a72014-07-18 13:50:00 -0700180 private Link getPacketLinkIfExists(Map<String, LinkEvent> links) {
Yuta HIGUCHI8313f0b2014-07-09 16:36:03 -0700181
182 if (links == null) {
183 return null;
184 }
185
Yuta HIGUCHI8b389a72014-07-18 13:50:00 -0700186 LinkEvent link = links.get(TopologyElement.TYPE_PACKET_LAYER);
Yuta HIGUCHI8313f0b2014-07-09 16:36:03 -0700187 if (link != null) {
188 // return packet link
Yuta HIGUCHI8b389a72014-07-18 13:50:00 -0700189 return new LinkImpl(this, link.getLinkTuple());
Yuta HIGUCHI8313f0b2014-07-09 16:36:03 -0700190 } else {
191 // return whatever found
Yuta HIGUCHI8b389a72014-07-18 13:50:00 -0700192 Iterator<LinkEvent> it = links.values().iterator();
Yuta HIGUCHI8313f0b2014-07-09 16:36:03 -0700193 if (it.hasNext()) {
Yuta HIGUCHI8b389a72014-07-18 13:50:00 -0700194 return new LinkImpl(this, it.next().getLinkTuple());
Yuta HIGUCHI8313f0b2014-07-09 16:36:03 -0700195 }
196 }
197 return null;
198 }
199
200 @Override
201 public Link getOutgoingLink(Dpid dpid, PortNumber number, String type) {
202 return getOutgoingLink(new SwitchPort(dpid, number), type);
203 }
204
205 @Override
206 public Link getOutgoingLink(SwitchPort port, String type) {
Yuta HIGUCHI8b389a72014-07-18 13:50:00 -0700207 Map<String, LinkEvent> links = outgoingLinks.get(port);
208 final LinkEvent link = links.get(type);
209 if (link != null) {
210 return new LinkImpl(this, link.getLinkTuple());
211 }
212 return null;
Yuta HIGUCHI8313f0b2014-07-09 16:36:03 -0700213 }
214
215 @Override
216 public Collection<Link> getOutgoingLinks(SwitchPort port) {
Yuta HIGUCHI8b389a72014-07-18 13:50:00 -0700217 ConcurrentMap<String, LinkEvent> typeMap = outgoingLinks.get(port);
218 if (typeMap == null) {
219 return Collections.emptyList();
220 }
221 return toLinkImpls(typeMap.values());
222 }
223
224 /**
225 * Converts collection of LinkEvent to collection of LinkImpls.
226 *
227 * @param links collection of LinkEvent
228 * @return collection of LinkImpls
229 */
230 private Collection<Link> toLinkImpls(final Collection<LinkEvent> links) {
231 if (links == null) {
232 return Collections.emptyList();
233 }
234 List<Link> list = new ArrayList<>(links.size());
235 for (LinkEvent elm : links) {
236 list.add(new LinkImpl(this, elm.getLinkTuple()));
237 }
238 return list;
Yuta HIGUCHI8f3dfa32014-06-25 00:14:25 -0700239 }
240
241 @Override
242 public Link getIncomingLink(Dpid dpid, PortNumber number) {
Yuta HIGUCHI8313f0b2014-07-09 16:36:03 -0700243 return getIncomingLink(new SwitchPort(dpid, number));
Yuta HIGUCHI8f3dfa32014-06-25 00:14:25 -0700244 }
245
246 @Override
247 public Link getIncomingLink(SwitchPort port) {
Yuta HIGUCHI8b389a72014-07-18 13:50:00 -0700248 Map<String, LinkEvent> links = incomingLinks.get(port);
Yuta HIGUCHI8313f0b2014-07-09 16:36:03 -0700249 return getPacketLinkIfExists(links);
250 }
251
252 @Override
253 public Link getIncomingLink(Dpid dpid, PortNumber number, String type) {
254 return getIncomingLink(new SwitchPort(dpid, number), type);
255 }
256
257 @Override
258 public Link getIncomingLink(SwitchPort port, String type) {
Yuta HIGUCHI8b389a72014-07-18 13:50:00 -0700259 Map<String, LinkEvent> links = incomingLinks.get(port);
260 final LinkEvent link = links.get(type);
261 if (link != null) {
262 return new LinkImpl(this, link.getLinkTuple());
263 }
264 return null;
Yuta HIGUCHI8313f0b2014-07-09 16:36:03 -0700265 }
266
267 @Override
268 public Collection<Link> getIncomingLinks(SwitchPort port) {
Yuta HIGUCHI8b389a72014-07-18 13:50:00 -0700269 ConcurrentMap<String, LinkEvent> typeMap = incomingLinks.get(port);
270 if (typeMap == null) {
271 return Collections.emptyList();
272 }
273 return toLinkImpls(typeMap.values());
Yuta HIGUCHI8f3dfa32014-06-25 00:14:25 -0700274 }
275
276 @Override
277 public Link getLink(Dpid srcDpid, PortNumber srcNumber,
278 Dpid dstDpid, PortNumber dstNumber) {
279
Yuta HIGUCHI8313f0b2014-07-09 16:36:03 -0700280 final SwitchPort dstSwitchPort = new SwitchPort(dstDpid, dstNumber);
281 Collection<Link> links = getOutgoingLinks(new SwitchPort(srcDpid, srcNumber));
282 for (Link link : links) {
283 if (link == null) {
284 continue;
285 }
Yuta HIGUCHIcd14dda2014-07-24 09:57:22 -0700286 if (link.getDstPort().getSwitchPort().equals(dstSwitchPort)) {
Yuta HIGUCHI8313f0b2014-07-09 16:36:03 -0700287 return link;
288 }
289 }
290 return null;
291 }
292
293 @Override
294 public Link getLink(Dpid srcDpid, PortNumber srcNumber,
295 Dpid dstDpid, PortNumber dstNumber,
296 String type) {
297
298 Link link = getOutgoingLink(srcDpid, srcNumber, type);
Ray Milkeyb29e6262014-04-09 16:02:14 -0700299 if (link == null) {
Ray Milkey269ffb92014-04-03 14:43:30 -0700300 return null;
Ray Milkeyb29e6262014-04-09 16:02:14 -0700301 }
302 if (!link.getDstSwitch().getDpid().equals(dstDpid)) {
Ray Milkey269ffb92014-04-03 14:43:30 -0700303 return null;
Ray Milkeyb29e6262014-04-09 16:02:14 -0700304 }
305 if (!link.getDstPort().getNumber().equals(dstNumber)) {
Ray Milkey269ffb92014-04-03 14:43:30 -0700306 return null;
Ray Milkeyb29e6262014-04-09 16:02:14 -0700307 }
Ray Milkey269ffb92014-04-03 14:43:30 -0700308 return link;
309 }
Pavlin Radoslavov7c8f69a2014-02-19 19:01:45 -0800310
Ray Milkey269ffb92014-04-03 14:43:30 -0700311 @Override
312 public Iterable<Link> getLinks() {
Yuta HIGUCHI8313f0b2014-07-09 16:36:03 -0700313 List<Link> links = new ArrayList<>();
314
Yuta HIGUCHI8b389a72014-07-18 13:50:00 -0700315 for (Map<String, LinkEvent> portLinks : outgoingLinks.values()) {
316 if (portLinks == null) {
317 continue;
318 }
319 for (LinkEvent elm : portLinks.values()) {
320 links.add(new LinkImpl(this, elm.getLinkTuple()));
321 }
Yuta HIGUCHI8313f0b2014-07-09 16:36:03 -0700322 }
323 return links;
Jonathan Hart25bd53e2014-04-30 23:44:09 -0700324 }
Toshio Koide2f570c12014-02-06 16:55:32 -0800325
Yuta HIGUCHI8b389a72014-07-18 13:50:00 -0700326 @Override
327 public Host getHostByMac(MACAddress address) {
328 HostEvent host = mac2Host.get(address);
329 if (host != null) {
330 return new HostImpl(this, address);
331 }
332 return null;
333 }
334
335 @Override
336 public Iterable<Host> getHosts() {
337 return toHostImpls(mac2Host.values());
338 }
339
340 /**
341 * Converts collection of HostEvent to collection of HostImpl.
342 *
343 * @param events collection of HostEvent
344 * @return collection of HostImpl
345 */
346 private List<Host> toHostImpls(Collection<HostEvent> events) {
347 if (events == null) {
348 return Collections.emptyList();
349 }
350 List<Host> list = new ArrayList<>(events.size());
351 for (HostEvent elm : events) {
352 list.add(new HostImpl(this, elm.getMac()));
353 }
354 return list;
355 }
356
357 @Override
358 public Collection<Host> getHosts(SwitchPort port) {
359 return toHostImpls(hosts.get(port));
360 }
361
362 @Override
363 public SwitchEvent getSwitchEvent(final Dpid dpid) {
364 return this.switches.get(dpid);
365 }
366
367 @Override
Pavlin Radoslavov054cd592014-08-07 20:57:16 -0700368 public Collection<SwitchEvent> getAllSwitchEvents() {
369 return Collections.unmodifiableCollection(switches.values());
370 }
371
372 @Override
Yuta HIGUCHI8b389a72014-07-18 13:50:00 -0700373 public PortEvent getPortEvent(final SwitchPort port) {
374 ConcurrentMap<PortNumber, PortEvent> portMap = this.ports.get(port.getDpid());
375 if (portMap != null) {
376 return portMap.get(port.getPortNumber());
377 }
378 return null;
379 }
380
381 @Override
Pavlin Radoslavov054cd592014-08-07 20:57:16 -0700382 public Collection<PortEvent> getAllPortEvents() {
383 List<PortEvent> events = new LinkedList<>();
384 for (ConcurrentMap<PortNumber, PortEvent> cm : ports.values()) {
385 events.addAll(cm.values());
386 }
387 return Collections.unmodifiableCollection(events);
388 }
389
390 @Override
Yuta HIGUCHI8b389a72014-07-18 13:50:00 -0700391 public LinkEvent getLinkEvent(final LinkTuple linkId) {
392 ConcurrentMap<String, LinkEvent> links = this.outgoingLinks.get(linkId.getSrc());
393 if (links == null) {
394 return null;
395 }
396
397 // TODO Should we look for Packet link first?
398 // Not unless invariant is broken.
399
400 for (LinkEvent link : links.values()) {
401 if (link.getDst().equals(linkId.getDst())) {
402 return link;
403 }
404 }
405 return null;
406 }
407
408 @Override
409 public LinkEvent getLinkEvent(final LinkTuple linkId, final String type) {
410 ConcurrentMap<String, LinkEvent> links = this.outgoingLinks.get(linkId.getSrc());
411 if (links == null) {
412 return null;
413 }
414 return links.get(type);
415 }
416
417 @Override
418 public Collection<LinkEvent> getLinkEvents(final LinkTuple linkId) {
419 ConcurrentMap<String, LinkEvent> links = this.outgoingLinks.get(linkId.getSrc());
420 if (links == null) {
421 return Collections.emptyList();
422 }
423
424 // unless invariant is broken, this should contain at most 1 element.
425 return Collections.unmodifiableCollection(links.values());
426 }
427
428 @Override
Pavlin Radoslavov054cd592014-08-07 20:57:16 -0700429 public Collection<LinkEvent> getAllLinkEvents() {
430 List<LinkEvent> events = new LinkedList<>();
431 for (ConcurrentMap<String, LinkEvent> cm : outgoingLinks.values()) {
432 events.addAll(cm.values());
433 }
434 return Collections.unmodifiableCollection(events);
435 }
436
437 @Override
Yuta HIGUCHI8b389a72014-07-18 13:50:00 -0700438 public HostEvent getHostEvent(final MACAddress mac) {
439 return this.mac2Host.get(mac);
440 }
441
Pavlin Radoslavov054cd592014-08-07 20:57:16 -0700442 @Override
443 public Collection<HostEvent> getAllHostEvents() {
444 return Collections.unmodifiableCollection(mac2Host.values());
445 }
446
Yuta HIGUCHI8b389a72014-07-18 13:50:00 -0700447 /**
448 * Puts a SwitchEvent.
449 *
450 * @param sw Switch to add. (Will be frozen if not already)
451 */
452 @GuardedBy("writeLock")
453 protected void putSwitch(SwitchEvent sw) {
454 // TODO isFrozen check once we implement CoW/lock-free
455 switches.put(sw.getDpid(), sw.freeze());
456 ports.putIfAbsent(sw.getDpid(), new ConcurrentHashMap<PortNumber, PortEvent>());
457 }
458
459 /**
460 * Removes a SwitchEvent from this snapshot.
461 * <p/>
462 * Will also remove ports, if it has not been removed already.
463 *
464 * @param dpid Switch DPID
465 */
466 @GuardedBy("writeLock")
467 protected void removeSwitch(Dpid dpid) {
468 // TODO isFrozen check once we implement CoW/lock-free
469 switches.remove(dpid);
470 ConcurrentMap<PortNumber, PortEvent> removedPorts = ports.remove(dpid);
471 if (removedPorts != null && !removedPorts.isEmpty()) {
472 log.warn("Some ports were removed as side-effect of #removeSwitch({})", dpid);
473 }
474 }
475
476 /**
477 * Puts a PortEvent.
478 *
479 * @param port Port to add. (Will be frozen if not already)
480 */
481 @GuardedBy("writeLock")
482 protected void putPort(PortEvent port) {
483
484 ConcurrentMap<PortNumber, PortEvent> portMap = ports.get(port.getDpid());
485 if (portMap == null) {
486 portMap = new ConcurrentHashMap<>();
487 ConcurrentMap<PortNumber, PortEvent> existing
488 = ports.putIfAbsent(port.getDpid(), portMap);
489 if (existing != null) {
490 // port map was added concurrently, using theirs
491 portMap = existing;
492 }
493 }
494 portMap.put(port.getPortNumber(), port.freeze());
495 }
496
497 /**
498 * Removes a PortEvent from this snapshot.
499 *
500 * @param port SwitchPort to remove
501 */
502 @GuardedBy("writeLock")
503 protected void removePort(SwitchPort port) {
504 removePort(port.getDpid(), port.getPortNumber());
505 }
506
507 /**
508 * Removes a PortEvent from this snapshot.
509 * <p/>
510 * Will also remove ports, if it has not been removed already.
511 *
512 * @param dpid Switch DPID
513 * @param number PortNumber
514 */
515 @GuardedBy("writeLock")
516 protected void removePort(Dpid dpid, PortNumber number) {
517 // TODO sanity check Host attachment point.
518 ConcurrentMap<PortNumber, PortEvent> portMap = ports.get(dpid);
519 if (portMap != null) {
520 portMap.remove(number);
521 }
522 }
523
524 /**
525 * Puts a LinkEvent.
526 *
527 * @param link LinkEvent
528 */
529 @GuardedBy("writeLock")
530 protected void putLink(LinkEvent link) {
531 // TODO Do sanity check?
532 // - There cannot be 2 links in same direction between a port pair.
533 putLinkMap(outgoingLinks, link.getSrc(), link);
534 putLinkMap(incomingLinks, link.getDst(), link);
Jonathan Hart25bd53e2014-04-30 23:44:09 -0700535 }
536
Yuta HIGUCHI8313f0b2014-07-09 16:36:03 -0700537 /**
538 * Helper method to update outgoingLinks, incomingLinks.
539 *
Yuta HIGUCHI8b389a72014-07-18 13:50:00 -0700540 * @param linkMap outgoingLinks or incomingLinks to update
541 * @param port {@code linkMap} key to update
Yuta HIGUCHI8313f0b2014-07-09 16:36:03 -0700542 * @param link Link to add
543 */
Yuta HIGUCHI8b389a72014-07-18 13:50:00 -0700544 @GuardedBy("writeLock")
545 private void putLinkMap(ConcurrentMap<SwitchPort, ConcurrentMap<String, LinkEvent>> linkMap,
546 SwitchPort port, LinkEvent link) {
547
548 ConcurrentMap<String, LinkEvent> linksOnPort = linkMap.get(port);
549 if (linksOnPort == null) {
550 linksOnPort = new ConcurrentHashMap<>(4);
551 ConcurrentMap<String, LinkEvent> existing
552 = linkMap.putIfAbsent(
Yuta HIGUCHI8313f0b2014-07-09 16:36:03 -0700553 port,
Yuta HIGUCHI8b389a72014-07-18 13:50:00 -0700554 linksOnPort);
555
556 if (existing != null) {
557 linksOnPort = existing;
558 }
Yuta HIGUCHI8313f0b2014-07-09 16:36:03 -0700559 }
Yuta HIGUCHI8b389a72014-07-18 13:50:00 -0700560 linksOnPort.put(link.getType(), link);
Yuta HIGUCHI8313f0b2014-07-09 16:36:03 -0700561 }
562
Yuta HIGUCHI8b389a72014-07-18 13:50:00 -0700563 /**
564 * Removes a LinkEvent from this snapshot.
565 *
566 * @param link Link to remove
567 * @param type type of link to remove
568 */
569 @GuardedBy("writeLock")
570 protected void removeLink(LinkTuple link, String type) {
571 ConcurrentMap<String, LinkEvent> portLinks
572 = outgoingLinks.get(link.getSrc());
Yuta HIGUCHI8313f0b2014-07-09 16:36:03 -0700573 if (portLinks != null) {
574 // no conditional update here
Yuta HIGUCHI8b389a72014-07-18 13:50:00 -0700575 portLinks.remove(type);
Yuta HIGUCHI8313f0b2014-07-09 16:36:03 -0700576 }
Yuta HIGUCHI8b389a72014-07-18 13:50:00 -0700577 portLinks
578 = incomingLinks.get(link.getDst());
Yuta HIGUCHI8313f0b2014-07-09 16:36:03 -0700579 if (portLinks != null) {
580 // no conditional update here
Yuta HIGUCHI8b389a72014-07-18 13:50:00 -0700581 portLinks.remove(type);
Yuta HIGUCHI8313f0b2014-07-09 16:36:03 -0700582 }
Ray Milkey269ffb92014-04-03 14:43:30 -0700583 }
Yuta HIGUCHI80829d12014-02-05 20:16:56 -0800584
Yuta HIGUCHI8b389a72014-07-18 13:50:00 -0700585 /**
586 * Removes a LinkEvent from this snapshot.
587 *
588 * @param link Link to remove
589 */
590 @GuardedBy("writeLock")
591 protected void removeLink(LinkTuple link) {
592 Collection<LinkEvent> links = getLinkEvents(link);
593 for (LinkEvent l : links) {
594 removeLink(link, l.getType());
Yuta HIGUCHIfa742842014-07-03 22:35:13 -0700595 }
Yuta HIGUCHI8b389a72014-07-18 13:50:00 -0700596 }
597
598 /**
599 * Puts a HostEvent.
600 * <p/>
601 * Removes attachment points for previous HostEvent and update
602 * them with new HostEvent
603 *
604 * @param host HostEvent
605 */
606 @GuardedBy("writeLock")
607 protected void putHost(HostEvent host) {
608 // Host cannot be simply put() to replace instance since it has mobility.
609 // Simply remove -> put for now.
610
611 // remove old attachment points
612 removeHost(host.getMac());
613
Yuta HIGUCHIfa742842014-07-03 22:35:13 -0700614 // add new attachment points
Yuta HIGUCHI8b389a72014-07-18 13:50:00 -0700615 for (SwitchPort port : host.getAttachmentPoints()) {
616 hosts.put(port, host);
Yuta HIGUCHIfa742842014-07-03 22:35:13 -0700617 }
Yuta HIGUCHI8b389a72014-07-18 13:50:00 -0700618 mac2Host.put(host.getMac(), host);
Ray Milkey269ffb92014-04-03 14:43:30 -0700619 }
Pavlin Radoslavov6d224ee2014-02-18 16:43:15 -0800620
Yuta HIGUCHI8b389a72014-07-18 13:50:00 -0700621 /**
622 * Removes a HostEvent from this snapshot.
623 *
624 * @param mac MACAddress of the Host to remove
625 */
626 @GuardedBy("writeLock")
627 protected void removeHost(MACAddress mac) {
628 HostEvent host = mac2Host.remove(mac);
629 if (host != null) {
630 for (SwitchPort port : host.getAttachmentPoints()) {
631 hosts.remove(port, host);
632 }
Yuta HIGUCHIfa742842014-07-03 22:35:13 -0700633 }
Ray Milkey269ffb92014-04-03 14:43:30 -0700634 }
Jonathan Hart26f291b2014-02-18 16:57:24 -0800635
Yuta HIGUCHI8b389a72014-07-18 13:50:00 -0700636
Ray Milkey269ffb92014-04-03 14:43:30 -0700637 @Override
638 public void acquireReadLock() {
639 readLock.lock();
640 }
Jonathan Hart26f291b2014-02-18 16:57:24 -0800641
Ray Milkey269ffb92014-04-03 14:43:30 -0700642 @Override
643 public void releaseReadLock() {
644 readLock.unlock();
645 }
Pavlin Radoslavov8ffb8bf2014-02-20 15:34:26 -0800646
Ray Milkey269ffb92014-04-03 14:43:30 -0700647 protected void acquireWriteLock() {
648 writeLock.lock();
649 }
Pavlin Radoslavov8ffb8bf2014-02-20 15:34:26 -0800650
Ray Milkey269ffb92014-04-03 14:43:30 -0700651 protected void releaseWriteLock() {
652 writeLock.unlock();
653 }
Yuta HIGUCHI80829d12014-02-05 20:16:56 -0800654}