blob: 5411a1b2660dd0b2bd06622fefa3d8b53a82dbf5 [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) {
Pavlin Radoslavov3d322f42014-08-18 14:58:55 -0700145 return getPort(port.getDpid(), port.getPortNumber());
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) {
Yuta HIGUCHI45ccade2014-08-18 17:09:19 -0700374 return getPortEvent(port.getDpid(), port.getPortNumber());
375 }
376
377 @Override
378 public PortEvent getPortEvent(final Dpid dpid, PortNumber portNumber) {
379 ConcurrentMap<PortNumber, PortEvent> portMap = this.ports.get(dpid);
Yuta HIGUCHI8b389a72014-07-18 13:50:00 -0700380 if (portMap != null) {
Yuta HIGUCHI45ccade2014-08-18 17:09:19 -0700381 return portMap.get(portNumber);
Yuta HIGUCHI8b389a72014-07-18 13:50:00 -0700382 }
383 return null;
384 }
385
386 @Override
Yuta HIGUCHI45ccade2014-08-18 17:09:19 -0700387 public Collection<PortEvent> getPortEvents(final Dpid dpid) {
388 ConcurrentMap<PortNumber, PortEvent> portList = ports.get(dpid);
389 if (portList == null) {
390 return Collections.emptyList();
391 }
392 return Collections.unmodifiableCollection(portList.values());
393 }
394
395 @Override
Pavlin Radoslavov054cd592014-08-07 20:57:16 -0700396 public Collection<PortEvent> getAllPortEvents() {
397 List<PortEvent> events = new LinkedList<>();
398 for (ConcurrentMap<PortNumber, PortEvent> cm : ports.values()) {
399 events.addAll(cm.values());
400 }
401 return Collections.unmodifiableCollection(events);
402 }
403
404 @Override
Yuta HIGUCHI8b389a72014-07-18 13:50:00 -0700405 public LinkEvent getLinkEvent(final LinkTuple linkId) {
406 ConcurrentMap<String, LinkEvent> links = this.outgoingLinks.get(linkId.getSrc());
407 if (links == null) {
408 return null;
409 }
410
411 // TODO Should we look for Packet link first?
412 // Not unless invariant is broken.
413
414 for (LinkEvent link : links.values()) {
415 if (link.getDst().equals(linkId.getDst())) {
416 return link;
417 }
418 }
419 return null;
420 }
421
422 @Override
423 public LinkEvent getLinkEvent(final LinkTuple linkId, final String type) {
424 ConcurrentMap<String, LinkEvent> links = this.outgoingLinks.get(linkId.getSrc());
425 if (links == null) {
426 return null;
427 }
428 return links.get(type);
429 }
430
431 @Override
432 public Collection<LinkEvent> getLinkEvents(final LinkTuple linkId) {
433 ConcurrentMap<String, LinkEvent> links = this.outgoingLinks.get(linkId.getSrc());
434 if (links == null) {
435 return Collections.emptyList();
436 }
437
438 // unless invariant is broken, this should contain at most 1 element.
439 return Collections.unmodifiableCollection(links.values());
440 }
441
442 @Override
Pavlin Radoslavov054cd592014-08-07 20:57:16 -0700443 public Collection<LinkEvent> getAllLinkEvents() {
444 List<LinkEvent> events = new LinkedList<>();
445 for (ConcurrentMap<String, LinkEvent> cm : outgoingLinks.values()) {
446 events.addAll(cm.values());
447 }
448 return Collections.unmodifiableCollection(events);
449 }
450
451 @Override
Yuta HIGUCHI8b389a72014-07-18 13:50:00 -0700452 public HostEvent getHostEvent(final MACAddress mac) {
453 return this.mac2Host.get(mac);
454 }
455
Pavlin Radoslavov054cd592014-08-07 20:57:16 -0700456 @Override
457 public Collection<HostEvent> getAllHostEvents() {
458 return Collections.unmodifiableCollection(mac2Host.values());
459 }
460
Yuta HIGUCHI8b389a72014-07-18 13:50:00 -0700461 /**
462 * Puts a SwitchEvent.
463 *
464 * @param sw Switch to add. (Will be frozen if not already)
465 */
466 @GuardedBy("writeLock")
467 protected void putSwitch(SwitchEvent sw) {
468 // TODO isFrozen check once we implement CoW/lock-free
469 switches.put(sw.getDpid(), sw.freeze());
470 ports.putIfAbsent(sw.getDpid(), new ConcurrentHashMap<PortNumber, PortEvent>());
471 }
472
473 /**
474 * Removes a SwitchEvent from this snapshot.
475 * <p/>
476 * Will also remove ports, if it has not been removed already.
477 *
478 * @param dpid Switch DPID
479 */
480 @GuardedBy("writeLock")
481 protected void removeSwitch(Dpid dpid) {
482 // TODO isFrozen check once we implement CoW/lock-free
483 switches.remove(dpid);
484 ConcurrentMap<PortNumber, PortEvent> removedPorts = ports.remove(dpid);
485 if (removedPorts != null && !removedPorts.isEmpty()) {
486 log.warn("Some ports were removed as side-effect of #removeSwitch({})", dpid);
487 }
488 }
489
490 /**
491 * Puts a PortEvent.
492 *
493 * @param port Port to add. (Will be frozen if not already)
494 */
495 @GuardedBy("writeLock")
496 protected void putPort(PortEvent port) {
497
498 ConcurrentMap<PortNumber, PortEvent> portMap = ports.get(port.getDpid());
499 if (portMap == null) {
500 portMap = new ConcurrentHashMap<>();
501 ConcurrentMap<PortNumber, PortEvent> existing
502 = ports.putIfAbsent(port.getDpid(), portMap);
503 if (existing != null) {
504 // port map was added concurrently, using theirs
505 portMap = existing;
506 }
507 }
508 portMap.put(port.getPortNumber(), port.freeze());
509 }
510
511 /**
512 * Removes a PortEvent from this snapshot.
513 *
514 * @param port SwitchPort to remove
515 */
516 @GuardedBy("writeLock")
517 protected void removePort(SwitchPort port) {
518 removePort(port.getDpid(), port.getPortNumber());
519 }
520
521 /**
522 * Removes a PortEvent from this snapshot.
523 * <p/>
524 * Will also remove ports, if it has not been removed already.
525 *
526 * @param dpid Switch DPID
527 * @param number PortNumber
528 */
529 @GuardedBy("writeLock")
530 protected void removePort(Dpid dpid, PortNumber number) {
531 // TODO sanity check Host attachment point.
532 ConcurrentMap<PortNumber, PortEvent> portMap = ports.get(dpid);
533 if (portMap != null) {
534 portMap.remove(number);
535 }
536 }
537
538 /**
539 * Puts a LinkEvent.
540 *
541 * @param link LinkEvent
542 */
543 @GuardedBy("writeLock")
544 protected void putLink(LinkEvent link) {
545 // TODO Do sanity check?
546 // - There cannot be 2 links in same direction between a port pair.
547 putLinkMap(outgoingLinks, link.getSrc(), link);
548 putLinkMap(incomingLinks, link.getDst(), link);
Jonathan Hart25bd53e2014-04-30 23:44:09 -0700549 }
550
Yuta HIGUCHI8313f0b2014-07-09 16:36:03 -0700551 /**
552 * Helper method to update outgoingLinks, incomingLinks.
553 *
Yuta HIGUCHI8b389a72014-07-18 13:50:00 -0700554 * @param linkMap outgoingLinks or incomingLinks to update
555 * @param port {@code linkMap} key to update
Yuta HIGUCHI8313f0b2014-07-09 16:36:03 -0700556 * @param link Link to add
557 */
Yuta HIGUCHI8b389a72014-07-18 13:50:00 -0700558 @GuardedBy("writeLock")
559 private void putLinkMap(ConcurrentMap<SwitchPort, ConcurrentMap<String, LinkEvent>> linkMap,
560 SwitchPort port, LinkEvent link) {
561
562 ConcurrentMap<String, LinkEvent> linksOnPort = linkMap.get(port);
563 if (linksOnPort == null) {
564 linksOnPort = new ConcurrentHashMap<>(4);
565 ConcurrentMap<String, LinkEvent> existing
566 = linkMap.putIfAbsent(
Yuta HIGUCHI8313f0b2014-07-09 16:36:03 -0700567 port,
Yuta HIGUCHI8b389a72014-07-18 13:50:00 -0700568 linksOnPort);
569
570 if (existing != null) {
571 linksOnPort = existing;
572 }
Yuta HIGUCHI8313f0b2014-07-09 16:36:03 -0700573 }
Yuta HIGUCHI8b389a72014-07-18 13:50:00 -0700574 linksOnPort.put(link.getType(), link);
Yuta HIGUCHI8313f0b2014-07-09 16:36:03 -0700575 }
576
Yuta HIGUCHI8b389a72014-07-18 13:50:00 -0700577 /**
578 * Removes a LinkEvent from this snapshot.
579 *
580 * @param link Link to remove
581 * @param type type of link to remove
582 */
583 @GuardedBy("writeLock")
584 protected void removeLink(LinkTuple link, String type) {
585 ConcurrentMap<String, LinkEvent> portLinks
586 = outgoingLinks.get(link.getSrc());
Yuta HIGUCHI8313f0b2014-07-09 16:36:03 -0700587 if (portLinks != null) {
588 // no conditional update here
Yuta HIGUCHI8b389a72014-07-18 13:50:00 -0700589 portLinks.remove(type);
Yuta HIGUCHI8313f0b2014-07-09 16:36:03 -0700590 }
Yuta HIGUCHI8b389a72014-07-18 13:50:00 -0700591 portLinks
592 = incomingLinks.get(link.getDst());
Yuta HIGUCHI8313f0b2014-07-09 16:36:03 -0700593 if (portLinks != null) {
594 // no conditional update here
Yuta HIGUCHI8b389a72014-07-18 13:50:00 -0700595 portLinks.remove(type);
Yuta HIGUCHI8313f0b2014-07-09 16:36:03 -0700596 }
Ray Milkey269ffb92014-04-03 14:43:30 -0700597 }
Yuta HIGUCHI80829d12014-02-05 20:16:56 -0800598
Yuta HIGUCHI8b389a72014-07-18 13:50:00 -0700599 /**
600 * Removes a LinkEvent from this snapshot.
601 *
602 * @param link Link to remove
603 */
604 @GuardedBy("writeLock")
605 protected void removeLink(LinkTuple link) {
606 Collection<LinkEvent> links = getLinkEvents(link);
607 for (LinkEvent l : links) {
608 removeLink(link, l.getType());
Yuta HIGUCHIfa742842014-07-03 22:35:13 -0700609 }
Yuta HIGUCHI8b389a72014-07-18 13:50:00 -0700610 }
611
612 /**
613 * Puts a HostEvent.
614 * <p/>
615 * Removes attachment points for previous HostEvent and update
616 * them with new HostEvent
617 *
618 * @param host HostEvent
619 */
620 @GuardedBy("writeLock")
621 protected void putHost(HostEvent host) {
622 // Host cannot be simply put() to replace instance since it has mobility.
623 // Simply remove -> put for now.
624
625 // remove old attachment points
626 removeHost(host.getMac());
627
Yuta HIGUCHIfa742842014-07-03 22:35:13 -0700628 // add new attachment points
Yuta HIGUCHI8b389a72014-07-18 13:50:00 -0700629 for (SwitchPort port : host.getAttachmentPoints()) {
630 hosts.put(port, host);
Yuta HIGUCHIfa742842014-07-03 22:35:13 -0700631 }
Yuta HIGUCHI8b389a72014-07-18 13:50:00 -0700632 mac2Host.put(host.getMac(), host);
Ray Milkey269ffb92014-04-03 14:43:30 -0700633 }
Pavlin Radoslavov6d224ee2014-02-18 16:43:15 -0800634
Yuta HIGUCHI8b389a72014-07-18 13:50:00 -0700635 /**
636 * Removes a HostEvent from this snapshot.
637 *
638 * @param mac MACAddress of the Host to remove
639 */
640 @GuardedBy("writeLock")
641 protected void removeHost(MACAddress mac) {
642 HostEvent host = mac2Host.remove(mac);
643 if (host != null) {
644 for (SwitchPort port : host.getAttachmentPoints()) {
645 hosts.remove(port, host);
646 }
Yuta HIGUCHIfa742842014-07-03 22:35:13 -0700647 }
Ray Milkey269ffb92014-04-03 14:43:30 -0700648 }
Jonathan Hart26f291b2014-02-18 16:57:24 -0800649
Yuta HIGUCHI8b389a72014-07-18 13:50:00 -0700650
Ray Milkey269ffb92014-04-03 14:43:30 -0700651 @Override
652 public void acquireReadLock() {
653 readLock.lock();
654 }
Jonathan Hart26f291b2014-02-18 16:57:24 -0800655
Ray Milkey269ffb92014-04-03 14:43:30 -0700656 @Override
657 public void releaseReadLock() {
658 readLock.unlock();
659 }
Pavlin Radoslavov8ffb8bf2014-02-20 15:34:26 -0800660
Ray Milkey269ffb92014-04-03 14:43:30 -0700661 protected void acquireWriteLock() {
662 writeLock.lock();
663 }
Pavlin Radoslavov8ffb8bf2014-02-20 15:34:26 -0800664
Ray Milkey269ffb92014-04-03 14:43:30 -0700665 protected void releaseWriteLock() {
666 writeLock.unlock();
667 }
Yuta HIGUCHI80829d12014-02-05 20:16:56 -0800668}