blob: cc1cc9f615f6f9d5e10c29af9dbae8e6cea1d332 [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 }
Yuta HIGUCHI4f328842014-08-28 17:23:09 -0700448 LinkEvent link = links.get(type);
449 if (link.getDst().equals(linkId.getDst())) {
450 return link;
451 }
452 return null;
Yuta HIGUCHI8b389a72014-07-18 13:50:00 -0700453 }
454
455 @Override
Yuta HIGUCHI9e6223d2014-08-26 00:01:32 -0700456 public Collection<LinkEvent> getLinkEventsFrom(SwitchPort srcPort) {
457 ConcurrentMap<String, LinkEvent> links = this.outgoingLinks.get(srcPort);
458 if (links == null) {
459 return Collections.emptyList();
460 }
461 return Collections.unmodifiableCollection(links.values());
462 }
463
464 @Override
465 public Collection<LinkEvent> getLinkEventsTo(SwitchPort dstPort) {
466 ConcurrentMap<String, LinkEvent> links = this.incomingLinks.get(dstPort);
467 if (links == null) {
468 return Collections.emptyList();
469 }
470 return Collections.unmodifiableCollection(links.values());
471 }
472
473 @Override
Yuta HIGUCHI8b389a72014-07-18 13:50:00 -0700474 public Collection<LinkEvent> getLinkEvents(final LinkTuple linkId) {
475 ConcurrentMap<String, LinkEvent> links = this.outgoingLinks.get(linkId.getSrc());
476 if (links == null) {
477 return Collections.emptyList();
478 }
479
Yuta HIGUCHI4f328842014-08-28 17:23:09 -0700480 List<LinkEvent> linkEvents = new ArrayList<>();
481 for (LinkEvent e : links.values()) {
482 if (e.getDst().equals(linkId.getDst())) {
483 linkEvents.add(e);
484 }
485 }
486
Yuta HIGUCHI8b389a72014-07-18 13:50:00 -0700487 // unless invariant is broken, this should contain at most 1 element.
Yuta HIGUCHI4f328842014-08-28 17:23:09 -0700488 return linkEvents;
Yuta HIGUCHI8b389a72014-07-18 13:50:00 -0700489 }
490
491 @Override
Pavlin Radoslavov054cd592014-08-07 20:57:16 -0700492 public Collection<LinkEvent> getAllLinkEvents() {
493 List<LinkEvent> events = new LinkedList<>();
494 for (ConcurrentMap<String, LinkEvent> cm : outgoingLinks.values()) {
495 events.addAll(cm.values());
496 }
497 return Collections.unmodifiableCollection(events);
498 }
499
500 @Override
Yuta HIGUCHI8b389a72014-07-18 13:50:00 -0700501 public HostEvent getHostEvent(final MACAddress mac) {
502 return this.mac2Host.get(mac);
503 }
504
Pavlin Radoslavov054cd592014-08-07 20:57:16 -0700505 @Override
Yuta HIGUCHI9e6223d2014-08-26 00:01:32 -0700506 public Collection<HostEvent> getHostEvents(SwitchPort port) {
507 return Collections.unmodifiableCollection(hosts.get(port));
508 }
509
510 @Override
Pavlin Radoslavov054cd592014-08-07 20:57:16 -0700511 public Collection<HostEvent> getAllHostEvents() {
512 return Collections.unmodifiableCollection(mac2Host.values());
513 }
514
Yuta HIGUCHIab9dc7b2014-08-26 22:53:13 -0700515 @Override
516 public OnosInstanceId getSwitchMaster(Dpid dpid) {
517 final SortedSet<MastershipEvent> candidates = mastership.get(dpid);
518 if (candidates == null) {
519 return null;
520 }
521 for (MastershipEvent candidate : candidates) {
522 if (candidate.getRole() == Role.MASTER) {
523 return candidate.getOnosInstanceId();
524 }
525 }
526 return null;
527 }
528
Yuta HIGUCHI8b389a72014-07-18 13:50:00 -0700529 /**
530 * Puts a SwitchEvent.
531 *
532 * @param sw Switch to add. (Will be frozen if not already)
533 */
534 @GuardedBy("writeLock")
535 protected void putSwitch(SwitchEvent sw) {
536 // TODO isFrozen check once we implement CoW/lock-free
537 switches.put(sw.getDpid(), sw.freeze());
538 ports.putIfAbsent(sw.getDpid(), new ConcurrentHashMap<PortNumber, PortEvent>());
539 }
540
541 /**
542 * Removes a SwitchEvent from this snapshot.
543 * <p/>
544 * Will also remove ports, if it has not been removed already.
545 *
546 * @param dpid Switch DPID
547 */
548 @GuardedBy("writeLock")
549 protected void removeSwitch(Dpid dpid) {
550 // TODO isFrozen check once we implement CoW/lock-free
551 switches.remove(dpid);
552 ConcurrentMap<PortNumber, PortEvent> removedPorts = ports.remove(dpid);
553 if (removedPorts != null && !removedPorts.isEmpty()) {
554 log.warn("Some ports were removed as side-effect of #removeSwitch({})", dpid);
555 }
556 }
557
558 /**
559 * Puts a PortEvent.
560 *
561 * @param port Port to add. (Will be frozen if not already)
562 */
563 @GuardedBy("writeLock")
564 protected void putPort(PortEvent port) {
565
566 ConcurrentMap<PortNumber, PortEvent> portMap = ports.get(port.getDpid());
567 if (portMap == null) {
568 portMap = new ConcurrentHashMap<>();
569 ConcurrentMap<PortNumber, PortEvent> existing
570 = ports.putIfAbsent(port.getDpid(), portMap);
571 if (existing != null) {
572 // port map was added concurrently, using theirs
573 portMap = existing;
574 }
575 }
576 portMap.put(port.getPortNumber(), port.freeze());
577 }
578
579 /**
580 * Removes a PortEvent from this snapshot.
581 *
582 * @param port SwitchPort to remove
583 */
584 @GuardedBy("writeLock")
585 protected void removePort(SwitchPort port) {
586 removePort(port.getDpid(), port.getPortNumber());
587 }
588
589 /**
590 * Removes a PortEvent from this snapshot.
591 * <p/>
592 * Will also remove ports, if it has not been removed already.
593 *
594 * @param dpid Switch DPID
595 * @param number PortNumber
596 */
597 @GuardedBy("writeLock")
598 protected void removePort(Dpid dpid, PortNumber number) {
599 // TODO sanity check Host attachment point.
600 ConcurrentMap<PortNumber, PortEvent> portMap = ports.get(dpid);
601 if (portMap != null) {
602 portMap.remove(number);
603 }
604 }
605
606 /**
607 * Puts a LinkEvent.
608 *
609 * @param link LinkEvent
610 */
611 @GuardedBy("writeLock")
612 protected void putLink(LinkEvent link) {
613 // TODO Do sanity check?
614 // - There cannot be 2 links in same direction between a port pair.
615 putLinkMap(outgoingLinks, link.getSrc(), link);
616 putLinkMap(incomingLinks, link.getDst(), link);
Jonathan Hart25bd53e2014-04-30 23:44:09 -0700617 }
618
Yuta HIGUCHI8313f0b2014-07-09 16:36:03 -0700619 /**
620 * Helper method to update outgoingLinks, incomingLinks.
621 *
Yuta HIGUCHI8b389a72014-07-18 13:50:00 -0700622 * @param linkMap outgoingLinks or incomingLinks to update
623 * @param port {@code linkMap} key to update
Yuta HIGUCHI8313f0b2014-07-09 16:36:03 -0700624 * @param link Link to add
625 */
Yuta HIGUCHI8b389a72014-07-18 13:50:00 -0700626 @GuardedBy("writeLock")
627 private void putLinkMap(ConcurrentMap<SwitchPort, ConcurrentMap<String, LinkEvent>> linkMap,
628 SwitchPort port, LinkEvent link) {
629
630 ConcurrentMap<String, LinkEvent> linksOnPort = linkMap.get(port);
631 if (linksOnPort == null) {
632 linksOnPort = new ConcurrentHashMap<>(4);
633 ConcurrentMap<String, LinkEvent> existing
634 = linkMap.putIfAbsent(
Yuta HIGUCHI8313f0b2014-07-09 16:36:03 -0700635 port,
Yuta HIGUCHI8b389a72014-07-18 13:50:00 -0700636 linksOnPort);
637
638 if (existing != null) {
639 linksOnPort = existing;
640 }
Yuta HIGUCHI8313f0b2014-07-09 16:36:03 -0700641 }
Yuta HIGUCHI8b389a72014-07-18 13:50:00 -0700642 linksOnPort.put(link.getType(), link);
Yuta HIGUCHI8313f0b2014-07-09 16:36:03 -0700643 }
644
Yuta HIGUCHI8b389a72014-07-18 13:50:00 -0700645 /**
646 * Removes a LinkEvent from this snapshot.
647 *
648 * @param link Link to remove
649 * @param type type of link to remove
650 */
651 @GuardedBy("writeLock")
652 protected void removeLink(LinkTuple link, String type) {
653 ConcurrentMap<String, LinkEvent> portLinks
654 = outgoingLinks.get(link.getSrc());
Yuta HIGUCHI8313f0b2014-07-09 16:36:03 -0700655 if (portLinks != null) {
656 // no conditional update here
Yuta HIGUCHI8b389a72014-07-18 13:50:00 -0700657 portLinks.remove(type);
Yuta HIGUCHI8313f0b2014-07-09 16:36:03 -0700658 }
Yuta HIGUCHI8b389a72014-07-18 13:50:00 -0700659 portLinks
660 = incomingLinks.get(link.getDst());
Yuta HIGUCHI8313f0b2014-07-09 16:36:03 -0700661 if (portLinks != null) {
662 // no conditional update here
Yuta HIGUCHI8b389a72014-07-18 13:50:00 -0700663 portLinks.remove(type);
Yuta HIGUCHI8313f0b2014-07-09 16:36:03 -0700664 }
Ray Milkey269ffb92014-04-03 14:43:30 -0700665 }
Yuta HIGUCHI80829d12014-02-05 20:16:56 -0800666
Yuta HIGUCHI8b389a72014-07-18 13:50:00 -0700667 /**
668 * Removes a LinkEvent from this snapshot.
669 *
670 * @param link Link to remove
671 */
672 @GuardedBy("writeLock")
673 protected void removeLink(LinkTuple link) {
674 Collection<LinkEvent> links = getLinkEvents(link);
675 for (LinkEvent l : links) {
676 removeLink(link, l.getType());
Yuta HIGUCHIfa742842014-07-03 22:35:13 -0700677 }
Yuta HIGUCHI8b389a72014-07-18 13:50:00 -0700678 }
679
680 /**
681 * Puts a HostEvent.
682 * <p/>
683 * Removes attachment points for previous HostEvent and update
684 * them with new HostEvent
685 *
686 * @param host HostEvent
687 */
688 @GuardedBy("writeLock")
689 protected void putHost(HostEvent host) {
690 // Host cannot be simply put() to replace instance since it has mobility.
691 // Simply remove -> put for now.
692
693 // remove old attachment points
694 removeHost(host.getMac());
695
Yuta HIGUCHIfa742842014-07-03 22:35:13 -0700696 // add new attachment points
Yuta HIGUCHI8b389a72014-07-18 13:50:00 -0700697 for (SwitchPort port : host.getAttachmentPoints()) {
698 hosts.put(port, host);
Yuta HIGUCHIfa742842014-07-03 22:35:13 -0700699 }
Yuta HIGUCHI8b389a72014-07-18 13:50:00 -0700700 mac2Host.put(host.getMac(), host);
Ray Milkey269ffb92014-04-03 14:43:30 -0700701 }
Pavlin Radoslavov6d224ee2014-02-18 16:43:15 -0800702
Yuta HIGUCHI8b389a72014-07-18 13:50:00 -0700703 /**
704 * Removes a HostEvent from this snapshot.
705 *
706 * @param mac MACAddress of the Host to remove
707 */
708 @GuardedBy("writeLock")
709 protected void removeHost(MACAddress mac) {
710 HostEvent host = mac2Host.remove(mac);
711 if (host != null) {
712 for (SwitchPort port : host.getAttachmentPoints()) {
713 hosts.remove(port, host);
714 }
Yuta HIGUCHIfa742842014-07-03 22:35:13 -0700715 }
Ray Milkey269ffb92014-04-03 14:43:30 -0700716 }
Jonathan Hart26f291b2014-02-18 16:57:24 -0800717
Yuta HIGUCHIab9dc7b2014-08-26 22:53:13 -0700718 /**
719 * Puts a mastership change event.
720 *
721 * @param master MastershipEvent
722 */
723 @GuardedBy("writeLock")
724 protected void putSwitchMastershipEvent(MastershipEvent master) {
725 checkNotNull(master);
726
727 SortedSet<MastershipEvent> candidates
728 = mastership.get(master.getDpid());
729 if (candidates == null) {
730 // SortedSet, customized so that MASTER MastershipEvent appear
731 // earlier during iteration.
732 candidates = new TreeSet<>(new MastershipEvent.MasterFirstComparator());
733 }
734
735 // always replace
736 candidates.remove(master);
737 candidates.add(master);
738 }
739
740 /**
741 * Removes a mastership change event.
742 * <p>
743 * Note: Only Dpid and OnosInstanceId will be used to identify the
744 * {@link MastershipEvent} to remove.
745 *
746 * @param master {@link MastershipEvent} to remove. (Role is ignored)
747 */
748 @GuardedBy("writeLock")
749 protected void removeSwitchMastershipEvent(MastershipEvent master) {
750 checkNotNull(master);
751
752 SortedSet<MastershipEvent> candidates
753 = mastership.get(master.getDpid());
754 if (candidates == null) {
755 // nothing to do
756 return;
757 }
758 candidates.remove(master);
759 }
760
Yuta HIGUCHI8b389a72014-07-18 13:50:00 -0700761
Ray Milkey269ffb92014-04-03 14:43:30 -0700762 @Override
763 public void acquireReadLock() {
764 readLock.lock();
765 }
Jonathan Hart26f291b2014-02-18 16:57:24 -0800766
Ray Milkey269ffb92014-04-03 14:43:30 -0700767 @Override
768 public void releaseReadLock() {
769 readLock.unlock();
770 }
Pavlin Radoslavov8ffb8bf2014-02-20 15:34:26 -0800771
Ray Milkey269ffb92014-04-03 14:43:30 -0700772 protected void acquireWriteLock() {
773 writeLock.lock();
774 }
Pavlin Radoslavov8ffb8bf2014-02-20 15:34:26 -0800775
Ray Milkey269ffb92014-04-03 14:43:30 -0700776 protected void releaseWriteLock() {
777 writeLock.unlock();
778 }
Yuta HIGUCHI80829d12014-02-05 20:16:56 -0800779}