blob: 1dc14c61eb2dcf7445c91562b61d10d169edebc2 [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 HIGUCHIab9dc7b2014-08-26 22:53:13 -07003import static com.google.common.base.Preconditions.checkNotNull;
4
Yuta HIGUCHI8313f0b2014-07-09 16:36:03 -07005import java.util.ArrayList;
Yuta HIGUCHIfa742842014-07-03 22:35:13 -07006import java.util.Collection;
Yuta HIGUCHI80829d12014-02-05 20:16:56 -08007import java.util.Collections;
Yuta HIGUCHIab9dc7b2014-08-26 22:53:13 -07008import java.util.HashMap;
Yuta HIGUCHI8313f0b2014-07-09 16:36:03 -07009import java.util.Iterator;
Pavlin Radoslavov054cd592014-08-07 20:57:16 -070010import java.util.LinkedList;
Yuta HIGUCHI8313f0b2014-07-09 16:36:03 -070011import java.util.List;
12import java.util.Map;
Yuta HIGUCHIab9dc7b2014-08-26 22:53:13 -070013import java.util.SortedSet;
14import java.util.TreeSet;
Yuta HIGUCHI8b389a72014-07-18 13:50:00 -070015import java.util.Map.Entry;
Yuta HIGUCHI80829d12014-02-05 20:16:56 -080016import java.util.concurrent.ConcurrentHashMap;
17import java.util.concurrent.ConcurrentMap;
Jonathan Hart26f291b2014-02-18 16:57:24 -080018import java.util.concurrent.locks.Lock;
19import java.util.concurrent.locks.ReadWriteLock;
20import java.util.concurrent.locks.ReentrantReadWriteLock;
Yuta HIGUCHI80829d12014-02-05 20:16:56 -080021
Yuta HIGUCHI8313f0b2014-07-09 16:36:03 -070022import javax.annotation.concurrent.GuardedBy;
23
Yuta HIGUCHIab9dc7b2014-08-26 22:53:13 -070024import net.floodlightcontroller.core.IFloodlightProviderService.Role;
Yuta HIGUCHI80829d12014-02-05 20:16:56 -080025import net.floodlightcontroller.util.MACAddress;
Yuta HIGUCHI8f3dfa32014-06-25 00:14:25 -070026import net.onrc.onos.core.util.Dpid;
Yuta HIGUCHI8b389a72014-07-18 13:50:00 -070027import net.onrc.onos.core.util.LinkTuple;
Yuta HIGUCHIab9dc7b2014-08-26 22:53:13 -070028import net.onrc.onos.core.util.OnosInstanceId;
Yuta HIGUCHI8f3dfa32014-06-25 00:14:25 -070029import net.onrc.onos.core.util.PortNumber;
Jonathan Hart25bd53e2014-04-30 23:44:09 -070030import net.onrc.onos.core.util.SwitchPort;
Yuta HIGUCHI80829d12014-02-05 20:16:56 -080031
32import org.slf4j.Logger;
33import org.slf4j.LoggerFactory;
34
Yuta HIGUCHIfa742842014-07-03 22:35:13 -070035import com.google.common.collect.HashMultimap;
36import com.google.common.collect.Multimap;
37import com.google.common.collect.Multimaps;
38
Yuta HIGUCHI8b389a72014-07-18 13:50:00 -070039
Yuta HIGUCHIab9dc7b2014-08-26 22:53:13 -070040// TODO add TopologyManager, etc. to populate Mastership information.
Yuta HIGUCHI8b389a72014-07-18 13:50:00 -070041/**
42 * Class to represent an instance of Topology Snapshot.
43 */
Yuta HIGUCHI9e6223d2014-08-26 00:01:32 -070044public class TopologyImpl implements MutableTopology, MutableInternalTopology {
Yuta HIGUCHI8b389a72014-07-18 13:50:00 -070045
Jonathan Harte37e4e22014-05-13 19:12:02 -070046 private static final Logger log = LoggerFactory.getLogger(TopologyImpl.class);
Yuta HIGUCHI80829d12014-02-05 20:16:56 -080047
Yuta HIGUCHI8b389a72014-07-18 13:50:00 -070048 // TODO Revisit Map types after implementing CoW/lock-free
49
Yuta HIGUCHIab9dc7b2014-08-26 22:53:13 -070050 // Mastership info
51 // Dpid -> [ (InstanceID, Role) ]
52 private final Map<Dpid, SortedSet<MastershipEvent>> mastership;
53
Ray Milkey269ffb92014-04-03 14:43:30 -070054 // DPID -> Switch
Yuta HIGUCHI8b389a72014-07-18 13:50:00 -070055 private final ConcurrentMap<Dpid, SwitchEvent> switches;
56 private final ConcurrentMap<Dpid, ConcurrentMap<PortNumber, PortEvent>> ports;
Yuta HIGUCHIfa742842014-07-03 22:35:13 -070057
Yuta HIGUCHIbfc77f02014-07-14 22:50:25 -070058 // Index from Port to Host
Yuta HIGUCHI8b389a72014-07-18 13:50:00 -070059 private final Multimap<SwitchPort, HostEvent> hosts;
60 private final ConcurrentMap<MACAddress, HostEvent> mac2Host;
Jonathan Hart25bd53e2014-04-30 23:44:09 -070061
Yuta HIGUCHI8313f0b2014-07-09 16:36:03 -070062 // SwitchPort -> (type -> Link)
Yuta HIGUCHI8b389a72014-07-18 13:50:00 -070063 private final ConcurrentMap<SwitchPort, ConcurrentMap<String, LinkEvent>> outgoingLinks;
64 private final ConcurrentMap<SwitchPort, ConcurrentMap<String, LinkEvent>> incomingLinks;
Yuta HIGUCHI5d2d8d42014-02-20 22:22:53 -080065
Yuta HIGUCHI9e6223d2014-08-26 00:01:32 -070066 private final ReadWriteLock readWriteLock = new ReentrantReadWriteLock();
67 private final Lock readLock = readWriteLock.readLock();
Ray Milkey269ffb92014-04-03 14:43:30 -070068 // TODO use the write lock after refactor
Yuta HIGUCHI9e6223d2014-08-26 00:01:32 -070069 private final Lock writeLock = readWriteLock.writeLock();
Yuta HIGUCHI80829d12014-02-05 20:16:56 -080070
Yuta HIGUCHI8b389a72014-07-18 13:50:00 -070071 /**
72 * Create an empty Topology.
73 */
Jonathan Harte37e4e22014-05-13 19:12:02 -070074 public TopologyImpl() {
Yuta HIGUCHIab9dc7b2014-08-26 22:53:13 -070075 mastership = new HashMap<>();
Ray Milkey269ffb92014-04-03 14:43:30 -070076 // TODO: Does these object need to be stored in Concurrent Collection?
77 switches = new ConcurrentHashMap<>();
Yuta HIGUCHIfa742842014-07-03 22:35:13 -070078 ports = new ConcurrentHashMap<>();
Yuta HIGUCHIbfc77f02014-07-14 22:50:25 -070079 hosts = Multimaps.synchronizedMultimap(
Yuta HIGUCHI8b389a72014-07-18 13:50:00 -070080 HashMultimap.<SwitchPort, HostEvent>create());
Yuta HIGUCHIbfc77f02014-07-14 22:50:25 -070081 mac2Host = new ConcurrentHashMap<>();
Jonathan Hart25bd53e2014-04-30 23:44:09 -070082 outgoingLinks = new ConcurrentHashMap<>();
83 incomingLinks = new ConcurrentHashMap<>();
Ray Milkey269ffb92014-04-03 14:43:30 -070084 }
Yuta HIGUCHI80829d12014-02-05 20:16:56 -080085
Yuta HIGUCHI8b389a72014-07-18 13:50:00 -070086 /**
87 * Create a shallow copy of given Topology.
88 *
89 * @param original Topology
90 */
91 public TopologyImpl(TopologyImpl original) {
92 original.acquireReadLock();
93 try {
Yuta HIGUCHIab9dc7b2014-08-26 22:53:13 -070094 // shallow copy Set in Map
95 this.mastership = new HashMap<>(original.mastership.size());
96 for (Entry<Dpid, SortedSet<MastershipEvent>> e
97 : original.mastership.entrySet()) {
98 this.mastership.put(e.getKey(), new TreeSet<>(e.getValue()));
99 }
100
Yuta HIGUCHI8b389a72014-07-18 13:50:00 -0700101 this.switches = new ConcurrentHashMap<>(original.switches);
102
103 // shallow copy Map in Map
104 this.ports = new ConcurrentHashMap<>(original.ports.size());
105 for (Entry<Dpid, ConcurrentMap<PortNumber, PortEvent>> entry
106 : original.ports.entrySet()) {
107 this.ports.put(entry.getKey(), new ConcurrentHashMap<>(entry.getValue()));
108 }
109
110 this.hosts = Multimaps.synchronizedMultimap(
111 HashMultimap.<SwitchPort, HostEvent>create(original.hosts));
112 this.mac2Host = new ConcurrentHashMap<>(original.mac2Host);
113
114 // shallow copy Map in Map
115 this.outgoingLinks = new ConcurrentHashMap<>(original.outgoingLinks.size());
116 for (Entry<SwitchPort, ConcurrentMap<String, LinkEvent>> entry
117 : original.outgoingLinks.entrySet()) {
118 this.outgoingLinks.put(entry.getKey(), new ConcurrentHashMap<>(entry.getValue()));
119 }
120
121 // shallow copy Map in Map
122 this.incomingLinks = new ConcurrentHashMap<>(original.incomingLinks.size());
123 for (Entry<SwitchPort, ConcurrentMap<String, LinkEvent>> entry
124 : original.incomingLinks.entrySet()) {
125 this.incomingLinks.put(entry.getKey(), new ConcurrentHashMap<>(entry.getValue()));
126 }
127 } finally {
128 original.releaseReadLock();
129 }
130 }
131
Ray Milkey269ffb92014-04-03 14:43:30 -0700132 @Override
Yuta HIGUCHI8f3dfa32014-06-25 00:14:25 -0700133 public Switch getSwitch(Dpid dpid) {
Yuta HIGUCHI8b389a72014-07-18 13:50:00 -0700134 final SwitchEvent sw = switches.get(dpid);
135 if (sw != null) {
136 return new SwitchImpl(this, dpid);
137 } else {
138 return null;
Yuta HIGUCHIfa742842014-07-03 22:35:13 -0700139 }
Ray Milkey269ffb92014-04-03 14:43:30 -0700140 }
Pavlin Radoslavov6d224ee2014-02-18 16:43:15 -0800141
Ray Milkey269ffb92014-04-03 14:43:30 -0700142 @Override
143 public Iterable<Switch> getSwitches() {
Yuta HIGUCHI8b389a72014-07-18 13:50:00 -0700144 List<Switch> list = new ArrayList<>(switches.size());
145 for (SwitchEvent elm : switches.values()) {
146 list.add(new SwitchImpl(this, elm.getDpid()));
147 }
148 return list;
Ray Milkey269ffb92014-04-03 14:43:30 -0700149 }
Yuta HIGUCHI80829d12014-02-05 20:16:56 -0800150
Ray Milkey269ffb92014-04-03 14:43:30 -0700151 @Override
Yuta HIGUCHI8f3dfa32014-06-25 00:14:25 -0700152 public Port getPort(Dpid dpid, PortNumber number) {
Yuta HIGUCHI8b389a72014-07-18 13:50:00 -0700153 ConcurrentMap<PortNumber, PortEvent> portMap = ports.get(dpid);
Yuta HIGUCHIfa742842014-07-03 22:35:13 -0700154 if (portMap != null) {
Yuta HIGUCHI8b389a72014-07-18 13:50:00 -0700155 final PortEvent port = portMap.get(number);
156 if (port != null) {
157 return new PortImpl(this, port.getSwitchPort());
158 }
Ray Milkey269ffb92014-04-03 14:43:30 -0700159 }
160 return null;
161 }
Pavlin Radoslavov06df22a2014-02-18 19:16:27 -0800162
Ray Milkey269ffb92014-04-03 14:43:30 -0700163 @Override
Yuta HIGUCHI8f3dfa32014-06-25 00:14:25 -0700164 public Port getPort(SwitchPort port) {
Pavlin Radoslavov3d322f42014-08-18 14:58:55 -0700165 return getPort(port.getDpid(), port.getPortNumber());
Jonathan Hart25bd53e2014-04-30 23:44:09 -0700166 }
167
168 @Override
Yuta HIGUCHIfa742842014-07-03 22:35:13 -0700169 public Collection<Port> getPorts(Dpid dpid) {
Yuta HIGUCHI8b389a72014-07-18 13:50:00 -0700170 ConcurrentMap<PortNumber, PortEvent> portMap = ports.get(dpid);
Yuta HIGUCHIfa742842014-07-03 22:35:13 -0700171 if (portMap == null) {
172 return Collections.emptyList();
173 }
Yuta HIGUCHI8b389a72014-07-18 13:50:00 -0700174 List<Port> list = new ArrayList<>(portMap.size());
175 for (PortEvent elm : portMap.values()) {
176 list.add(new PortImpl(this, elm.getSwitchPort()));
177 }
178 return list;
Yuta HIGUCHIfa742842014-07-03 22:35:13 -0700179 }
180
181 @Override
Yuta HIGUCHI8f3dfa32014-06-25 00:14:25 -0700182 public Link getOutgoingLink(Dpid dpid, PortNumber number) {
Yuta HIGUCHI8313f0b2014-07-09 16:36:03 -0700183 return getOutgoingLink(new SwitchPort(dpid, number));
Ray Milkey269ffb92014-04-03 14:43:30 -0700184 }
Pavlin Radoslavov7c8f69a2014-02-19 19:01:45 -0800185
Ray Milkey269ffb92014-04-03 14:43:30 -0700186 @Override
Yuta HIGUCHI8f3dfa32014-06-25 00:14:25 -0700187 public Link getOutgoingLink(SwitchPort port) {
Yuta HIGUCHI8b389a72014-07-18 13:50:00 -0700188 Map<String, LinkEvent> links = outgoingLinks.get(port);
Yuta HIGUCHI8313f0b2014-07-09 16:36:03 -0700189 return getPacketLinkIfExists(links);
190 }
191
192 // TODO remove when we no longer need packet fall back behavior
193 /**
Yuta HIGUCHI8b389a72014-07-18 13:50:00 -0700194 * Gets the "packet" link if such exists,
195 * if not return whichever link is found first.
Yuta HIGUCHI8313f0b2014-07-09 16:36:03 -0700196 *
197 * @param links Collection of links to search from
198 * @return Link instance found or null if no link exists
199 */
Yuta HIGUCHI8b389a72014-07-18 13:50:00 -0700200 private Link getPacketLinkIfExists(Map<String, LinkEvent> links) {
Yuta HIGUCHI8313f0b2014-07-09 16:36:03 -0700201
202 if (links == null) {
203 return null;
204 }
205
Yuta HIGUCHI8b389a72014-07-18 13:50:00 -0700206 LinkEvent link = links.get(TopologyElement.TYPE_PACKET_LAYER);
Yuta HIGUCHI8313f0b2014-07-09 16:36:03 -0700207 if (link != null) {
208 // return packet link
Yuta HIGUCHI8b389a72014-07-18 13:50:00 -0700209 return new LinkImpl(this, link.getLinkTuple());
Yuta HIGUCHI8313f0b2014-07-09 16:36:03 -0700210 } else {
211 // return whatever found
Yuta HIGUCHI8b389a72014-07-18 13:50:00 -0700212 Iterator<LinkEvent> it = links.values().iterator();
Yuta HIGUCHI8313f0b2014-07-09 16:36:03 -0700213 if (it.hasNext()) {
Yuta HIGUCHI8b389a72014-07-18 13:50:00 -0700214 return new LinkImpl(this, it.next().getLinkTuple());
Yuta HIGUCHI8313f0b2014-07-09 16:36:03 -0700215 }
216 }
217 return null;
218 }
219
220 @Override
221 public Link getOutgoingLink(Dpid dpid, PortNumber number, String type) {
222 return getOutgoingLink(new SwitchPort(dpid, number), type);
223 }
224
225 @Override
226 public Link getOutgoingLink(SwitchPort port, String type) {
Yuta HIGUCHI8b389a72014-07-18 13:50:00 -0700227 Map<String, LinkEvent> links = outgoingLinks.get(port);
228 final LinkEvent link = links.get(type);
229 if (link != null) {
230 return new LinkImpl(this, link.getLinkTuple());
231 }
232 return null;
Yuta HIGUCHI8313f0b2014-07-09 16:36:03 -0700233 }
234
235 @Override
236 public Collection<Link> getOutgoingLinks(SwitchPort port) {
Yuta HIGUCHI8b389a72014-07-18 13:50:00 -0700237 ConcurrentMap<String, LinkEvent> typeMap = outgoingLinks.get(port);
238 if (typeMap == null) {
239 return Collections.emptyList();
240 }
241 return toLinkImpls(typeMap.values());
242 }
243
244 /**
245 * Converts collection of LinkEvent to collection of LinkImpls.
246 *
247 * @param links collection of LinkEvent
248 * @return collection of LinkImpls
249 */
250 private Collection<Link> toLinkImpls(final Collection<LinkEvent> links) {
251 if (links == null) {
252 return Collections.emptyList();
253 }
254 List<Link> list = new ArrayList<>(links.size());
255 for (LinkEvent elm : links) {
256 list.add(new LinkImpl(this, elm.getLinkTuple()));
257 }
258 return list;
Yuta HIGUCHI8f3dfa32014-06-25 00:14:25 -0700259 }
260
261 @Override
262 public Link getIncomingLink(Dpid dpid, PortNumber number) {
Yuta HIGUCHI8313f0b2014-07-09 16:36:03 -0700263 return getIncomingLink(new SwitchPort(dpid, number));
Yuta HIGUCHI8f3dfa32014-06-25 00:14:25 -0700264 }
265
266 @Override
267 public Link getIncomingLink(SwitchPort port) {
Yuta HIGUCHI8b389a72014-07-18 13:50:00 -0700268 Map<String, LinkEvent> links = incomingLinks.get(port);
Yuta HIGUCHI8313f0b2014-07-09 16:36:03 -0700269 return getPacketLinkIfExists(links);
270 }
271
272 @Override
273 public Link getIncomingLink(Dpid dpid, PortNumber number, String type) {
274 return getIncomingLink(new SwitchPort(dpid, number), type);
275 }
276
277 @Override
278 public Link getIncomingLink(SwitchPort port, String type) {
Yuta HIGUCHI8b389a72014-07-18 13:50:00 -0700279 Map<String, LinkEvent> links = incomingLinks.get(port);
280 final LinkEvent link = links.get(type);
281 if (link != null) {
282 return new LinkImpl(this, link.getLinkTuple());
283 }
284 return null;
Yuta HIGUCHI8313f0b2014-07-09 16:36:03 -0700285 }
286
287 @Override
288 public Collection<Link> getIncomingLinks(SwitchPort port) {
Yuta HIGUCHI8b389a72014-07-18 13:50:00 -0700289 ConcurrentMap<String, LinkEvent> typeMap = incomingLinks.get(port);
290 if (typeMap == null) {
291 return Collections.emptyList();
292 }
293 return toLinkImpls(typeMap.values());
Yuta HIGUCHI8f3dfa32014-06-25 00:14:25 -0700294 }
295
296 @Override
297 public Link getLink(Dpid srcDpid, PortNumber srcNumber,
298 Dpid dstDpid, PortNumber dstNumber) {
299
Yuta HIGUCHI8313f0b2014-07-09 16:36:03 -0700300 final SwitchPort dstSwitchPort = new SwitchPort(dstDpid, dstNumber);
301 Collection<Link> links = getOutgoingLinks(new SwitchPort(srcDpid, srcNumber));
302 for (Link link : links) {
303 if (link == null) {
304 continue;
305 }
Yuta HIGUCHIcd14dda2014-07-24 09:57:22 -0700306 if (link.getDstPort().getSwitchPort().equals(dstSwitchPort)) {
Yuta HIGUCHI8313f0b2014-07-09 16:36:03 -0700307 return link;
308 }
309 }
310 return null;
311 }
312
313 @Override
314 public Link getLink(Dpid srcDpid, PortNumber srcNumber,
315 Dpid dstDpid, PortNumber dstNumber,
316 String type) {
317
318 Link link = getOutgoingLink(srcDpid, srcNumber, type);
Ray Milkeyb29e6262014-04-09 16:02:14 -0700319 if (link == null) {
Ray Milkey269ffb92014-04-03 14:43:30 -0700320 return null;
Ray Milkeyb29e6262014-04-09 16:02:14 -0700321 }
322 if (!link.getDstSwitch().getDpid().equals(dstDpid)) {
Ray Milkey269ffb92014-04-03 14:43:30 -0700323 return null;
Ray Milkeyb29e6262014-04-09 16:02:14 -0700324 }
325 if (!link.getDstPort().getNumber().equals(dstNumber)) {
Ray Milkey269ffb92014-04-03 14:43:30 -0700326 return null;
Ray Milkeyb29e6262014-04-09 16:02:14 -0700327 }
Ray Milkey269ffb92014-04-03 14:43:30 -0700328 return link;
329 }
Pavlin Radoslavov7c8f69a2014-02-19 19:01:45 -0800330
Ray Milkey269ffb92014-04-03 14:43:30 -0700331 @Override
332 public Iterable<Link> getLinks() {
Yuta HIGUCHI8313f0b2014-07-09 16:36:03 -0700333 List<Link> links = new ArrayList<>();
334
Yuta HIGUCHI8b389a72014-07-18 13:50:00 -0700335 for (Map<String, LinkEvent> portLinks : outgoingLinks.values()) {
336 if (portLinks == null) {
337 continue;
338 }
339 for (LinkEvent elm : portLinks.values()) {
340 links.add(new LinkImpl(this, elm.getLinkTuple()));
341 }
Yuta HIGUCHI8313f0b2014-07-09 16:36:03 -0700342 }
343 return links;
Jonathan Hart25bd53e2014-04-30 23:44:09 -0700344 }
Toshio Koide2f570c12014-02-06 16:55:32 -0800345
Yuta HIGUCHI8b389a72014-07-18 13:50:00 -0700346 @Override
347 public Host getHostByMac(MACAddress address) {
348 HostEvent host = mac2Host.get(address);
349 if (host != null) {
350 return new HostImpl(this, address);
351 }
352 return null;
353 }
354
355 @Override
356 public Iterable<Host> getHosts() {
357 return toHostImpls(mac2Host.values());
358 }
359
360 /**
361 * Converts collection of HostEvent to collection of HostImpl.
362 *
363 * @param events collection of HostEvent
364 * @return collection of HostImpl
365 */
366 private List<Host> toHostImpls(Collection<HostEvent> events) {
367 if (events == null) {
368 return Collections.emptyList();
369 }
370 List<Host> list = new ArrayList<>(events.size());
371 for (HostEvent elm : events) {
372 list.add(new HostImpl(this, elm.getMac()));
373 }
374 return list;
375 }
376
377 @Override
378 public Collection<Host> getHosts(SwitchPort port) {
379 return toHostImpls(hosts.get(port));
380 }
381
382 @Override
383 public SwitchEvent getSwitchEvent(final Dpid dpid) {
384 return this.switches.get(dpid);
385 }
386
387 @Override
Pavlin Radoslavov054cd592014-08-07 20:57:16 -0700388 public Collection<SwitchEvent> getAllSwitchEvents() {
389 return Collections.unmodifiableCollection(switches.values());
390 }
391
392 @Override
Yuta HIGUCHI8b389a72014-07-18 13:50:00 -0700393 public PortEvent getPortEvent(final SwitchPort port) {
Yuta HIGUCHI45ccade2014-08-18 17:09:19 -0700394 return getPortEvent(port.getDpid(), port.getPortNumber());
395 }
396
397 @Override
398 public PortEvent getPortEvent(final Dpid dpid, PortNumber portNumber) {
399 ConcurrentMap<PortNumber, PortEvent> portMap = this.ports.get(dpid);
Yuta HIGUCHI8b389a72014-07-18 13:50:00 -0700400 if (portMap != null) {
Yuta HIGUCHI45ccade2014-08-18 17:09:19 -0700401 return portMap.get(portNumber);
Yuta HIGUCHI8b389a72014-07-18 13:50:00 -0700402 }
403 return null;
404 }
405
406 @Override
Yuta HIGUCHI45ccade2014-08-18 17:09:19 -0700407 public Collection<PortEvent> getPortEvents(final Dpid dpid) {
408 ConcurrentMap<PortNumber, PortEvent> portList = ports.get(dpid);
409 if (portList == null) {
410 return Collections.emptyList();
411 }
412 return Collections.unmodifiableCollection(portList.values());
413 }
414
415 @Override
Pavlin Radoslavov054cd592014-08-07 20:57:16 -0700416 public Collection<PortEvent> getAllPortEvents() {
417 List<PortEvent> events = new LinkedList<>();
418 for (ConcurrentMap<PortNumber, PortEvent> cm : ports.values()) {
419 events.addAll(cm.values());
420 }
421 return Collections.unmodifiableCollection(events);
422 }
423
424 @Override
Yuta HIGUCHI8b389a72014-07-18 13:50:00 -0700425 public LinkEvent getLinkEvent(final LinkTuple linkId) {
426 ConcurrentMap<String, LinkEvent> links = this.outgoingLinks.get(linkId.getSrc());
427 if (links == null) {
428 return null;
429 }
430
431 // TODO Should we look for Packet link first?
432 // Not unless invariant is broken.
433
434 for (LinkEvent link : links.values()) {
435 if (link.getDst().equals(linkId.getDst())) {
436 return link;
437 }
438 }
439 return null;
440 }
441
442 @Override
443 public LinkEvent getLinkEvent(final LinkTuple linkId, final String type) {
444 ConcurrentMap<String, LinkEvent> links = this.outgoingLinks.get(linkId.getSrc());
445 if (links == null) {
446 return null;
447 }
448 return links.get(type);
449 }
450
451 @Override
Yuta HIGUCHI9e6223d2014-08-26 00:01:32 -0700452 public Collection<LinkEvent> getLinkEventsFrom(SwitchPort srcPort) {
453 ConcurrentMap<String, LinkEvent> links = this.outgoingLinks.get(srcPort);
454 if (links == null) {
455 return Collections.emptyList();
456 }
457 return Collections.unmodifiableCollection(links.values());
458 }
459
460 @Override
461 public Collection<LinkEvent> getLinkEventsTo(SwitchPort dstPort) {
462 ConcurrentMap<String, LinkEvent> links = this.incomingLinks.get(dstPort);
463 if (links == null) {
464 return Collections.emptyList();
465 }
466 return Collections.unmodifiableCollection(links.values());
467 }
468
469 @Override
Yuta HIGUCHI8b389a72014-07-18 13:50:00 -0700470 public Collection<LinkEvent> getLinkEvents(final LinkTuple linkId) {
471 ConcurrentMap<String, LinkEvent> links = this.outgoingLinks.get(linkId.getSrc());
472 if (links == null) {
473 return Collections.emptyList();
474 }
475
476 // unless invariant is broken, this should contain at most 1 element.
477 return Collections.unmodifiableCollection(links.values());
478 }
479
480 @Override
Pavlin Radoslavov054cd592014-08-07 20:57:16 -0700481 public Collection<LinkEvent> getAllLinkEvents() {
482 List<LinkEvent> events = new LinkedList<>();
483 for (ConcurrentMap<String, LinkEvent> cm : outgoingLinks.values()) {
484 events.addAll(cm.values());
485 }
486 return Collections.unmodifiableCollection(events);
487 }
488
489 @Override
Yuta HIGUCHI8b389a72014-07-18 13:50:00 -0700490 public HostEvent getHostEvent(final MACAddress mac) {
491 return this.mac2Host.get(mac);
492 }
493
Pavlin Radoslavov054cd592014-08-07 20:57:16 -0700494 @Override
Yuta HIGUCHI9e6223d2014-08-26 00:01:32 -0700495 public Collection<HostEvent> getHostEvents(SwitchPort port) {
496 return Collections.unmodifiableCollection(hosts.get(port));
497 }
498
499 @Override
Pavlin Radoslavov054cd592014-08-07 20:57:16 -0700500 public Collection<HostEvent> getAllHostEvents() {
501 return Collections.unmodifiableCollection(mac2Host.values());
502 }
503
Yuta HIGUCHIab9dc7b2014-08-26 22:53:13 -0700504 @Override
505 public OnosInstanceId getSwitchMaster(Dpid dpid) {
506 final SortedSet<MastershipEvent> candidates = mastership.get(dpid);
507 if (candidates == null) {
508 return null;
509 }
510 for (MastershipEvent candidate : candidates) {
511 if (candidate.getRole() == Role.MASTER) {
512 return candidate.getOnosInstanceId();
513 }
514 }
515 return null;
516 }
517
Yuta HIGUCHI8b389a72014-07-18 13:50:00 -0700518 /**
519 * Puts a SwitchEvent.
520 *
521 * @param sw Switch to add. (Will be frozen if not already)
522 */
523 @GuardedBy("writeLock")
524 protected void putSwitch(SwitchEvent sw) {
525 // TODO isFrozen check once we implement CoW/lock-free
526 switches.put(sw.getDpid(), sw.freeze());
527 ports.putIfAbsent(sw.getDpid(), new ConcurrentHashMap<PortNumber, PortEvent>());
528 }
529
530 /**
531 * Removes a SwitchEvent from this snapshot.
532 * <p/>
533 * Will also remove ports, if it has not been removed already.
534 *
535 * @param dpid Switch DPID
536 */
537 @GuardedBy("writeLock")
538 protected void removeSwitch(Dpid dpid) {
539 // TODO isFrozen check once we implement CoW/lock-free
540 switches.remove(dpid);
541 ConcurrentMap<PortNumber, PortEvent> removedPorts = ports.remove(dpid);
542 if (removedPorts != null && !removedPorts.isEmpty()) {
543 log.warn("Some ports were removed as side-effect of #removeSwitch({})", dpid);
544 }
545 }
546
547 /**
548 * Puts a PortEvent.
549 *
550 * @param port Port to add. (Will be frozen if not already)
551 */
552 @GuardedBy("writeLock")
553 protected void putPort(PortEvent port) {
554
555 ConcurrentMap<PortNumber, PortEvent> portMap = ports.get(port.getDpid());
556 if (portMap == null) {
557 portMap = new ConcurrentHashMap<>();
558 ConcurrentMap<PortNumber, PortEvent> existing
559 = ports.putIfAbsent(port.getDpid(), portMap);
560 if (existing != null) {
561 // port map was added concurrently, using theirs
562 portMap = existing;
563 }
564 }
565 portMap.put(port.getPortNumber(), port.freeze());
566 }
567
568 /**
569 * Removes a PortEvent from this snapshot.
570 *
571 * @param port SwitchPort to remove
572 */
573 @GuardedBy("writeLock")
574 protected void removePort(SwitchPort port) {
575 removePort(port.getDpid(), port.getPortNumber());
576 }
577
578 /**
579 * Removes a PortEvent from this snapshot.
580 * <p/>
581 * Will also remove ports, if it has not been removed already.
582 *
583 * @param dpid Switch DPID
584 * @param number PortNumber
585 */
586 @GuardedBy("writeLock")
587 protected void removePort(Dpid dpid, PortNumber number) {
588 // TODO sanity check Host attachment point.
589 ConcurrentMap<PortNumber, PortEvent> portMap = ports.get(dpid);
590 if (portMap != null) {
591 portMap.remove(number);
592 }
593 }
594
595 /**
596 * Puts a LinkEvent.
597 *
598 * @param link LinkEvent
599 */
600 @GuardedBy("writeLock")
601 protected void putLink(LinkEvent link) {
602 // TODO Do sanity check?
603 // - There cannot be 2 links in same direction between a port pair.
604 putLinkMap(outgoingLinks, link.getSrc(), link);
605 putLinkMap(incomingLinks, link.getDst(), link);
Jonathan Hart25bd53e2014-04-30 23:44:09 -0700606 }
607
Yuta HIGUCHI8313f0b2014-07-09 16:36:03 -0700608 /**
609 * Helper method to update outgoingLinks, incomingLinks.
610 *
Yuta HIGUCHI8b389a72014-07-18 13:50:00 -0700611 * @param linkMap outgoingLinks or incomingLinks to update
612 * @param port {@code linkMap} key to update
Yuta HIGUCHI8313f0b2014-07-09 16:36:03 -0700613 * @param link Link to add
614 */
Yuta HIGUCHI8b389a72014-07-18 13:50:00 -0700615 @GuardedBy("writeLock")
616 private void putLinkMap(ConcurrentMap<SwitchPort, ConcurrentMap<String, LinkEvent>> linkMap,
617 SwitchPort port, LinkEvent link) {
618
619 ConcurrentMap<String, LinkEvent> linksOnPort = linkMap.get(port);
620 if (linksOnPort == null) {
621 linksOnPort = new ConcurrentHashMap<>(4);
622 ConcurrentMap<String, LinkEvent> existing
623 = linkMap.putIfAbsent(
Yuta HIGUCHI8313f0b2014-07-09 16:36:03 -0700624 port,
Yuta HIGUCHI8b389a72014-07-18 13:50:00 -0700625 linksOnPort);
626
627 if (existing != null) {
628 linksOnPort = existing;
629 }
Yuta HIGUCHI8313f0b2014-07-09 16:36:03 -0700630 }
Yuta HIGUCHI8b389a72014-07-18 13:50:00 -0700631 linksOnPort.put(link.getType(), link);
Yuta HIGUCHI8313f0b2014-07-09 16:36:03 -0700632 }
633
Yuta HIGUCHI8b389a72014-07-18 13:50:00 -0700634 /**
635 * Removes a LinkEvent from this snapshot.
636 *
637 * @param link Link to remove
638 * @param type type of link to remove
639 */
640 @GuardedBy("writeLock")
641 protected void removeLink(LinkTuple link, String type) {
642 ConcurrentMap<String, LinkEvent> portLinks
643 = outgoingLinks.get(link.getSrc());
Yuta HIGUCHI8313f0b2014-07-09 16:36:03 -0700644 if (portLinks != null) {
645 // no conditional update here
Yuta HIGUCHI8b389a72014-07-18 13:50:00 -0700646 portLinks.remove(type);
Yuta HIGUCHI8313f0b2014-07-09 16:36:03 -0700647 }
Yuta HIGUCHI8b389a72014-07-18 13:50:00 -0700648 portLinks
649 = incomingLinks.get(link.getDst());
Yuta HIGUCHI8313f0b2014-07-09 16:36:03 -0700650 if (portLinks != null) {
651 // no conditional update here
Yuta HIGUCHI8b389a72014-07-18 13:50:00 -0700652 portLinks.remove(type);
Yuta HIGUCHI8313f0b2014-07-09 16:36:03 -0700653 }
Ray Milkey269ffb92014-04-03 14:43:30 -0700654 }
Yuta HIGUCHI80829d12014-02-05 20:16:56 -0800655
Yuta HIGUCHI8b389a72014-07-18 13:50:00 -0700656 /**
657 * Removes a LinkEvent from this snapshot.
658 *
659 * @param link Link to remove
660 */
661 @GuardedBy("writeLock")
662 protected void removeLink(LinkTuple link) {
663 Collection<LinkEvent> links = getLinkEvents(link);
664 for (LinkEvent l : links) {
665 removeLink(link, l.getType());
Yuta HIGUCHIfa742842014-07-03 22:35:13 -0700666 }
Yuta HIGUCHI8b389a72014-07-18 13:50:00 -0700667 }
668
669 /**
670 * Puts a HostEvent.
671 * <p/>
672 * Removes attachment points for previous HostEvent and update
673 * them with new HostEvent
674 *
675 * @param host HostEvent
676 */
677 @GuardedBy("writeLock")
678 protected void putHost(HostEvent host) {
679 // Host cannot be simply put() to replace instance since it has mobility.
680 // Simply remove -> put for now.
681
682 // remove old attachment points
683 removeHost(host.getMac());
684
Yuta HIGUCHIfa742842014-07-03 22:35:13 -0700685 // add new attachment points
Yuta HIGUCHI8b389a72014-07-18 13:50:00 -0700686 for (SwitchPort port : host.getAttachmentPoints()) {
687 hosts.put(port, host);
Yuta HIGUCHIfa742842014-07-03 22:35:13 -0700688 }
Yuta HIGUCHI8b389a72014-07-18 13:50:00 -0700689 mac2Host.put(host.getMac(), host);
Ray Milkey269ffb92014-04-03 14:43:30 -0700690 }
Pavlin Radoslavov6d224ee2014-02-18 16:43:15 -0800691
Yuta HIGUCHI8b389a72014-07-18 13:50:00 -0700692 /**
693 * Removes a HostEvent from this snapshot.
694 *
695 * @param mac MACAddress of the Host to remove
696 */
697 @GuardedBy("writeLock")
698 protected void removeHost(MACAddress mac) {
699 HostEvent host = mac2Host.remove(mac);
700 if (host != null) {
701 for (SwitchPort port : host.getAttachmentPoints()) {
702 hosts.remove(port, host);
703 }
Yuta HIGUCHIfa742842014-07-03 22:35:13 -0700704 }
Ray Milkey269ffb92014-04-03 14:43:30 -0700705 }
Jonathan Hart26f291b2014-02-18 16:57:24 -0800706
Yuta HIGUCHIab9dc7b2014-08-26 22:53:13 -0700707 /**
708 * Puts a mastership change event.
709 *
710 * @param master MastershipEvent
711 */
712 @GuardedBy("writeLock")
713 protected void putSwitchMastershipEvent(MastershipEvent master) {
714 checkNotNull(master);
715
716 SortedSet<MastershipEvent> candidates
717 = mastership.get(master.getDpid());
718 if (candidates == null) {
719 // SortedSet, customized so that MASTER MastershipEvent appear
720 // earlier during iteration.
721 candidates = new TreeSet<>(new MastershipEvent.MasterFirstComparator());
722 }
723
724 // always replace
725 candidates.remove(master);
726 candidates.add(master);
727 }
728
729 /**
730 * Removes a mastership change event.
731 * <p>
732 * Note: Only Dpid and OnosInstanceId will be used to identify the
733 * {@link MastershipEvent} to remove.
734 *
735 * @param master {@link MastershipEvent} to remove. (Role is ignored)
736 */
737 @GuardedBy("writeLock")
738 protected void removeSwitchMastershipEvent(MastershipEvent master) {
739 checkNotNull(master);
740
741 SortedSet<MastershipEvent> candidates
742 = mastership.get(master.getDpid());
743 if (candidates == null) {
744 // nothing to do
745 return;
746 }
747 candidates.remove(master);
748 }
749
Yuta HIGUCHI8b389a72014-07-18 13:50:00 -0700750
Ray Milkey269ffb92014-04-03 14:43:30 -0700751 @Override
752 public void acquireReadLock() {
753 readLock.lock();
754 }
Jonathan Hart26f291b2014-02-18 16:57:24 -0800755
Ray Milkey269ffb92014-04-03 14:43:30 -0700756 @Override
757 public void releaseReadLock() {
758 readLock.unlock();
759 }
Pavlin Radoslavov8ffb8bf2014-02-20 15:34:26 -0800760
Ray Milkey269ffb92014-04-03 14:43:30 -0700761 protected void acquireWriteLock() {
762 writeLock.lock();
763 }
Pavlin Radoslavov8ffb8bf2014-02-20 15:34:26 -0800764
Ray Milkey269ffb92014-04-03 14:43:30 -0700765 protected void releaseWriteLock() {
766 writeLock.unlock();
767 }
Yuta HIGUCHI80829d12014-02-05 20:16:56 -0800768}