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 | fa74284 | 2014-07-03 22:35:13 -0700 | [diff] [blame^] | 3 | import java.util.Collection; |
Yuta HIGUCHI | 80829d1 | 2014-02-05 20:16:56 -0800 | [diff] [blame] | 4 | import java.util.Collections; |
Yuta HIGUCHI | 80829d1 | 2014-02-05 20:16:56 -0800 | [diff] [blame] | 5 | import java.util.concurrent.ConcurrentHashMap; |
| 6 | import java.util.concurrent.ConcurrentMap; |
Jonathan Hart | 26f291b | 2014-02-18 16:57:24 -0800 | [diff] [blame] | 7 | import java.util.concurrent.locks.Lock; |
| 8 | import java.util.concurrent.locks.ReadWriteLock; |
| 9 | import java.util.concurrent.locks.ReentrantReadWriteLock; |
Yuta HIGUCHI | 80829d1 | 2014-02-05 20:16:56 -0800 | [diff] [blame] | 10 | |
| 11 | import net.floodlightcontroller.util.MACAddress; |
Yuta HIGUCHI | 8f3dfa3 | 2014-06-25 00:14:25 -0700 | [diff] [blame] | 12 | import net.onrc.onos.core.util.Dpid; |
| 13 | import net.onrc.onos.core.util.PortNumber; |
Jonathan Hart | 25bd53e | 2014-04-30 23:44:09 -0700 | [diff] [blame] | 14 | import net.onrc.onos.core.util.SwitchPort; |
Yuta HIGUCHI | 80829d1 | 2014-02-05 20:16:56 -0800 | [diff] [blame] | 15 | |
| 16 | import org.slf4j.Logger; |
| 17 | import org.slf4j.LoggerFactory; |
| 18 | |
Yuta HIGUCHI | fa74284 | 2014-07-03 22:35:13 -0700 | [diff] [blame^] | 19 | import com.google.common.collect.HashMultimap; |
| 20 | import com.google.common.collect.Multimap; |
| 21 | import com.google.common.collect.Multimaps; |
| 22 | |
Jonathan Hart | e37e4e2 | 2014-05-13 19:12:02 -0700 | [diff] [blame] | 23 | public class TopologyImpl implements Topology { |
Ray Milkey | 269ffb9 | 2014-04-03 14:43:30 -0700 | [diff] [blame] | 24 | @SuppressWarnings("unused") |
Jonathan Hart | e37e4e2 | 2014-05-13 19:12:02 -0700 | [diff] [blame] | 25 | private static final Logger log = LoggerFactory.getLogger(TopologyImpl.class); |
Yuta HIGUCHI | 80829d1 | 2014-02-05 20:16:56 -0800 | [diff] [blame] | 26 | |
Ray Milkey | 269ffb9 | 2014-04-03 14:43:30 -0700 | [diff] [blame] | 27 | // DPID -> Switch |
Yuta HIGUCHI | 8f3dfa3 | 2014-06-25 00:14:25 -0700 | [diff] [blame] | 28 | private final ConcurrentMap<Dpid, Switch> switches; |
Yuta HIGUCHI | fa74284 | 2014-07-03 22:35:13 -0700 | [diff] [blame^] | 29 | // XXX may need to be careful when shallow copying. |
| 30 | private final ConcurrentMap<Dpid, ConcurrentMap<PortNumber, Port>> ports; |
| 31 | |
| 32 | // Index from Port to Device |
| 33 | private final Multimap<SwitchPort, Device> devices; |
Jonathan Hart | 25bd53e | 2014-04-30 23:44:09 -0700 | [diff] [blame] | 34 | private final ConcurrentMap<MACAddress, Device> mac2Device; |
| 35 | |
| 36 | private final ConcurrentMap<SwitchPort, Link> outgoingLinks; |
| 37 | private final ConcurrentMap<SwitchPort, Link> incomingLinks; |
Yuta HIGUCHI | 5d2d8d4 | 2014-02-20 22:22:53 -0800 | [diff] [blame] | 38 | |
Ray Milkey | 269ffb9 | 2014-04-03 14:43:30 -0700 | [diff] [blame] | 39 | private ReadWriteLock readWriteLock = new ReentrantReadWriteLock(); |
| 40 | private Lock readLock = readWriteLock.readLock(); |
| 41 | // TODO use the write lock after refactor |
| 42 | private Lock writeLock = readWriteLock.writeLock(); |
Yuta HIGUCHI | 80829d1 | 2014-02-05 20:16:56 -0800 | [diff] [blame] | 43 | |
Jonathan Hart | e37e4e2 | 2014-05-13 19:12:02 -0700 | [diff] [blame] | 44 | public TopologyImpl() { |
Ray Milkey | 269ffb9 | 2014-04-03 14:43:30 -0700 | [diff] [blame] | 45 | // TODO: Does these object need to be stored in Concurrent Collection? |
| 46 | switches = new ConcurrentHashMap<>(); |
Yuta HIGUCHI | fa74284 | 2014-07-03 22:35:13 -0700 | [diff] [blame^] | 47 | ports = new ConcurrentHashMap<>(); |
| 48 | devices = Multimaps.synchronizedMultimap( |
| 49 | HashMultimap.<SwitchPort, Device>create()); |
Ray Milkey | 269ffb9 | 2014-04-03 14:43:30 -0700 | [diff] [blame] | 50 | mac2Device = new ConcurrentHashMap<>(); |
Jonathan Hart | 25bd53e | 2014-04-30 23:44:09 -0700 | [diff] [blame] | 51 | outgoingLinks = new ConcurrentHashMap<>(); |
| 52 | incomingLinks = new ConcurrentHashMap<>(); |
Ray Milkey | 269ffb9 | 2014-04-03 14:43:30 -0700 | [diff] [blame] | 53 | } |
Yuta HIGUCHI | 80829d1 | 2014-02-05 20:16:56 -0800 | [diff] [blame] | 54 | |
Ray Milkey | 269ffb9 | 2014-04-03 14:43:30 -0700 | [diff] [blame] | 55 | @Override |
Yuta HIGUCHI | 8f3dfa3 | 2014-06-25 00:14:25 -0700 | [diff] [blame] | 56 | public Switch getSwitch(Dpid dpid) { |
Ray Milkey | 269ffb9 | 2014-04-03 14:43:30 -0700 | [diff] [blame] | 57 | // TODO Check if it is safe to directly return this Object. |
| 58 | return switches.get(dpid); |
| 59 | } |
Yuta HIGUCHI | 80829d1 | 2014-02-05 20:16:56 -0800 | [diff] [blame] | 60 | |
Yuta HIGUCHI | fa74284 | 2014-07-03 22:35:13 -0700 | [diff] [blame^] | 61 | // Only add switch. |
Ray Milkey | 269ffb9 | 2014-04-03 14:43:30 -0700 | [diff] [blame] | 62 | protected void putSwitch(Switch sw) { |
| 63 | switches.put(sw.getDpid(), sw); |
Yuta HIGUCHI | fa74284 | 2014-07-03 22:35:13 -0700 | [diff] [blame^] | 64 | ports.putIfAbsent(sw.getDpid(), new ConcurrentHashMap<PortNumber, Port>()); |
Ray Milkey | 269ffb9 | 2014-04-03 14:43:30 -0700 | [diff] [blame] | 65 | } |
Pavlin Radoslavov | 6d224ee | 2014-02-18 16:43:15 -0800 | [diff] [blame] | 66 | |
Yuta HIGUCHI | fa74284 | 2014-07-03 22:35:13 -0700 | [diff] [blame^] | 67 | // TODO remove me when ready |
Ray Milkey | 269ffb9 | 2014-04-03 14:43:30 -0700 | [diff] [blame] | 68 | protected void removeSwitch(Long dpid) { |
Yuta HIGUCHI | fa74284 | 2014-07-03 22:35:13 -0700 | [diff] [blame^] | 69 | removeSwitch(new Dpid(dpid)); |
Yuta HIGUCHI | 8f3dfa3 | 2014-06-25 00:14:25 -0700 | [diff] [blame] | 70 | } |
| 71 | |
Yuta HIGUCHI | fa74284 | 2014-07-03 22:35:13 -0700 | [diff] [blame^] | 72 | // XXX Will remove ports in snapshot as side-effect. |
Yuta HIGUCHI | 8f3dfa3 | 2014-06-25 00:14:25 -0700 | [diff] [blame] | 73 | protected void removeSwitch(Dpid dpid) { |
Ray Milkey | 269ffb9 | 2014-04-03 14:43:30 -0700 | [diff] [blame] | 74 | switches.remove(dpid); |
Yuta HIGUCHI | fa74284 | 2014-07-03 22:35:13 -0700 | [diff] [blame^] | 75 | ports.remove(dpid); |
| 76 | } |
| 77 | |
| 78 | // This method is expected to be serialized by writeLock. |
| 79 | protected void putPort(Port port) { |
| 80 | ConcurrentMap<PortNumber, Port> portMap = ports.get(port.getDpid()); |
| 81 | if (portMap == null) { |
| 82 | portMap = new ConcurrentHashMap<>(); |
| 83 | ConcurrentMap<PortNumber, Port> existing = |
| 84 | ports.putIfAbsent(port.getDpid(), portMap); |
| 85 | if (existing != null) { |
| 86 | // port map was added concurrently, using theirs |
| 87 | portMap = existing; |
| 88 | } |
| 89 | } |
| 90 | portMap.put(port.getNumber(), port); |
| 91 | } |
| 92 | |
| 93 | protected void removePort(Port port) { |
| 94 | ConcurrentMap<PortNumber, Port> portMap = ports.get(port.getDpid()); |
| 95 | if (portMap != null) { |
| 96 | portMap.remove(port.getNumber()); |
| 97 | } |
Ray Milkey | 269ffb9 | 2014-04-03 14:43:30 -0700 | [diff] [blame] | 98 | } |
Pavlin Radoslavov | 6d224ee | 2014-02-18 16:43:15 -0800 | [diff] [blame] | 99 | |
Ray Milkey | 269ffb9 | 2014-04-03 14:43:30 -0700 | [diff] [blame] | 100 | @Override |
| 101 | public Iterable<Switch> getSwitches() { |
| 102 | // TODO Check if it is safe to directly return this Object. |
| 103 | return Collections.unmodifiableCollection(switches.values()); |
| 104 | } |
Yuta HIGUCHI | 80829d1 | 2014-02-05 20:16:56 -0800 | [diff] [blame] | 105 | |
Ray Milkey | 269ffb9 | 2014-04-03 14:43:30 -0700 | [diff] [blame] | 106 | @Override |
Yuta HIGUCHI | 8f3dfa3 | 2014-06-25 00:14:25 -0700 | [diff] [blame] | 107 | public Port getPort(Dpid dpid, PortNumber number) { |
Yuta HIGUCHI | fa74284 | 2014-07-03 22:35:13 -0700 | [diff] [blame^] | 108 | ConcurrentMap<PortNumber, Port> portMap = ports.get(dpid); |
| 109 | if (portMap != null) { |
| 110 | return portMap.get(number); |
Ray Milkey | 269ffb9 | 2014-04-03 14:43:30 -0700 | [diff] [blame] | 111 | } |
| 112 | return null; |
| 113 | } |
Pavlin Radoslavov | 06df22a | 2014-02-18 19:16:27 -0800 | [diff] [blame] | 114 | |
Ray Milkey | 269ffb9 | 2014-04-03 14:43:30 -0700 | [diff] [blame] | 115 | @Override |
Yuta HIGUCHI | 8f3dfa3 | 2014-06-25 00:14:25 -0700 | [diff] [blame] | 116 | public Port getPort(SwitchPort port) { |
| 117 | return getPort(port.dpid(), port.port()); |
Jonathan Hart | 25bd53e | 2014-04-30 23:44:09 -0700 | [diff] [blame] | 118 | } |
| 119 | |
| 120 | @Override |
Yuta HIGUCHI | fa74284 | 2014-07-03 22:35:13 -0700 | [diff] [blame^] | 121 | public Collection<Port> getPorts(Dpid dpid) { |
| 122 | ConcurrentMap<PortNumber, Port> portMap = ports.get(dpid); |
| 123 | if (portMap == null) { |
| 124 | return Collections.emptyList(); |
| 125 | } |
| 126 | return Collections.unmodifiableCollection(portMap.values()); |
| 127 | } |
| 128 | |
| 129 | @Override |
Yuta HIGUCHI | 8f3dfa3 | 2014-06-25 00:14:25 -0700 | [diff] [blame] | 130 | public Link getOutgoingLink(Dpid dpid, PortNumber number) { |
| 131 | return outgoingLinks.get(new SwitchPort(dpid, number)); |
Ray Milkey | 269ffb9 | 2014-04-03 14:43:30 -0700 | [diff] [blame] | 132 | } |
Pavlin Radoslavov | 7c8f69a | 2014-02-19 19:01:45 -0800 | [diff] [blame] | 133 | |
Ray Milkey | 269ffb9 | 2014-04-03 14:43:30 -0700 | [diff] [blame] | 134 | @Override |
Yuta HIGUCHI | 8f3dfa3 | 2014-06-25 00:14:25 -0700 | [diff] [blame] | 135 | public Link getOutgoingLink(SwitchPort port) { |
| 136 | return outgoingLinks.get(port); |
| 137 | } |
| 138 | |
| 139 | @Override |
| 140 | public Link getIncomingLink(Dpid dpid, PortNumber number) { |
| 141 | return incomingLinks.get(new SwitchPort(dpid, number)); |
| 142 | } |
| 143 | |
| 144 | @Override |
| 145 | public Link getIncomingLink(SwitchPort port) { |
| 146 | return incomingLinks.get(port); |
| 147 | } |
| 148 | |
| 149 | @Override |
| 150 | public Link getLink(Dpid srcDpid, PortNumber srcNumber, |
| 151 | Dpid dstDpid, PortNumber dstNumber) { |
| 152 | |
Jonathan Hart | 25bd53e | 2014-04-30 23:44:09 -0700 | [diff] [blame] | 153 | Link link = getOutgoingLink(srcDpid, srcNumber); |
Ray Milkey | b29e626 | 2014-04-09 16:02:14 -0700 | [diff] [blame] | 154 | if (link == null) { |
Ray Milkey | 269ffb9 | 2014-04-03 14:43:30 -0700 | [diff] [blame] | 155 | return null; |
Ray Milkey | b29e626 | 2014-04-09 16:02:14 -0700 | [diff] [blame] | 156 | } |
| 157 | if (!link.getDstSwitch().getDpid().equals(dstDpid)) { |
Ray Milkey | 269ffb9 | 2014-04-03 14:43:30 -0700 | [diff] [blame] | 158 | return null; |
Ray Milkey | b29e626 | 2014-04-09 16:02:14 -0700 | [diff] [blame] | 159 | } |
| 160 | if (!link.getDstPort().getNumber().equals(dstNumber)) { |
Ray Milkey | 269ffb9 | 2014-04-03 14:43:30 -0700 | [diff] [blame] | 161 | return null; |
Ray Milkey | b29e626 | 2014-04-09 16:02:14 -0700 | [diff] [blame] | 162 | } |
Ray Milkey | 269ffb9 | 2014-04-03 14:43:30 -0700 | [diff] [blame] | 163 | return link; |
| 164 | } |
Pavlin Radoslavov | 7c8f69a | 2014-02-19 19:01:45 -0800 | [diff] [blame] | 165 | |
Ray Milkey | 269ffb9 | 2014-04-03 14:43:30 -0700 | [diff] [blame] | 166 | @Override |
| 167 | public Iterable<Link> getLinks() { |
Jonathan Hart | 25bd53e | 2014-04-30 23:44:09 -0700 | [diff] [blame] | 168 | return Collections.unmodifiableCollection(outgoingLinks.values()); |
| 169 | } |
Toshio Koide | 2f570c1 | 2014-02-06 16:55:32 -0800 | [diff] [blame] | 170 | |
Jonathan Hart | 25bd53e | 2014-04-30 23:44:09 -0700 | [diff] [blame] | 171 | protected void putLink(Link link) { |
| 172 | outgoingLinks.put(link.getSrcPort().asSwitchPort(), link); |
| 173 | incomingLinks.put(link.getDstPort().asSwitchPort(), link); |
| 174 | } |
| 175 | |
| 176 | protected void removeLink(Link link) { |
| 177 | outgoingLinks.remove(link.getSrcPort().asSwitchPort(), link); |
| 178 | incomingLinks.remove(link.getDstPort().asSwitchPort(), link); |
Ray Milkey | 269ffb9 | 2014-04-03 14:43:30 -0700 | [diff] [blame] | 179 | } |
Yuta HIGUCHI | 80829d1 | 2014-02-05 20:16:56 -0800 | [diff] [blame] | 180 | |
Ray Milkey | 269ffb9 | 2014-04-03 14:43:30 -0700 | [diff] [blame] | 181 | @Override |
Ray Milkey | 269ffb9 | 2014-04-03 14:43:30 -0700 | [diff] [blame] | 182 | public Device getDeviceByMac(MACAddress address) { |
| 183 | return mac2Device.get(address); |
| 184 | } |
Pavlin Radoslavov | 6d224ee | 2014-02-18 16:43:15 -0800 | [diff] [blame] | 185 | |
TeruU | 65bc5ff | 2014-04-23 22:22:32 -0700 | [diff] [blame] | 186 | @Override |
| 187 | public Iterable<Device> getDevices() { |
| 188 | return Collections.unmodifiableCollection(mac2Device.values()); |
| 189 | } |
| 190 | |
Yuta HIGUCHI | fa74284 | 2014-07-03 22:35:13 -0700 | [diff] [blame^] | 191 | @Override |
| 192 | public Collection<Device> getDevices(SwitchPort port) { |
| 193 | return Collections.unmodifiableCollection(devices.get(port)); |
| 194 | } |
| 195 | |
| 196 | // This method is expected to be serialized by writeLock. |
| 197 | // XXX new or updated device |
Ray Milkey | 269ffb9 | 2014-04-03 14:43:30 -0700 | [diff] [blame] | 198 | protected void putDevice(Device device) { |
Yuta HIGUCHI | fa74284 | 2014-07-03 22:35:13 -0700 | [diff] [blame^] | 199 | // assuming Device is immutable |
| 200 | Device oldDevice = mac2Device.get(device.getMacAddress()); |
| 201 | if (oldDevice != null) { |
| 202 | // remove old attachment point |
| 203 | removeDevice(oldDevice); |
| 204 | } |
| 205 | // add new attachment points |
| 206 | for (Port port : device.getAttachmentPoints()) { |
| 207 | // TODO Won't need remove() if we define Device equality to reflect |
| 208 | // all of it's fields. |
| 209 | devices.remove(port.asSwitchPort(), device); |
| 210 | devices.put(port.asSwitchPort(), device); |
| 211 | } |
Ray Milkey | 269ffb9 | 2014-04-03 14:43:30 -0700 | [diff] [blame] | 212 | mac2Device.put(device.getMacAddress(), device); |
Ray Milkey | 269ffb9 | 2014-04-03 14:43:30 -0700 | [diff] [blame] | 213 | } |
Pavlin Radoslavov | 6d224ee | 2014-02-18 16:43:15 -0800 | [diff] [blame] | 214 | |
Ray Milkey | 269ffb9 | 2014-04-03 14:43:30 -0700 | [diff] [blame] | 215 | protected void removeDevice(Device device) { |
Yuta HIGUCHI | fa74284 | 2014-07-03 22:35:13 -0700 | [diff] [blame^] | 216 | for (Port port : device.getAttachmentPoints()) { |
| 217 | devices.remove(port.asSwitchPort(), device); |
| 218 | } |
Ray Milkey | 269ffb9 | 2014-04-03 14:43:30 -0700 | [diff] [blame] | 219 | mac2Device.remove(device.getMacAddress()); |
Ray Milkey | 269ffb9 | 2014-04-03 14:43:30 -0700 | [diff] [blame] | 220 | } |
Jonathan Hart | 26f291b | 2014-02-18 16:57:24 -0800 | [diff] [blame] | 221 | |
Ray Milkey | 269ffb9 | 2014-04-03 14:43:30 -0700 | [diff] [blame] | 222 | @Override |
| 223 | public void acquireReadLock() { |
| 224 | readLock.lock(); |
| 225 | } |
Jonathan Hart | 26f291b | 2014-02-18 16:57:24 -0800 | [diff] [blame] | 226 | |
Ray Milkey | 269ffb9 | 2014-04-03 14:43:30 -0700 | [diff] [blame] | 227 | @Override |
| 228 | public void releaseReadLock() { |
| 229 | readLock.unlock(); |
| 230 | } |
Pavlin Radoslavov | 8ffb8bf | 2014-02-20 15:34:26 -0800 | [diff] [blame] | 231 | |
Ray Milkey | 269ffb9 | 2014-04-03 14:43:30 -0700 | [diff] [blame] | 232 | protected void acquireWriteLock() { |
| 233 | writeLock.lock(); |
| 234 | } |
Pavlin Radoslavov | 8ffb8bf | 2014-02-20 15:34:26 -0800 | [diff] [blame] | 235 | |
Ray Milkey | 269ffb9 | 2014-04-03 14:43:30 -0700 | [diff] [blame] | 236 | protected void releaseWriteLock() { |
| 237 | writeLock.unlock(); |
| 238 | } |
Yuta HIGUCHI | 80829d1 | 2014-02-05 20:16:56 -0800 | [diff] [blame] | 239 | } |