blob: decab6b0ecd53a0f818eba055f570ac6dfecbd03 [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;
7import java.util.List;
8import java.util.Map;
Yuta HIGUCHI80829d12014-02-05 20:16:56 -08009import java.util.concurrent.ConcurrentHashMap;
10import java.util.concurrent.ConcurrentMap;
Jonathan Hart26f291b2014-02-18 16:57:24 -080011import java.util.concurrent.locks.Lock;
12import java.util.concurrent.locks.ReadWriteLock;
13import java.util.concurrent.locks.ReentrantReadWriteLock;
Yuta HIGUCHI80829d12014-02-05 20:16:56 -080014
Yuta HIGUCHI8313f0b2014-07-09 16:36:03 -070015import javax.annotation.concurrent.GuardedBy;
16
Yuta HIGUCHI80829d12014-02-05 20:16:56 -080017import net.floodlightcontroller.util.MACAddress;
Yuta HIGUCHI8f3dfa32014-06-25 00:14:25 -070018import net.onrc.onos.core.util.Dpid;
19import net.onrc.onos.core.util.PortNumber;
Jonathan Hart25bd53e2014-04-30 23:44:09 -070020import net.onrc.onos.core.util.SwitchPort;
Yuta HIGUCHI80829d12014-02-05 20:16:56 -080021
22import org.slf4j.Logger;
23import org.slf4j.LoggerFactory;
24
Yuta HIGUCHIfa742842014-07-03 22:35:13 -070025import com.google.common.collect.HashMultimap;
26import com.google.common.collect.Multimap;
27import com.google.common.collect.Multimaps;
28
Jonathan Harte37e4e22014-05-13 19:12:02 -070029public class TopologyImpl implements Topology {
Ray Milkey269ffb92014-04-03 14:43:30 -070030 @SuppressWarnings("unused")
Jonathan Harte37e4e22014-05-13 19:12:02 -070031 private static final Logger log = LoggerFactory.getLogger(TopologyImpl.class);
Yuta HIGUCHI80829d12014-02-05 20:16:56 -080032
Ray Milkey269ffb92014-04-03 14:43:30 -070033 // DPID -> Switch
Yuta HIGUCHI8f3dfa32014-06-25 00:14:25 -070034 private final ConcurrentMap<Dpid, Switch> switches;
Yuta HIGUCHIfa742842014-07-03 22:35:13 -070035 // XXX may need to be careful when shallow copying.
36 private final ConcurrentMap<Dpid, ConcurrentMap<PortNumber, Port>> ports;
37
Yuta HIGUCHIbfc77f02014-07-14 22:50:25 -070038 // Index from Port to Host
39 private final Multimap<SwitchPort, Host> hosts;
40 private final ConcurrentMap<MACAddress, Host> mac2Host;
Jonathan Hart25bd53e2014-04-30 23:44:09 -070041
Yuta HIGUCHI8313f0b2014-07-09 16:36:03 -070042 // SwitchPort -> (type -> Link)
43 private final ConcurrentMap<SwitchPort, ConcurrentMap<String, Link>> outgoingLinks;
44 private final ConcurrentMap<SwitchPort, ConcurrentMap<String, Link>> incomingLinks;
Yuta HIGUCHI5d2d8d42014-02-20 22:22:53 -080045
Ray Milkey269ffb92014-04-03 14:43:30 -070046 private ReadWriteLock readWriteLock = new ReentrantReadWriteLock();
47 private Lock readLock = readWriteLock.readLock();
48 // TODO use the write lock after refactor
49 private Lock writeLock = readWriteLock.writeLock();
Yuta HIGUCHI80829d12014-02-05 20:16:56 -080050
Jonathan Harte37e4e22014-05-13 19:12:02 -070051 public TopologyImpl() {
Ray Milkey269ffb92014-04-03 14:43:30 -070052 // TODO: Does these object need to be stored in Concurrent Collection?
53 switches = new ConcurrentHashMap<>();
Yuta HIGUCHIfa742842014-07-03 22:35:13 -070054 ports = new ConcurrentHashMap<>();
Yuta HIGUCHIbfc77f02014-07-14 22:50:25 -070055 hosts = Multimaps.synchronizedMultimap(
56 HashMultimap.<SwitchPort, Host>create());
57 mac2Host = new ConcurrentHashMap<>();
Jonathan Hart25bd53e2014-04-30 23:44:09 -070058 outgoingLinks = new ConcurrentHashMap<>();
59 incomingLinks = new ConcurrentHashMap<>();
Ray Milkey269ffb92014-04-03 14:43:30 -070060 }
Yuta HIGUCHI80829d12014-02-05 20:16:56 -080061
Ray Milkey269ffb92014-04-03 14:43:30 -070062 @Override
Yuta HIGUCHI8f3dfa32014-06-25 00:14:25 -070063 public Switch getSwitch(Dpid dpid) {
Ray Milkey269ffb92014-04-03 14:43:30 -070064 // TODO Check if it is safe to directly return this Object.
65 return switches.get(dpid);
66 }
Yuta HIGUCHI80829d12014-02-05 20:16:56 -080067
Yuta HIGUCHIfa742842014-07-03 22:35:13 -070068 // Only add switch.
Ray Milkey269ffb92014-04-03 14:43:30 -070069 protected void putSwitch(Switch sw) {
70 switches.put(sw.getDpid(), sw);
Yuta HIGUCHIfa742842014-07-03 22:35:13 -070071 ports.putIfAbsent(sw.getDpid(), new ConcurrentHashMap<PortNumber, Port>());
Ray Milkey269ffb92014-04-03 14:43:30 -070072 }
Pavlin Radoslavov6d224ee2014-02-18 16:43:15 -080073
Yuta HIGUCHIfa742842014-07-03 22:35:13 -070074 // XXX Will remove ports in snapshot as side-effect.
Yuta HIGUCHI8f3dfa32014-06-25 00:14:25 -070075 protected void removeSwitch(Dpid dpid) {
Ray Milkey269ffb92014-04-03 14:43:30 -070076 switches.remove(dpid);
Yuta HIGUCHIfa742842014-07-03 22:35:13 -070077 ports.remove(dpid);
78 }
79
80 // This method is expected to be serialized by writeLock.
81 protected void putPort(Port port) {
82 ConcurrentMap<PortNumber, Port> portMap = ports.get(port.getDpid());
83 if (portMap == null) {
84 portMap = new ConcurrentHashMap<>();
85 ConcurrentMap<PortNumber, Port> existing =
86 ports.putIfAbsent(port.getDpid(), portMap);
87 if (existing != null) {
88 // port map was added concurrently, using theirs
89 portMap = existing;
90 }
91 }
92 portMap.put(port.getNumber(), port);
93 }
94
95 protected void removePort(Port port) {
96 ConcurrentMap<PortNumber, Port> portMap = ports.get(port.getDpid());
97 if (portMap != null) {
98 portMap.remove(port.getNumber());
99 }
Ray Milkey269ffb92014-04-03 14:43:30 -0700100 }
Pavlin Radoslavov6d224ee2014-02-18 16:43:15 -0800101
Ray Milkey269ffb92014-04-03 14:43:30 -0700102 @Override
103 public Iterable<Switch> getSwitches() {
104 // TODO Check if it is safe to directly return this Object.
105 return Collections.unmodifiableCollection(switches.values());
106 }
Yuta HIGUCHI80829d12014-02-05 20:16:56 -0800107
Ray Milkey269ffb92014-04-03 14:43:30 -0700108 @Override
Yuta HIGUCHI8f3dfa32014-06-25 00:14:25 -0700109 public Port getPort(Dpid dpid, PortNumber number) {
Yuta HIGUCHIfa742842014-07-03 22:35:13 -0700110 ConcurrentMap<PortNumber, Port> portMap = ports.get(dpid);
111 if (portMap != null) {
112 return portMap.get(number);
Ray Milkey269ffb92014-04-03 14:43:30 -0700113 }
114 return null;
115 }
Pavlin Radoslavov06df22a2014-02-18 19:16:27 -0800116
Ray Milkey269ffb92014-04-03 14:43:30 -0700117 @Override
Yuta HIGUCHI8f3dfa32014-06-25 00:14:25 -0700118 public Port getPort(SwitchPort port) {
119 return getPort(port.dpid(), port.port());
Jonathan Hart25bd53e2014-04-30 23:44:09 -0700120 }
121
122 @Override
Yuta HIGUCHIfa742842014-07-03 22:35:13 -0700123 public Collection<Port> getPorts(Dpid dpid) {
124 ConcurrentMap<PortNumber, Port> portMap = ports.get(dpid);
125 if (portMap == null) {
126 return Collections.emptyList();
127 }
128 return Collections.unmodifiableCollection(portMap.values());
129 }
130
131 @Override
Yuta HIGUCHI8f3dfa32014-06-25 00:14:25 -0700132 public Link getOutgoingLink(Dpid dpid, PortNumber number) {
Yuta HIGUCHI8313f0b2014-07-09 16:36:03 -0700133 return getOutgoingLink(new SwitchPort(dpid, number));
Ray Milkey269ffb92014-04-03 14:43:30 -0700134 }
Pavlin Radoslavov7c8f69a2014-02-19 19:01:45 -0800135
Ray Milkey269ffb92014-04-03 14:43:30 -0700136 @Override
Yuta HIGUCHI8f3dfa32014-06-25 00:14:25 -0700137 public Link getOutgoingLink(SwitchPort port) {
Yuta HIGUCHI8313f0b2014-07-09 16:36:03 -0700138 Map<String, Link> links = outgoingLinks.get(port);
139 return getPacketLinkIfExists(links);
140 }
141
142 // TODO remove when we no longer need packet fall back behavior
143 /**
144 * Gets the "packet" link if such exists, if not return whatever found.
145 *
146 * @param links Collection of links to search from
147 * @return Link instance found or null if no link exists
148 */
149 private Link getPacketLinkIfExists(Map<String, Link> links) {
150
151 if (links == null) {
152 return null;
153 }
154
Yuta HIGUCHIdbc33122014-07-10 13:32:32 -0700155 Link link = links.get(TopologyElement.TYPE_PACKET_LAYER);
Yuta HIGUCHI8313f0b2014-07-09 16:36:03 -0700156 if (link != null) {
157 // return packet link
158 return link;
159 } else {
160 // return whatever found
161 Iterator<Link> it = links.values().iterator();
162 if (it.hasNext()) {
163 return it.next();
164 }
165 }
166 return null;
167 }
168
169 @Override
170 public Link getOutgoingLink(Dpid dpid, PortNumber number, String type) {
171 return getOutgoingLink(new SwitchPort(dpid, number), type);
172 }
173
174 @Override
175 public Link getOutgoingLink(SwitchPort port, String type) {
176 Map<String, Link> links = outgoingLinks.get(port);
177 return links.get(type);
178 }
179
180 @Override
181 public Collection<Link> getOutgoingLinks(SwitchPort port) {
182 return Collections.unmodifiableCollection(outgoingLinks.get(port).values());
Yuta HIGUCHI8f3dfa32014-06-25 00:14:25 -0700183 }
184
185 @Override
186 public Link getIncomingLink(Dpid dpid, PortNumber number) {
Yuta HIGUCHI8313f0b2014-07-09 16:36:03 -0700187 return getIncomingLink(new SwitchPort(dpid, number));
Yuta HIGUCHI8f3dfa32014-06-25 00:14:25 -0700188 }
189
190 @Override
191 public Link getIncomingLink(SwitchPort port) {
Yuta HIGUCHI8313f0b2014-07-09 16:36:03 -0700192 Map<String, Link> links = incomingLinks.get(port);
193 return getPacketLinkIfExists(links);
194 }
195
196 @Override
197 public Link getIncomingLink(Dpid dpid, PortNumber number, String type) {
198 return getIncomingLink(new SwitchPort(dpid, number), type);
199 }
200
201 @Override
202 public Link getIncomingLink(SwitchPort port, String type) {
203 Map<String, Link> links = incomingLinks.get(port);
204 return links.get(type);
205 }
206
207 @Override
208 public Collection<Link> getIncomingLinks(SwitchPort port) {
209 return Collections.unmodifiableCollection(incomingLinks.get(port).values());
Yuta HIGUCHI8f3dfa32014-06-25 00:14:25 -0700210 }
211
212 @Override
213 public Link getLink(Dpid srcDpid, PortNumber srcNumber,
214 Dpid dstDpid, PortNumber dstNumber) {
215
Yuta HIGUCHI8313f0b2014-07-09 16:36:03 -0700216 final SwitchPort dstSwitchPort = new SwitchPort(dstDpid, dstNumber);
217 Collection<Link> links = getOutgoingLinks(new SwitchPort(srcDpid, srcNumber));
218 for (Link link : links) {
219 if (link == null) {
220 continue;
221 }
222 if (link.getDstPort().asSwitchPort().equals(dstSwitchPort)) {
223 return link;
224 }
225 }
226 return null;
227 }
228
229 @Override
230 public Link getLink(Dpid srcDpid, PortNumber srcNumber,
231 Dpid dstDpid, PortNumber dstNumber,
232 String type) {
233
234 Link link = getOutgoingLink(srcDpid, srcNumber, type);
Ray Milkeyb29e6262014-04-09 16:02:14 -0700235 if (link == null) {
Ray Milkey269ffb92014-04-03 14:43:30 -0700236 return null;
Ray Milkeyb29e6262014-04-09 16:02:14 -0700237 }
238 if (!link.getDstSwitch().getDpid().equals(dstDpid)) {
Ray Milkey269ffb92014-04-03 14:43:30 -0700239 return null;
Ray Milkeyb29e6262014-04-09 16:02:14 -0700240 }
241 if (!link.getDstPort().getNumber().equals(dstNumber)) {
Ray Milkey269ffb92014-04-03 14:43:30 -0700242 return null;
Ray Milkeyb29e6262014-04-09 16:02:14 -0700243 }
Ray Milkey269ffb92014-04-03 14:43:30 -0700244 return link;
245 }
Pavlin Radoslavov7c8f69a2014-02-19 19:01:45 -0800246
Ray Milkey269ffb92014-04-03 14:43:30 -0700247 @Override
248 public Iterable<Link> getLinks() {
Yuta HIGUCHI8313f0b2014-07-09 16:36:03 -0700249 List<Link> links = new ArrayList<>();
250
251 for (Map<String, Link> portLinks : outgoingLinks.values()) {
252 links.addAll(portLinks.values());
253 }
254 return links;
Jonathan Hart25bd53e2014-04-30 23:44:09 -0700255 }
Toshio Koide2f570c12014-02-06 16:55:32 -0800256
Yuta HIGUCHI8313f0b2014-07-09 16:36:03 -0700257 @GuardedBy("topology.writeLock")
Jonathan Hart25bd53e2014-04-30 23:44:09 -0700258 protected void putLink(Link link) {
Yuta HIGUCHI8313f0b2014-07-09 16:36:03 -0700259 putLinkMap(outgoingLinks, link.getSrcPort().asSwitchPort(), link);
260 putLinkMap(incomingLinks, link.getDstPort().asSwitchPort(), link);
Jonathan Hart25bd53e2014-04-30 23:44:09 -0700261 }
262
Yuta HIGUCHI8313f0b2014-07-09 16:36:03 -0700263 /**
264 * Helper method to update outgoingLinks, incomingLinks.
265 *
266 * @param linkMap outgoingLinks or incomingLinks
267 * @param port Map key
268 * @param link Link to add
269 */
270 @GuardedBy("topology.writeLock")
271 private void putLinkMap(ConcurrentMap<SwitchPort, ConcurrentMap<String, Link>> linkMap,
272 SwitchPort port, Link link) {
273 ConcurrentMap<String, Link> portLinks = new ConcurrentHashMap<String, Link>(3);
274 portLinks.put(link.getType(), link);
275 Map<String, Link> existing = linkMap.putIfAbsent(
276 port,
277 portLinks);
278 if (existing != null) {
279 // no conditional update here
280 existing.put(link.getType(), link);
281 }
282 }
283
284 @GuardedBy("topology.writeLock")
Jonathan Hart25bd53e2014-04-30 23:44:09 -0700285 protected void removeLink(Link link) {
Yuta HIGUCHI8313f0b2014-07-09 16:36:03 -0700286 ConcurrentMap<String, Link> portLinks = outgoingLinks.get(link.getSrcPort().asSwitchPort());
287 if (portLinks != null) {
288 // no conditional update here
289 portLinks.remove(link.getType());
290 }
291 portLinks = incomingLinks.get(link.getDstPort().asSwitchPort());
292 if (portLinks != null) {
293 // no conditional update here
294 portLinks.remove(link.getType());
295 }
Ray Milkey269ffb92014-04-03 14:43:30 -0700296 }
Yuta HIGUCHI80829d12014-02-05 20:16:56 -0800297
Ray Milkey269ffb92014-04-03 14:43:30 -0700298 @Override
Yuta HIGUCHIbfc77f02014-07-14 22:50:25 -0700299 public Host getHostByMac(MACAddress address) {
300 return mac2Host.get(address);
Ray Milkey269ffb92014-04-03 14:43:30 -0700301 }
Pavlin Radoslavov6d224ee2014-02-18 16:43:15 -0800302
TeruU65bc5ff2014-04-23 22:22:32 -0700303 @Override
Yuta HIGUCHIbfc77f02014-07-14 22:50:25 -0700304 public Iterable<Host> getHosts() {
305 return Collections.unmodifiableCollection(mac2Host.values());
TeruU65bc5ff2014-04-23 22:22:32 -0700306 }
307
Yuta HIGUCHIfa742842014-07-03 22:35:13 -0700308 @Override
Yuta HIGUCHIbfc77f02014-07-14 22:50:25 -0700309 public Collection<Host> getHosts(SwitchPort port) {
310 return Collections.unmodifiableCollection(hosts.get(port));
Yuta HIGUCHIfa742842014-07-03 22:35:13 -0700311 }
312
313 // This method is expected to be serialized by writeLock.
314 // XXX new or updated device
Yuta HIGUCHIbfc77f02014-07-14 22:50:25 -0700315 protected void putHost(Host host) {
316 // assuming Host is immutable
317 Host oldHost = mac2Host.get(host.getMacAddress());
318 if (oldHost != null) {
Yuta HIGUCHIfa742842014-07-03 22:35:13 -0700319 // remove old attachment point
Yuta HIGUCHIbfc77f02014-07-14 22:50:25 -0700320 removeHost(oldHost);
Yuta HIGUCHIfa742842014-07-03 22:35:13 -0700321 }
322 // add new attachment points
Yuta HIGUCHIbfc77f02014-07-14 22:50:25 -0700323 for (Port port : host.getAttachmentPoints()) {
324 // TODO Won't need remove() if we define Host equality to reflect
Yuta HIGUCHIfa742842014-07-03 22:35:13 -0700325 // all of it's fields.
Yuta HIGUCHIbfc77f02014-07-14 22:50:25 -0700326 hosts.remove(port.asSwitchPort(), host);
327 hosts.put(port.asSwitchPort(), host);
Yuta HIGUCHIfa742842014-07-03 22:35:13 -0700328 }
Yuta HIGUCHIbfc77f02014-07-14 22:50:25 -0700329 mac2Host.put(host.getMacAddress(), host);
Ray Milkey269ffb92014-04-03 14:43:30 -0700330 }
Pavlin Radoslavov6d224ee2014-02-18 16:43:15 -0800331
Yuta HIGUCHIbfc77f02014-07-14 22:50:25 -0700332 protected void removeHost(Host host) {
333 for (Port port : host.getAttachmentPoints()) {
334 hosts.remove(port.asSwitchPort(), host);
Yuta HIGUCHIfa742842014-07-03 22:35:13 -0700335 }
Yuta HIGUCHIbfc77f02014-07-14 22:50:25 -0700336 mac2Host.remove(host.getMacAddress());
Ray Milkey269ffb92014-04-03 14:43:30 -0700337 }
Jonathan Hart26f291b2014-02-18 16:57:24 -0800338
Ray Milkey269ffb92014-04-03 14:43:30 -0700339 @Override
340 public void acquireReadLock() {
341 readLock.lock();
342 }
Jonathan Hart26f291b2014-02-18 16:57:24 -0800343
Ray Milkey269ffb92014-04-03 14:43:30 -0700344 @Override
345 public void releaseReadLock() {
346 readLock.unlock();
347 }
Pavlin Radoslavov8ffb8bf2014-02-20 15:34:26 -0800348
Ray Milkey269ffb92014-04-03 14:43:30 -0700349 protected void acquireWriteLock() {
350 writeLock.lock();
351 }
Pavlin Radoslavov8ffb8bf2014-02-20 15:34:26 -0800352
Ray Milkey269ffb92014-04-03 14:43:30 -0700353 protected void releaseWriteLock() {
354 writeLock.unlock();
355 }
Yuta HIGUCHI80829d12014-02-05 20:16:56 -0800356}