Jonathan Hart | 472062d | 2014-04-03 10:56:48 -0700 | [diff] [blame] | 1 | package net.onrc.onos.core.topology; |
Yuta HIGUCHI | 80829d1 | 2014-02-05 20:16:56 -0800 | [diff] [blame] | 2 | |
Yuta HIGUCHI | 8313f0b | 2014-07-09 16:36:03 -0700 | [diff] [blame^] | 3 | import java.util.ArrayList; |
Yuta HIGUCHI | fa74284 | 2014-07-03 22:35:13 -0700 | [diff] [blame] | 4 | import java.util.Collection; |
Yuta HIGUCHI | 80829d1 | 2014-02-05 20:16:56 -0800 | [diff] [blame] | 5 | import java.util.Collections; |
Yuta HIGUCHI | 8313f0b | 2014-07-09 16:36:03 -0700 | [diff] [blame^] | 6 | import java.util.Iterator; |
| 7 | import java.util.List; |
| 8 | import java.util.Map; |
Yuta HIGUCHI | 80829d1 | 2014-02-05 20:16:56 -0800 | [diff] [blame] | 9 | import java.util.concurrent.ConcurrentHashMap; |
| 10 | import java.util.concurrent.ConcurrentMap; |
Jonathan Hart | 26f291b | 2014-02-18 16:57:24 -0800 | [diff] [blame] | 11 | import java.util.concurrent.locks.Lock; |
| 12 | import java.util.concurrent.locks.ReadWriteLock; |
| 13 | import java.util.concurrent.locks.ReentrantReadWriteLock; |
Yuta HIGUCHI | 80829d1 | 2014-02-05 20:16:56 -0800 | [diff] [blame] | 14 | |
Yuta HIGUCHI | 8313f0b | 2014-07-09 16:36:03 -0700 | [diff] [blame^] | 15 | import javax.annotation.concurrent.GuardedBy; |
| 16 | |
Yuta HIGUCHI | 80829d1 | 2014-02-05 20:16:56 -0800 | [diff] [blame] | 17 | import net.floodlightcontroller.util.MACAddress; |
Yuta HIGUCHI | 8f3dfa3 | 2014-06-25 00:14:25 -0700 | [diff] [blame] | 18 | import net.onrc.onos.core.util.Dpid; |
| 19 | import net.onrc.onos.core.util.PortNumber; |
Jonathan Hart | 25bd53e | 2014-04-30 23:44:09 -0700 | [diff] [blame] | 20 | import net.onrc.onos.core.util.SwitchPort; |
Yuta HIGUCHI | 80829d1 | 2014-02-05 20:16:56 -0800 | [diff] [blame] | 21 | |
| 22 | import org.slf4j.Logger; |
| 23 | import org.slf4j.LoggerFactory; |
| 24 | |
Yuta HIGUCHI | fa74284 | 2014-07-03 22:35:13 -0700 | [diff] [blame] | 25 | import com.google.common.collect.HashMultimap; |
| 26 | import com.google.common.collect.Multimap; |
| 27 | import com.google.common.collect.Multimaps; |
| 28 | |
Jonathan Hart | e37e4e2 | 2014-05-13 19:12:02 -0700 | [diff] [blame] | 29 | public class TopologyImpl implements Topology { |
Ray Milkey | 269ffb9 | 2014-04-03 14:43:30 -0700 | [diff] [blame] | 30 | @SuppressWarnings("unused") |
Jonathan Hart | e37e4e2 | 2014-05-13 19:12:02 -0700 | [diff] [blame] | 31 | private static final Logger log = LoggerFactory.getLogger(TopologyImpl.class); |
Yuta HIGUCHI | 80829d1 | 2014-02-05 20:16:56 -0800 | [diff] [blame] | 32 | |
Ray Milkey | 269ffb9 | 2014-04-03 14:43:30 -0700 | [diff] [blame] | 33 | // DPID -> Switch |
Yuta HIGUCHI | 8f3dfa3 | 2014-06-25 00:14:25 -0700 | [diff] [blame] | 34 | private final ConcurrentMap<Dpid, Switch> switches; |
Yuta HIGUCHI | fa74284 | 2014-07-03 22:35:13 -0700 | [diff] [blame] | 35 | // 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 Hart | 25bd53e | 2014-04-30 23:44:09 -0700 | [diff] [blame] | 40 | private final ConcurrentMap<MACAddress, Device> mac2Device; |
| 41 | |
Yuta HIGUCHI | 8313f0b | 2014-07-09 16:36:03 -0700 | [diff] [blame^] | 42 | // SwitchPort -> (type -> Link) |
| 43 | private final ConcurrentMap<SwitchPort, ConcurrentMap<String, Link>> outgoingLinks; |
| 44 | private final ConcurrentMap<SwitchPort, ConcurrentMap<String, Link>> incomingLinks; |
Yuta HIGUCHI | 5d2d8d4 | 2014-02-20 22:22:53 -0800 | [diff] [blame] | 45 | |
Ray Milkey | 269ffb9 | 2014-04-03 14:43:30 -0700 | [diff] [blame] | 46 | 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 HIGUCHI | 80829d1 | 2014-02-05 20:16:56 -0800 | [diff] [blame] | 50 | |
Jonathan Hart | e37e4e2 | 2014-05-13 19:12:02 -0700 | [diff] [blame] | 51 | public TopologyImpl() { |
Ray Milkey | 269ffb9 | 2014-04-03 14:43:30 -0700 | [diff] [blame] | 52 | // TODO: Does these object need to be stored in Concurrent Collection? |
| 53 | switches = new ConcurrentHashMap<>(); |
Yuta HIGUCHI | fa74284 | 2014-07-03 22:35:13 -0700 | [diff] [blame] | 54 | ports = new ConcurrentHashMap<>(); |
| 55 | devices = Multimaps.synchronizedMultimap( |
| 56 | HashMultimap.<SwitchPort, Device>create()); |
Ray Milkey | 269ffb9 | 2014-04-03 14:43:30 -0700 | [diff] [blame] | 57 | mac2Device = new ConcurrentHashMap<>(); |
Jonathan Hart | 25bd53e | 2014-04-30 23:44:09 -0700 | [diff] [blame] | 58 | outgoingLinks = new ConcurrentHashMap<>(); |
| 59 | incomingLinks = new ConcurrentHashMap<>(); |
Ray Milkey | 269ffb9 | 2014-04-03 14:43:30 -0700 | [diff] [blame] | 60 | } |
Yuta HIGUCHI | 80829d1 | 2014-02-05 20:16:56 -0800 | [diff] [blame] | 61 | |
Ray Milkey | 269ffb9 | 2014-04-03 14:43:30 -0700 | [diff] [blame] | 62 | @Override |
Yuta HIGUCHI | 8f3dfa3 | 2014-06-25 00:14:25 -0700 | [diff] [blame] | 63 | public Switch getSwitch(Dpid dpid) { |
Ray Milkey | 269ffb9 | 2014-04-03 14:43:30 -0700 | [diff] [blame] | 64 | // TODO Check if it is safe to directly return this Object. |
| 65 | return switches.get(dpid); |
| 66 | } |
Yuta HIGUCHI | 80829d1 | 2014-02-05 20:16:56 -0800 | [diff] [blame] | 67 | |
Yuta HIGUCHI | fa74284 | 2014-07-03 22:35:13 -0700 | [diff] [blame] | 68 | // Only add switch. |
Ray Milkey | 269ffb9 | 2014-04-03 14:43:30 -0700 | [diff] [blame] | 69 | protected void putSwitch(Switch sw) { |
| 70 | switches.put(sw.getDpid(), sw); |
Yuta HIGUCHI | fa74284 | 2014-07-03 22:35:13 -0700 | [diff] [blame] | 71 | ports.putIfAbsent(sw.getDpid(), new ConcurrentHashMap<PortNumber, Port>()); |
Ray Milkey | 269ffb9 | 2014-04-03 14:43:30 -0700 | [diff] [blame] | 72 | } |
Pavlin Radoslavov | 6d224ee | 2014-02-18 16:43:15 -0800 | [diff] [blame] | 73 | |
Yuta HIGUCHI | fa74284 | 2014-07-03 22:35:13 -0700 | [diff] [blame] | 74 | // TODO remove me when ready |
Ray Milkey | 269ffb9 | 2014-04-03 14:43:30 -0700 | [diff] [blame] | 75 | protected void removeSwitch(Long dpid) { |
Yuta HIGUCHI | fa74284 | 2014-07-03 22:35:13 -0700 | [diff] [blame] | 76 | removeSwitch(new Dpid(dpid)); |
Yuta HIGUCHI | 8f3dfa3 | 2014-06-25 00:14:25 -0700 | [diff] [blame] | 77 | } |
| 78 | |
Yuta HIGUCHI | fa74284 | 2014-07-03 22:35:13 -0700 | [diff] [blame] | 79 | // XXX Will remove ports in snapshot as side-effect. |
Yuta HIGUCHI | 8f3dfa3 | 2014-06-25 00:14:25 -0700 | [diff] [blame] | 80 | protected void removeSwitch(Dpid dpid) { |
Ray Milkey | 269ffb9 | 2014-04-03 14:43:30 -0700 | [diff] [blame] | 81 | switches.remove(dpid); |
Yuta HIGUCHI | fa74284 | 2014-07-03 22:35:13 -0700 | [diff] [blame] | 82 | 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 Milkey | 269ffb9 | 2014-04-03 14:43:30 -0700 | [diff] [blame] | 105 | } |
Pavlin Radoslavov | 6d224ee | 2014-02-18 16:43:15 -0800 | [diff] [blame] | 106 | |
Ray Milkey | 269ffb9 | 2014-04-03 14:43:30 -0700 | [diff] [blame] | 107 | @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 HIGUCHI | 80829d1 | 2014-02-05 20:16:56 -0800 | [diff] [blame] | 112 | |
Ray Milkey | 269ffb9 | 2014-04-03 14:43:30 -0700 | [diff] [blame] | 113 | @Override |
Yuta HIGUCHI | 8f3dfa3 | 2014-06-25 00:14:25 -0700 | [diff] [blame] | 114 | public Port getPort(Dpid dpid, PortNumber number) { |
Yuta HIGUCHI | fa74284 | 2014-07-03 22:35:13 -0700 | [diff] [blame] | 115 | ConcurrentMap<PortNumber, Port> portMap = ports.get(dpid); |
| 116 | if (portMap != null) { |
| 117 | return portMap.get(number); |
Ray Milkey | 269ffb9 | 2014-04-03 14:43:30 -0700 | [diff] [blame] | 118 | } |
| 119 | return null; |
| 120 | } |
Pavlin Radoslavov | 06df22a | 2014-02-18 19:16:27 -0800 | [diff] [blame] | 121 | |
Ray Milkey | 269ffb9 | 2014-04-03 14:43:30 -0700 | [diff] [blame] | 122 | @Override |
Yuta HIGUCHI | 8f3dfa3 | 2014-06-25 00:14:25 -0700 | [diff] [blame] | 123 | public Port getPort(SwitchPort port) { |
| 124 | return getPort(port.dpid(), port.port()); |
Jonathan Hart | 25bd53e | 2014-04-30 23:44:09 -0700 | [diff] [blame] | 125 | } |
| 126 | |
| 127 | @Override |
Yuta HIGUCHI | fa74284 | 2014-07-03 22:35:13 -0700 | [diff] [blame] | 128 | 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 HIGUCHI | 8f3dfa3 | 2014-06-25 00:14:25 -0700 | [diff] [blame] | 137 | public Link getOutgoingLink(Dpid dpid, PortNumber number) { |
Yuta HIGUCHI | 8313f0b | 2014-07-09 16:36:03 -0700 | [diff] [blame^] | 138 | return getOutgoingLink(new SwitchPort(dpid, number)); |
Ray Milkey | 269ffb9 | 2014-04-03 14:43:30 -0700 | [diff] [blame] | 139 | } |
Pavlin Radoslavov | 7c8f69a | 2014-02-19 19:01:45 -0800 | [diff] [blame] | 140 | |
Ray Milkey | 269ffb9 | 2014-04-03 14:43:30 -0700 | [diff] [blame] | 141 | @Override |
Yuta HIGUCHI | 8f3dfa3 | 2014-06-25 00:14:25 -0700 | [diff] [blame] | 142 | public Link getOutgoingLink(SwitchPort port) { |
Yuta HIGUCHI | 8313f0b | 2014-07-09 16:36:03 -0700 | [diff] [blame^] | 143 | 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 | |
| 160 | Link link = links.get(TopologyElement.TYPE_PACKET); |
| 161 | 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 HIGUCHI | 8f3dfa3 | 2014-06-25 00:14:25 -0700 | [diff] [blame] | 188 | } |
| 189 | |
| 190 | @Override |
| 191 | public Link getIncomingLink(Dpid dpid, PortNumber number) { |
Yuta HIGUCHI | 8313f0b | 2014-07-09 16:36:03 -0700 | [diff] [blame^] | 192 | return getIncomingLink(new SwitchPort(dpid, number)); |
Yuta HIGUCHI | 8f3dfa3 | 2014-06-25 00:14:25 -0700 | [diff] [blame] | 193 | } |
| 194 | |
| 195 | @Override |
| 196 | public Link getIncomingLink(SwitchPort port) { |
Yuta HIGUCHI | 8313f0b | 2014-07-09 16:36:03 -0700 | [diff] [blame^] | 197 | 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 HIGUCHI | 8f3dfa3 | 2014-06-25 00:14:25 -0700 | [diff] [blame] | 215 | } |
| 216 | |
| 217 | @Override |
| 218 | public Link getLink(Dpid srcDpid, PortNumber srcNumber, |
| 219 | Dpid dstDpid, PortNumber dstNumber) { |
| 220 | |
Yuta HIGUCHI | 8313f0b | 2014-07-09 16:36:03 -0700 | [diff] [blame^] | 221 | 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 Milkey | b29e626 | 2014-04-09 16:02:14 -0700 | [diff] [blame] | 240 | if (link == null) { |
Ray Milkey | 269ffb9 | 2014-04-03 14:43:30 -0700 | [diff] [blame] | 241 | return null; |
Ray Milkey | b29e626 | 2014-04-09 16:02:14 -0700 | [diff] [blame] | 242 | } |
| 243 | if (!link.getDstSwitch().getDpid().equals(dstDpid)) { |
Ray Milkey | 269ffb9 | 2014-04-03 14:43:30 -0700 | [diff] [blame] | 244 | return null; |
Ray Milkey | b29e626 | 2014-04-09 16:02:14 -0700 | [diff] [blame] | 245 | } |
| 246 | if (!link.getDstPort().getNumber().equals(dstNumber)) { |
Ray Milkey | 269ffb9 | 2014-04-03 14:43:30 -0700 | [diff] [blame] | 247 | return null; |
Ray Milkey | b29e626 | 2014-04-09 16:02:14 -0700 | [diff] [blame] | 248 | } |
Ray Milkey | 269ffb9 | 2014-04-03 14:43:30 -0700 | [diff] [blame] | 249 | return link; |
| 250 | } |
Pavlin Radoslavov | 7c8f69a | 2014-02-19 19:01:45 -0800 | [diff] [blame] | 251 | |
Ray Milkey | 269ffb9 | 2014-04-03 14:43:30 -0700 | [diff] [blame] | 252 | @Override |
| 253 | public Iterable<Link> getLinks() { |
Yuta HIGUCHI | 8313f0b | 2014-07-09 16:36:03 -0700 | [diff] [blame^] | 254 | List<Link> links = new ArrayList<>(); |
| 255 | |
| 256 | for (Map<String, Link> portLinks : outgoingLinks.values()) { |
| 257 | links.addAll(portLinks.values()); |
| 258 | } |
| 259 | return links; |
Jonathan Hart | 25bd53e | 2014-04-30 23:44:09 -0700 | [diff] [blame] | 260 | } |
Toshio Koide | 2f570c1 | 2014-02-06 16:55:32 -0800 | [diff] [blame] | 261 | |
Yuta HIGUCHI | 8313f0b | 2014-07-09 16:36:03 -0700 | [diff] [blame^] | 262 | @GuardedBy("topology.writeLock") |
Jonathan Hart | 25bd53e | 2014-04-30 23:44:09 -0700 | [diff] [blame] | 263 | protected void putLink(Link link) { |
Yuta HIGUCHI | 8313f0b | 2014-07-09 16:36:03 -0700 | [diff] [blame^] | 264 | putLinkMap(outgoingLinks, link.getSrcPort().asSwitchPort(), link); |
| 265 | putLinkMap(incomingLinks, link.getDstPort().asSwitchPort(), link); |
Jonathan Hart | 25bd53e | 2014-04-30 23:44:09 -0700 | [diff] [blame] | 266 | } |
| 267 | |
Yuta HIGUCHI | 8313f0b | 2014-07-09 16:36:03 -0700 | [diff] [blame^] | 268 | /** |
| 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 Hart | 25bd53e | 2014-04-30 23:44:09 -0700 | [diff] [blame] | 290 | protected void removeLink(Link link) { |
Yuta HIGUCHI | 8313f0b | 2014-07-09 16:36:03 -0700 | [diff] [blame^] | 291 | 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 Milkey | 269ffb9 | 2014-04-03 14:43:30 -0700 | [diff] [blame] | 301 | } |
Yuta HIGUCHI | 80829d1 | 2014-02-05 20:16:56 -0800 | [diff] [blame] | 302 | |
Ray Milkey | 269ffb9 | 2014-04-03 14:43:30 -0700 | [diff] [blame] | 303 | @Override |
Ray Milkey | 269ffb9 | 2014-04-03 14:43:30 -0700 | [diff] [blame] | 304 | public Device getDeviceByMac(MACAddress address) { |
| 305 | return mac2Device.get(address); |
| 306 | } |
Pavlin Radoslavov | 6d224ee | 2014-02-18 16:43:15 -0800 | [diff] [blame] | 307 | |
TeruU | 65bc5ff | 2014-04-23 22:22:32 -0700 | [diff] [blame] | 308 | @Override |
| 309 | public Iterable<Device> getDevices() { |
| 310 | return Collections.unmodifiableCollection(mac2Device.values()); |
| 311 | } |
| 312 | |
Yuta HIGUCHI | fa74284 | 2014-07-03 22:35:13 -0700 | [diff] [blame] | 313 | @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 Milkey | 269ffb9 | 2014-04-03 14:43:30 -0700 | [diff] [blame] | 320 | protected void putDevice(Device device) { |
Yuta HIGUCHI | fa74284 | 2014-07-03 22:35:13 -0700 | [diff] [blame] | 321 | // 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 Milkey | 269ffb9 | 2014-04-03 14:43:30 -0700 | [diff] [blame] | 334 | mac2Device.put(device.getMacAddress(), device); |
Ray Milkey | 269ffb9 | 2014-04-03 14:43:30 -0700 | [diff] [blame] | 335 | } |
Pavlin Radoslavov | 6d224ee | 2014-02-18 16:43:15 -0800 | [diff] [blame] | 336 | |
Ray Milkey | 269ffb9 | 2014-04-03 14:43:30 -0700 | [diff] [blame] | 337 | protected void removeDevice(Device device) { |
Yuta HIGUCHI | fa74284 | 2014-07-03 22:35:13 -0700 | [diff] [blame] | 338 | for (Port port : device.getAttachmentPoints()) { |
| 339 | devices.remove(port.asSwitchPort(), device); |
| 340 | } |
Ray Milkey | 269ffb9 | 2014-04-03 14:43:30 -0700 | [diff] [blame] | 341 | mac2Device.remove(device.getMacAddress()); |
Ray Milkey | 269ffb9 | 2014-04-03 14:43:30 -0700 | [diff] [blame] | 342 | } |
Jonathan Hart | 26f291b | 2014-02-18 16:57:24 -0800 | [diff] [blame] | 343 | |
Ray Milkey | 269ffb9 | 2014-04-03 14:43:30 -0700 | [diff] [blame] | 344 | @Override |
| 345 | public void acquireReadLock() { |
| 346 | readLock.lock(); |
| 347 | } |
Jonathan Hart | 26f291b | 2014-02-18 16:57:24 -0800 | [diff] [blame] | 348 | |
Ray Milkey | 269ffb9 | 2014-04-03 14:43:30 -0700 | [diff] [blame] | 349 | @Override |
| 350 | public void releaseReadLock() { |
| 351 | readLock.unlock(); |
| 352 | } |
Pavlin Radoslavov | 8ffb8bf | 2014-02-20 15:34:26 -0800 | [diff] [blame] | 353 | |
Ray Milkey | 269ffb9 | 2014-04-03 14:43:30 -0700 | [diff] [blame] | 354 | protected void acquireWriteLock() { |
| 355 | writeLock.lock(); |
| 356 | } |
Pavlin Radoslavov | 8ffb8bf | 2014-02-20 15:34:26 -0800 | [diff] [blame] | 357 | |
Ray Milkey | 269ffb9 | 2014-04-03 14:43:30 -0700 | [diff] [blame] | 358 | protected void releaseWriteLock() { |
| 359 | writeLock.unlock(); |
| 360 | } |
Yuta HIGUCHI | 80829d1 | 2014-02-05 20:16:56 -0800 | [diff] [blame] | 361 | } |