blob: d40706456158866d99a7fbd5b62b371b17ca4f99 [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 */
Yuta HIGUCHI9e6223d2014-08-26 00:01:32 -070036public class TopologyImpl implements MutableTopology, MutableInternalTopology {
Yuta HIGUCHI8b389a72014-07-18 13:50:00 -070037
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
Yuta HIGUCHI9e6223d2014-08-26 00:01:32 -070054 private final ReadWriteLock readWriteLock = new ReentrantReadWriteLock();
55 private final Lock readLock = readWriteLock.readLock();
Ray Milkey269ffb92014-04-03 14:43:30 -070056 // TODO use the write lock after refactor
Yuta HIGUCHI9e6223d2014-08-26 00:01:32 -070057 private final 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
Yuta HIGUCHI9e6223d2014-08-26 00:01:32 -0700432 public Collection<LinkEvent> getLinkEventsFrom(SwitchPort srcPort) {
433 ConcurrentMap<String, LinkEvent> links = this.outgoingLinks.get(srcPort);
434 if (links == null) {
435 return Collections.emptyList();
436 }
437 return Collections.unmodifiableCollection(links.values());
438 }
439
440 @Override
441 public Collection<LinkEvent> getLinkEventsTo(SwitchPort dstPort) {
442 ConcurrentMap<String, LinkEvent> links = this.incomingLinks.get(dstPort);
443 if (links == null) {
444 return Collections.emptyList();
445 }
446 return Collections.unmodifiableCollection(links.values());
447 }
448
449 @Override
Yuta HIGUCHI8b389a72014-07-18 13:50:00 -0700450 public Collection<LinkEvent> getLinkEvents(final LinkTuple linkId) {
451 ConcurrentMap<String, LinkEvent> links = this.outgoingLinks.get(linkId.getSrc());
452 if (links == null) {
453 return Collections.emptyList();
454 }
455
456 // unless invariant is broken, this should contain at most 1 element.
457 return Collections.unmodifiableCollection(links.values());
458 }
459
460 @Override
Pavlin Radoslavov054cd592014-08-07 20:57:16 -0700461 public Collection<LinkEvent> getAllLinkEvents() {
462 List<LinkEvent> events = new LinkedList<>();
463 for (ConcurrentMap<String, LinkEvent> cm : outgoingLinks.values()) {
464 events.addAll(cm.values());
465 }
466 return Collections.unmodifiableCollection(events);
467 }
468
469 @Override
Yuta HIGUCHI8b389a72014-07-18 13:50:00 -0700470 public HostEvent getHostEvent(final MACAddress mac) {
471 return this.mac2Host.get(mac);
472 }
473
Pavlin Radoslavov054cd592014-08-07 20:57:16 -0700474 @Override
Yuta HIGUCHI9e6223d2014-08-26 00:01:32 -0700475 public Collection<HostEvent> getHostEvents(SwitchPort port) {
476 return Collections.unmodifiableCollection(hosts.get(port));
477 }
478
479 @Override
Pavlin Radoslavov054cd592014-08-07 20:57:16 -0700480 public Collection<HostEvent> getAllHostEvents() {
481 return Collections.unmodifiableCollection(mac2Host.values());
482 }
483
Yuta HIGUCHI8b389a72014-07-18 13:50:00 -0700484 /**
485 * Puts a SwitchEvent.
486 *
487 * @param sw Switch to add. (Will be frozen if not already)
488 */
489 @GuardedBy("writeLock")
490 protected void putSwitch(SwitchEvent sw) {
491 // TODO isFrozen check once we implement CoW/lock-free
492 switches.put(sw.getDpid(), sw.freeze());
493 ports.putIfAbsent(sw.getDpid(), new ConcurrentHashMap<PortNumber, PortEvent>());
494 }
495
496 /**
497 * Removes a SwitchEvent from this snapshot.
498 * <p/>
499 * Will also remove ports, if it has not been removed already.
500 *
501 * @param dpid Switch DPID
502 */
503 @GuardedBy("writeLock")
504 protected void removeSwitch(Dpid dpid) {
505 // TODO isFrozen check once we implement CoW/lock-free
506 switches.remove(dpid);
507 ConcurrentMap<PortNumber, PortEvent> removedPorts = ports.remove(dpid);
508 if (removedPorts != null && !removedPorts.isEmpty()) {
509 log.warn("Some ports were removed as side-effect of #removeSwitch({})", dpid);
510 }
511 }
512
513 /**
514 * Puts a PortEvent.
515 *
516 * @param port Port to add. (Will be frozen if not already)
517 */
518 @GuardedBy("writeLock")
519 protected void putPort(PortEvent port) {
520
521 ConcurrentMap<PortNumber, PortEvent> portMap = ports.get(port.getDpid());
522 if (portMap == null) {
523 portMap = new ConcurrentHashMap<>();
524 ConcurrentMap<PortNumber, PortEvent> existing
525 = ports.putIfAbsent(port.getDpid(), portMap);
526 if (existing != null) {
527 // port map was added concurrently, using theirs
528 portMap = existing;
529 }
530 }
531 portMap.put(port.getPortNumber(), port.freeze());
532 }
533
534 /**
535 * Removes a PortEvent from this snapshot.
536 *
537 * @param port SwitchPort to remove
538 */
539 @GuardedBy("writeLock")
540 protected void removePort(SwitchPort port) {
541 removePort(port.getDpid(), port.getPortNumber());
542 }
543
544 /**
545 * Removes a PortEvent from this snapshot.
546 * <p/>
547 * Will also remove ports, if it has not been removed already.
548 *
549 * @param dpid Switch DPID
550 * @param number PortNumber
551 */
552 @GuardedBy("writeLock")
553 protected void removePort(Dpid dpid, PortNumber number) {
554 // TODO sanity check Host attachment point.
555 ConcurrentMap<PortNumber, PortEvent> portMap = ports.get(dpid);
556 if (portMap != null) {
557 portMap.remove(number);
558 }
559 }
560
561 /**
562 * Puts a LinkEvent.
563 *
564 * @param link LinkEvent
565 */
566 @GuardedBy("writeLock")
567 protected void putLink(LinkEvent link) {
568 // TODO Do sanity check?
569 // - There cannot be 2 links in same direction between a port pair.
570 putLinkMap(outgoingLinks, link.getSrc(), link);
571 putLinkMap(incomingLinks, link.getDst(), link);
Jonathan Hart25bd53e2014-04-30 23:44:09 -0700572 }
573
Yuta HIGUCHI8313f0b2014-07-09 16:36:03 -0700574 /**
575 * Helper method to update outgoingLinks, incomingLinks.
576 *
Yuta HIGUCHI8b389a72014-07-18 13:50:00 -0700577 * @param linkMap outgoingLinks or incomingLinks to update
578 * @param port {@code linkMap} key to update
Yuta HIGUCHI8313f0b2014-07-09 16:36:03 -0700579 * @param link Link to add
580 */
Yuta HIGUCHI8b389a72014-07-18 13:50:00 -0700581 @GuardedBy("writeLock")
582 private void putLinkMap(ConcurrentMap<SwitchPort, ConcurrentMap<String, LinkEvent>> linkMap,
583 SwitchPort port, LinkEvent link) {
584
585 ConcurrentMap<String, LinkEvent> linksOnPort = linkMap.get(port);
586 if (linksOnPort == null) {
587 linksOnPort = new ConcurrentHashMap<>(4);
588 ConcurrentMap<String, LinkEvent> existing
589 = linkMap.putIfAbsent(
Yuta HIGUCHI8313f0b2014-07-09 16:36:03 -0700590 port,
Yuta HIGUCHI8b389a72014-07-18 13:50:00 -0700591 linksOnPort);
592
593 if (existing != null) {
594 linksOnPort = existing;
595 }
Yuta HIGUCHI8313f0b2014-07-09 16:36:03 -0700596 }
Yuta HIGUCHI8b389a72014-07-18 13:50:00 -0700597 linksOnPort.put(link.getType(), link);
Yuta HIGUCHI8313f0b2014-07-09 16:36:03 -0700598 }
599
Yuta HIGUCHI8b389a72014-07-18 13:50:00 -0700600 /**
601 * Removes a LinkEvent from this snapshot.
602 *
603 * @param link Link to remove
604 * @param type type of link to remove
605 */
606 @GuardedBy("writeLock")
607 protected void removeLink(LinkTuple link, String type) {
608 ConcurrentMap<String, LinkEvent> portLinks
609 = outgoingLinks.get(link.getSrc());
Yuta HIGUCHI8313f0b2014-07-09 16:36:03 -0700610 if (portLinks != null) {
611 // no conditional update here
Yuta HIGUCHI8b389a72014-07-18 13:50:00 -0700612 portLinks.remove(type);
Yuta HIGUCHI8313f0b2014-07-09 16:36:03 -0700613 }
Yuta HIGUCHI8b389a72014-07-18 13:50:00 -0700614 portLinks
615 = incomingLinks.get(link.getDst());
Yuta HIGUCHI8313f0b2014-07-09 16:36:03 -0700616 if (portLinks != null) {
617 // no conditional update here
Yuta HIGUCHI8b389a72014-07-18 13:50:00 -0700618 portLinks.remove(type);
Yuta HIGUCHI8313f0b2014-07-09 16:36:03 -0700619 }
Ray Milkey269ffb92014-04-03 14:43:30 -0700620 }
Yuta HIGUCHI80829d12014-02-05 20:16:56 -0800621
Yuta HIGUCHI8b389a72014-07-18 13:50:00 -0700622 /**
623 * Removes a LinkEvent from this snapshot.
624 *
625 * @param link Link to remove
626 */
627 @GuardedBy("writeLock")
628 protected void removeLink(LinkTuple link) {
629 Collection<LinkEvent> links = getLinkEvents(link);
630 for (LinkEvent l : links) {
631 removeLink(link, l.getType());
Yuta HIGUCHIfa742842014-07-03 22:35:13 -0700632 }
Yuta HIGUCHI8b389a72014-07-18 13:50:00 -0700633 }
634
635 /**
636 * Puts a HostEvent.
637 * <p/>
638 * Removes attachment points for previous HostEvent and update
639 * them with new HostEvent
640 *
641 * @param host HostEvent
642 */
643 @GuardedBy("writeLock")
644 protected void putHost(HostEvent host) {
645 // Host cannot be simply put() to replace instance since it has mobility.
646 // Simply remove -> put for now.
647
648 // remove old attachment points
649 removeHost(host.getMac());
650
Yuta HIGUCHIfa742842014-07-03 22:35:13 -0700651 // add new attachment points
Yuta HIGUCHI8b389a72014-07-18 13:50:00 -0700652 for (SwitchPort port : host.getAttachmentPoints()) {
653 hosts.put(port, host);
Yuta HIGUCHIfa742842014-07-03 22:35:13 -0700654 }
Yuta HIGUCHI8b389a72014-07-18 13:50:00 -0700655 mac2Host.put(host.getMac(), host);
Ray Milkey269ffb92014-04-03 14:43:30 -0700656 }
Pavlin Radoslavov6d224ee2014-02-18 16:43:15 -0800657
Yuta HIGUCHI8b389a72014-07-18 13:50:00 -0700658 /**
659 * Removes a HostEvent from this snapshot.
660 *
661 * @param mac MACAddress of the Host to remove
662 */
663 @GuardedBy("writeLock")
664 protected void removeHost(MACAddress mac) {
665 HostEvent host = mac2Host.remove(mac);
666 if (host != null) {
667 for (SwitchPort port : host.getAttachmentPoints()) {
668 hosts.remove(port, host);
669 }
Yuta HIGUCHIfa742842014-07-03 22:35:13 -0700670 }
Ray Milkey269ffb92014-04-03 14:43:30 -0700671 }
Jonathan Hart26f291b2014-02-18 16:57:24 -0800672
Yuta HIGUCHI8b389a72014-07-18 13:50:00 -0700673
Ray Milkey269ffb92014-04-03 14:43:30 -0700674 @Override
675 public void acquireReadLock() {
676 readLock.lock();
677 }
Jonathan Hart26f291b2014-02-18 16:57:24 -0800678
Ray Milkey269ffb92014-04-03 14:43:30 -0700679 @Override
680 public void releaseReadLock() {
681 readLock.unlock();
682 }
Pavlin Radoslavov8ffb8bf2014-02-20 15:34:26 -0800683
Ray Milkey269ffb92014-04-03 14:43:30 -0700684 protected void acquireWriteLock() {
685 writeLock.lock();
686 }
Pavlin Radoslavov8ffb8bf2014-02-20 15:34:26 -0800687
Ray Milkey269ffb92014-04-03 14:43:30 -0700688 protected void releaseWriteLock() {
689 writeLock.unlock();
690 }
Yuta HIGUCHI80829d12014-02-05 20:16:56 -0800691}