blob: 81f3041790375cb571e583c465abf565f67b3fe8 [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
38 // Index from Port to Device
39 private final Multimap<SwitchPort, Device> devices;
Jonathan Hart25bd53e2014-04-30 23:44:09 -070040 private final ConcurrentMap<MACAddress, Device> mac2Device;
41
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<>();
55 devices = Multimaps.synchronizedMultimap(
56 HashMultimap.<SwitchPort, Device>create());
Ray Milkey269ffb92014-04-03 14:43:30 -070057 mac2Device = 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 // TODO remove me when ready
Ray Milkey269ffb92014-04-03 14:43:30 -070075 protected void removeSwitch(Long dpid) {
Yuta HIGUCHIfa742842014-07-03 22:35:13 -070076 removeSwitch(new Dpid(dpid));
Yuta HIGUCHI8f3dfa32014-06-25 00:14:25 -070077 }
78
Yuta HIGUCHIfa742842014-07-03 22:35:13 -070079 // XXX Will remove ports in snapshot as side-effect.
Yuta HIGUCHI8f3dfa32014-06-25 00:14:25 -070080 protected void removeSwitch(Dpid dpid) {
Ray Milkey269ffb92014-04-03 14:43:30 -070081 switches.remove(dpid);
Yuta HIGUCHIfa742842014-07-03 22:35:13 -070082 ports.remove(dpid);
83 }
84
85 // This method is expected to be serialized by writeLock.
86 protected void putPort(Port port) {
87 ConcurrentMap<PortNumber, Port> portMap = ports.get(port.getDpid());
88 if (portMap == null) {
89 portMap = new ConcurrentHashMap<>();
90 ConcurrentMap<PortNumber, Port> existing =
91 ports.putIfAbsent(port.getDpid(), portMap);
92 if (existing != null) {
93 // port map was added concurrently, using theirs
94 portMap = existing;
95 }
96 }
97 portMap.put(port.getNumber(), port);
98 }
99
100 protected void removePort(Port port) {
101 ConcurrentMap<PortNumber, Port> portMap = ports.get(port.getDpid());
102 if (portMap != null) {
103 portMap.remove(port.getNumber());
104 }
Ray Milkey269ffb92014-04-03 14:43:30 -0700105 }
Pavlin Radoslavov6d224ee2014-02-18 16:43:15 -0800106
Ray Milkey269ffb92014-04-03 14:43:30 -0700107 @Override
108 public Iterable<Switch> getSwitches() {
109 // TODO Check if it is safe to directly return this Object.
110 return Collections.unmodifiableCollection(switches.values());
111 }
Yuta HIGUCHI80829d12014-02-05 20:16:56 -0800112
Ray Milkey269ffb92014-04-03 14:43:30 -0700113 @Override
Yuta HIGUCHI8f3dfa32014-06-25 00:14:25 -0700114 public Port getPort(Dpid dpid, PortNumber number) {
Yuta HIGUCHIfa742842014-07-03 22:35:13 -0700115 ConcurrentMap<PortNumber, Port> portMap = ports.get(dpid);
116 if (portMap != null) {
117 return portMap.get(number);
Ray Milkey269ffb92014-04-03 14:43:30 -0700118 }
119 return null;
120 }
Pavlin Radoslavov06df22a2014-02-18 19:16:27 -0800121
Ray Milkey269ffb92014-04-03 14:43:30 -0700122 @Override
Yuta HIGUCHI8f3dfa32014-06-25 00:14:25 -0700123 public Port getPort(SwitchPort port) {
124 return getPort(port.dpid(), port.port());
Jonathan Hart25bd53e2014-04-30 23:44:09 -0700125 }
126
127 @Override
Yuta HIGUCHIfa742842014-07-03 22:35:13 -0700128 public Collection<Port> getPorts(Dpid dpid) {
129 ConcurrentMap<PortNumber, Port> portMap = ports.get(dpid);
130 if (portMap == null) {
131 return Collections.emptyList();
132 }
133 return Collections.unmodifiableCollection(portMap.values());
134 }
135
136 @Override
Yuta HIGUCHI8f3dfa32014-06-25 00:14:25 -0700137 public Link getOutgoingLink(Dpid dpid, PortNumber number) {
Yuta HIGUCHI8313f0b2014-07-09 16:36:03 -0700138 return getOutgoingLink(new SwitchPort(dpid, number));
Ray Milkey269ffb92014-04-03 14:43:30 -0700139 }
Pavlin Radoslavov7c8f69a2014-02-19 19:01:45 -0800140
Ray Milkey269ffb92014-04-03 14:43:30 -0700141 @Override
Yuta HIGUCHI8f3dfa32014-06-25 00:14:25 -0700142 public Link getOutgoingLink(SwitchPort port) {
Yuta HIGUCHI8313f0b2014-07-09 16:36:03 -0700143 Map<String, Link> links = outgoingLinks.get(port);
144 return getPacketLinkIfExists(links);
145 }
146
147 // TODO remove when we no longer need packet fall back behavior
148 /**
149 * Gets the "packet" link if such exists, if not return whatever found.
150 *
151 * @param links Collection of links to search from
152 * @return Link instance found or null if no link exists
153 */
154 private Link getPacketLinkIfExists(Map<String, Link> links) {
155
156 if (links == null) {
157 return null;
158 }
159
Yuta HIGUCHIdbc33122014-07-10 13:32:32 -0700160 Link link = links.get(TopologyElement.TYPE_PACKET_LAYER);
Yuta HIGUCHI8313f0b2014-07-09 16:36:03 -0700161 if (link != null) {
162 // return packet link
163 return link;
164 } else {
165 // return whatever found
166 Iterator<Link> it = links.values().iterator();
167 if (it.hasNext()) {
168 return it.next();
169 }
170 }
171 return null;
172 }
173
174 @Override
175 public Link getOutgoingLink(Dpid dpid, PortNumber number, String type) {
176 return getOutgoingLink(new SwitchPort(dpid, number), type);
177 }
178
179 @Override
180 public Link getOutgoingLink(SwitchPort port, String type) {
181 Map<String, Link> links = outgoingLinks.get(port);
182 return links.get(type);
183 }
184
185 @Override
186 public Collection<Link> getOutgoingLinks(SwitchPort port) {
187 return Collections.unmodifiableCollection(outgoingLinks.get(port).values());
Yuta HIGUCHI8f3dfa32014-06-25 00:14:25 -0700188 }
189
190 @Override
191 public Link getIncomingLink(Dpid dpid, PortNumber number) {
Yuta HIGUCHI8313f0b2014-07-09 16:36:03 -0700192 return getIncomingLink(new SwitchPort(dpid, number));
Yuta HIGUCHI8f3dfa32014-06-25 00:14:25 -0700193 }
194
195 @Override
196 public Link getIncomingLink(SwitchPort port) {
Yuta HIGUCHI8313f0b2014-07-09 16:36:03 -0700197 Map<String, Link> links = incomingLinks.get(port);
198 return getPacketLinkIfExists(links);
199 }
200
201 @Override
202 public Link getIncomingLink(Dpid dpid, PortNumber number, String type) {
203 return getIncomingLink(new SwitchPort(dpid, number), type);
204 }
205
206 @Override
207 public Link getIncomingLink(SwitchPort port, String type) {
208 Map<String, Link> links = incomingLinks.get(port);
209 return links.get(type);
210 }
211
212 @Override
213 public Collection<Link> getIncomingLinks(SwitchPort port) {
214 return Collections.unmodifiableCollection(incomingLinks.get(port).values());
Yuta HIGUCHI8f3dfa32014-06-25 00:14:25 -0700215 }
216
217 @Override
218 public Link getLink(Dpid srcDpid, PortNumber srcNumber,
219 Dpid dstDpid, PortNumber dstNumber) {
220
Yuta HIGUCHI8313f0b2014-07-09 16:36:03 -0700221 final SwitchPort dstSwitchPort = new SwitchPort(dstDpid, dstNumber);
222 Collection<Link> links = getOutgoingLinks(new SwitchPort(srcDpid, srcNumber));
223 for (Link link : links) {
224 if (link == null) {
225 continue;
226 }
227 if (link.getDstPort().asSwitchPort().equals(dstSwitchPort)) {
228 return link;
229 }
230 }
231 return null;
232 }
233
234 @Override
235 public Link getLink(Dpid srcDpid, PortNumber srcNumber,
236 Dpid dstDpid, PortNumber dstNumber,
237 String type) {
238
239 Link link = getOutgoingLink(srcDpid, srcNumber, type);
Ray Milkeyb29e6262014-04-09 16:02:14 -0700240 if (link == null) {
Ray Milkey269ffb92014-04-03 14:43:30 -0700241 return null;
Ray Milkeyb29e6262014-04-09 16:02:14 -0700242 }
243 if (!link.getDstSwitch().getDpid().equals(dstDpid)) {
Ray Milkey269ffb92014-04-03 14:43:30 -0700244 return null;
Ray Milkeyb29e6262014-04-09 16:02:14 -0700245 }
246 if (!link.getDstPort().getNumber().equals(dstNumber)) {
Ray Milkey269ffb92014-04-03 14:43:30 -0700247 return null;
Ray Milkeyb29e6262014-04-09 16:02:14 -0700248 }
Ray Milkey269ffb92014-04-03 14:43:30 -0700249 return link;
250 }
Pavlin Radoslavov7c8f69a2014-02-19 19:01:45 -0800251
Ray Milkey269ffb92014-04-03 14:43:30 -0700252 @Override
253 public Iterable<Link> getLinks() {
Yuta HIGUCHI8313f0b2014-07-09 16:36:03 -0700254 List<Link> links = new ArrayList<>();
255
256 for (Map<String, Link> portLinks : outgoingLinks.values()) {
257 links.addAll(portLinks.values());
258 }
259 return links;
Jonathan Hart25bd53e2014-04-30 23:44:09 -0700260 }
Toshio Koide2f570c12014-02-06 16:55:32 -0800261
Yuta HIGUCHI8313f0b2014-07-09 16:36:03 -0700262 @GuardedBy("topology.writeLock")
Jonathan Hart25bd53e2014-04-30 23:44:09 -0700263 protected void putLink(Link link) {
Yuta HIGUCHI8313f0b2014-07-09 16:36:03 -0700264 putLinkMap(outgoingLinks, link.getSrcPort().asSwitchPort(), link);
265 putLinkMap(incomingLinks, link.getDstPort().asSwitchPort(), link);
Jonathan Hart25bd53e2014-04-30 23:44:09 -0700266 }
267
Yuta HIGUCHI8313f0b2014-07-09 16:36:03 -0700268 /**
269 * Helper method to update outgoingLinks, incomingLinks.
270 *
271 * @param linkMap outgoingLinks or incomingLinks
272 * @param port Map key
273 * @param link Link to add
274 */
275 @GuardedBy("topology.writeLock")
276 private void putLinkMap(ConcurrentMap<SwitchPort, ConcurrentMap<String, Link>> linkMap,
277 SwitchPort port, Link link) {
278 ConcurrentMap<String, Link> portLinks = new ConcurrentHashMap<String, Link>(3);
279 portLinks.put(link.getType(), link);
280 Map<String, Link> existing = linkMap.putIfAbsent(
281 port,
282 portLinks);
283 if (existing != null) {
284 // no conditional update here
285 existing.put(link.getType(), link);
286 }
287 }
288
289 @GuardedBy("topology.writeLock")
Jonathan Hart25bd53e2014-04-30 23:44:09 -0700290 protected void removeLink(Link link) {
Yuta HIGUCHI8313f0b2014-07-09 16:36:03 -0700291 ConcurrentMap<String, Link> portLinks = outgoingLinks.get(link.getSrcPort().asSwitchPort());
292 if (portLinks != null) {
293 // no conditional update here
294 portLinks.remove(link.getType());
295 }
296 portLinks = incomingLinks.get(link.getDstPort().asSwitchPort());
297 if (portLinks != null) {
298 // no conditional update here
299 portLinks.remove(link.getType());
300 }
Ray Milkey269ffb92014-04-03 14:43:30 -0700301 }
Yuta HIGUCHI80829d12014-02-05 20:16:56 -0800302
Ray Milkey269ffb92014-04-03 14:43:30 -0700303 @Override
Ray Milkey269ffb92014-04-03 14:43:30 -0700304 public Device getDeviceByMac(MACAddress address) {
305 return mac2Device.get(address);
306 }
Pavlin Radoslavov6d224ee2014-02-18 16:43:15 -0800307
TeruU65bc5ff2014-04-23 22:22:32 -0700308 @Override
309 public Iterable<Device> getDevices() {
310 return Collections.unmodifiableCollection(mac2Device.values());
311 }
312
Yuta HIGUCHIfa742842014-07-03 22:35:13 -0700313 @Override
314 public Collection<Device> getDevices(SwitchPort port) {
315 return Collections.unmodifiableCollection(devices.get(port));
316 }
317
318 // This method is expected to be serialized by writeLock.
319 // XXX new or updated device
Ray Milkey269ffb92014-04-03 14:43:30 -0700320 protected void putDevice(Device device) {
Yuta HIGUCHIfa742842014-07-03 22:35:13 -0700321 // assuming Device is immutable
322 Device oldDevice = mac2Device.get(device.getMacAddress());
323 if (oldDevice != null) {
324 // remove old attachment point
325 removeDevice(oldDevice);
326 }
327 // add new attachment points
328 for (Port port : device.getAttachmentPoints()) {
329 // TODO Won't need remove() if we define Device equality to reflect
330 // all of it's fields.
331 devices.remove(port.asSwitchPort(), device);
332 devices.put(port.asSwitchPort(), device);
333 }
Ray Milkey269ffb92014-04-03 14:43:30 -0700334 mac2Device.put(device.getMacAddress(), device);
Ray Milkey269ffb92014-04-03 14:43:30 -0700335 }
Pavlin Radoslavov6d224ee2014-02-18 16:43:15 -0800336
Ray Milkey269ffb92014-04-03 14:43:30 -0700337 protected void removeDevice(Device device) {
Yuta HIGUCHIfa742842014-07-03 22:35:13 -0700338 for (Port port : device.getAttachmentPoints()) {
339 devices.remove(port.asSwitchPort(), device);
340 }
Ray Milkey269ffb92014-04-03 14:43:30 -0700341 mac2Device.remove(device.getMacAddress());
Ray Milkey269ffb92014-04-03 14:43:30 -0700342 }
Jonathan Hart26f291b2014-02-18 16:57:24 -0800343
Ray Milkey269ffb92014-04-03 14:43:30 -0700344 @Override
345 public void acquireReadLock() {
346 readLock.lock();
347 }
Jonathan Hart26f291b2014-02-18 16:57:24 -0800348
Ray Milkey269ffb92014-04-03 14:43:30 -0700349 @Override
350 public void releaseReadLock() {
351 readLock.unlock();
352 }
Pavlin Radoslavov8ffb8bf2014-02-20 15:34:26 -0800353
Ray Milkey269ffb92014-04-03 14:43:30 -0700354 protected void acquireWriteLock() {
355 writeLock.lock();
356 }
Pavlin Radoslavov8ffb8bf2014-02-20 15:34:26 -0800357
Ray Milkey269ffb92014-04-03 14:43:30 -0700358 protected void releaseWriteLock() {
359 writeLock.unlock();
360 }
Yuta HIGUCHI80829d12014-02-05 20:16:56 -0800361}