Jonathan Hart | 062a2e8 | 2014-02-03 09:41:57 -0800 | [diff] [blame] | 1 | package net.onrc.onos.ofcontroller.networkgraph; |
| 2 | |
Yuta HIGUCHI | 4bfdd53 | 2014-02-07 13:47:36 -0800 | [diff] [blame^] | 3 | import java.util.NoSuchElementException; |
| 4 | |
Yuta HIGUCHI | 765cd0d | 2014-02-06 12:46:41 -0800 | [diff] [blame] | 5 | import net.onrc.onos.datastore.topology.RCLink; |
Jonathan Hart | 062a2e8 | 2014-02-03 09:41:57 -0800 | [diff] [blame] | 6 | import net.onrc.onos.datastore.topology.RCPort; |
| 7 | import net.onrc.onos.datastore.topology.RCSwitch; |
Yuta HIGUCHI | 765cd0d | 2014-02-06 12:46:41 -0800 | [diff] [blame] | 8 | import net.onrc.onos.ofcontroller.util.Dpid; |
Jonathan Hart | 062a2e8 | 2014-02-03 09:41:57 -0800 | [diff] [blame] | 9 | |
| 10 | import org.slf4j.Logger; |
| 11 | import org.slf4j.LoggerFactory; |
| 12 | |
| 13 | import edu.stanford.ramcloud.JRamCloud.ObjectDoesntExistException; |
| 14 | |
Yuta HIGUCHI | 181d34d | 2014-02-05 15:05:46 -0800 | [diff] [blame] | 15 | /** |
| 16 | * The "NB" read-only Network Map. |
| 17 | * |
Yuta HIGUCHI | 4bfdd53 | 2014-02-07 13:47:36 -0800 | [diff] [blame^] | 18 | * - Maintain Invariant/Relationships between Topology Objects. |
| 19 | * |
Yuta HIGUCHI | 765cd0d | 2014-02-06 12:46:41 -0800 | [diff] [blame] | 20 | * TODO To be synchronized based on TopologyEvent Notification. |
Yuta HIGUCHI | 181d34d | 2014-02-05 15:05:46 -0800 | [diff] [blame] | 21 | * |
Yuta HIGUCHI | 4bfdd53 | 2014-02-07 13:47:36 -0800 | [diff] [blame^] | 22 | * TODO TBD: This class may delay the requested change to handle event |
| 23 | * re-ordering. e.g.) Link Add came in, but Switch was not there. |
Yuta HIGUCHI | 181d34d | 2014-02-05 15:05:46 -0800 | [diff] [blame] | 24 | */ |
Yuta HIGUCHI | 80829d1 | 2014-02-05 20:16:56 -0800 | [diff] [blame] | 25 | public class NetworkGraphImpl extends AbstractNetworkGraph { |
Jonathan Hart | 062a2e8 | 2014-02-03 09:41:57 -0800 | [diff] [blame] | 26 | |
Yuta HIGUCHI | 80829d1 | 2014-02-05 20:16:56 -0800 | [diff] [blame] | 27 | private static final Logger log = LoggerFactory |
| 28 | .getLogger(NetworkGraphImpl.class); |
Yuta HIGUCHI | 181d34d | 2014-02-05 15:05:46 -0800 | [diff] [blame] | 29 | |
Yuta HIGUCHI | 80829d1 | 2014-02-05 20:16:56 -0800 | [diff] [blame] | 30 | public NetworkGraphImpl() { |
| 31 | super(); |
| 32 | } |
Yuta HIGUCHI | 181d34d | 2014-02-05 15:05:46 -0800 | [diff] [blame] | 33 | |
Yuta HIGUCHI | 4bfdd53 | 2014-02-07 13:47:36 -0800 | [diff] [blame^] | 34 | /** |
| 35 | * Add Switch to Topology. |
| 36 | * |
| 37 | * Fails with an Exception if a switch with same DPID already exist in |
| 38 | * Topology. |
| 39 | * |
| 40 | * @param sw |
| 41 | */ |
Yuta HIGUCHI | 80829d1 | 2014-02-05 20:16:56 -0800 | [diff] [blame] | 42 | void addSwitch(Switch sw) { |
Yuta HIGUCHI | 765cd0d | 2014-02-06 12:46:41 -0800 | [diff] [blame] | 43 | if (sw == null) { |
Yuta HIGUCHI | 80829d1 | 2014-02-05 20:16:56 -0800 | [diff] [blame] | 44 | throw new IllegalArgumentException("Switch cannot be null"); |
| 45 | } |
Yuta HIGUCHI | 4bfdd53 | 2014-02-07 13:47:36 -0800 | [diff] [blame^] | 46 | Switch oldSw = switches.putIfAbsent(sw.getDpid(), sw); |
| 47 | if (oldSw != null) { |
| 48 | // XXX Define or choose more appropriate Exception. |
| 49 | throw new RuntimeException("Switch already exists"); |
| 50 | } |
Yuta HIGUCHI | 80829d1 | 2014-02-05 20:16:56 -0800 | [diff] [blame] | 51 | } |
Yuta HIGUCHI | 181d34d | 2014-02-05 15:05:46 -0800 | [diff] [blame] | 52 | |
Yuta HIGUCHI | 80829d1 | 2014-02-05 20:16:56 -0800 | [diff] [blame] | 53 | /** |
Yuta HIGUCHI | 4bfdd53 | 2014-02-07 13:47:36 -0800 | [diff] [blame^] | 54 | * Deactivate and remove Switch. |
| 55 | * |
| 56 | * XXX Should it deactivate or delete its Ports also? |
Yuta HIGUCHI | 765cd0d | 2014-02-06 12:46:41 -0800 | [diff] [blame] | 57 | * |
Yuta HIGUCHI | 80829d1 | 2014-02-05 20:16:56 -0800 | [diff] [blame] | 58 | * @param sw |
| 59 | */ |
| 60 | void deactivateSwitch(Switch sw) { |
Yuta HIGUCHI | 765cd0d | 2014-02-06 12:46:41 -0800 | [diff] [blame] | 61 | if (sw == null) { |
Yuta HIGUCHI | 80829d1 | 2014-02-05 20:16:56 -0800 | [diff] [blame] | 62 | throw new IllegalArgumentException("Switch cannot be null"); |
| 63 | } |
Yuta HIGUCHI | 765cd0d | 2014-02-06 12:46:41 -0800 | [diff] [blame] | 64 | |
Yuta HIGUCHI | 4bfdd53 | 2014-02-07 13:47:36 -0800 | [diff] [blame^] | 65 | if( !isSwitchInstanceInTopology(sw) ){ |
| 66 | // XXX Define or choose more appropriate Exception. |
| 67 | throw new RuntimeException( |
| 68 | String.format( |
| 69 | "Switch with dpid %s did not exist or different instance registered.", |
| 70 | new Dpid(sw.getDpid()))); |
| 71 | } |
Yuta HIGUCHI | 181d34d | 2014-02-05 15:05:46 -0800 | [diff] [blame] | 72 | |
Yuta HIGUCHI | 80829d1 | 2014-02-05 20:16:56 -0800 | [diff] [blame] | 73 | // XXX Are we sure we want to deactivate Ports also? |
Yuta HIGUCHI | 4bfdd53 | 2014-02-07 13:47:36 -0800 | [diff] [blame^] | 74 | for (Port p : sw.getPorts()) { |
| 75 | deactivatePort(p); |
| 76 | } |
Yuta HIGUCHI | 181d34d | 2014-02-05 15:05:46 -0800 | [diff] [blame] | 77 | |
Yuta HIGUCHI | 4bfdd53 | 2014-02-07 13:47:36 -0800 | [diff] [blame^] | 78 | // TODO Deactivate Switch: What to do simply remove? |
| 79 | for (Link l : sw.getIncomingLinks()) { |
| 80 | removeLink(l); |
| 81 | } |
| 82 | |
| 83 | for (Link l : sw.getOutgoingLinks()) { |
| 84 | removeLink(l); |
| 85 | } |
| 86 | |
| 87 | if (!switches.containsKey(sw.getDpid())) { |
| 88 | throw new NoSuchElementException(String.format( |
| 89 | "Switch with dpid %s not found.", new Dpid(sw.getDpid()))); |
| 90 | } |
| 91 | boolean removed = switches.remove(sw.getDpid(), sw); |
| 92 | |
| 93 | if (!removed) { |
| 94 | // XXX Define or choose more appropriate Exception. |
| 95 | throw new RuntimeException( |
| 96 | String.format( |
| 97 | "Switch with dpid %s did not exist or different instance registered.", |
| 98 | new Dpid(sw.getDpid()))); |
| 99 | } |
Yuta HIGUCHI | 80829d1 | 2014-02-05 20:16:56 -0800 | [diff] [blame] | 100 | } |
Yuta HIGUCHI | 181d34d | 2014-02-05 15:05:46 -0800 | [diff] [blame] | 101 | |
Yuta HIGUCHI | 4bfdd53 | 2014-02-07 13:47:36 -0800 | [diff] [blame^] | 102 | /** |
| 103 | * Add Port to Topology. |
| 104 | * |
| 105 | * @param port |
| 106 | */ |
Yuta HIGUCHI | 80829d1 | 2014-02-05 20:16:56 -0800 | [diff] [blame] | 107 | void addPort(Port port) { |
Yuta HIGUCHI | 765cd0d | 2014-02-06 12:46:41 -0800 | [diff] [blame] | 108 | if (port == null) { |
Yuta HIGUCHI | 80829d1 | 2014-02-05 20:16:56 -0800 | [diff] [blame] | 109 | throw new IllegalArgumentException("Port cannot be null"); |
| 110 | } |
Yuta HIGUCHI | 4bfdd53 | 2014-02-07 13:47:36 -0800 | [diff] [blame^] | 111 | Switch sw = port.getSwitch(); |
Yuta HIGUCHI | 181d34d | 2014-02-05 15:05:46 -0800 | [diff] [blame] | 112 | |
Yuta HIGUCHI | 4bfdd53 | 2014-02-07 13:47:36 -0800 | [diff] [blame^] | 113 | if( !isSwitchInstanceInTopology(sw) ){ |
| 114 | // XXX Define or choose more appropriate Exception. |
| 115 | throw new RuntimeException( |
| 116 | String.format( |
| 117 | "Switch with dpid %s did not exist or different instance registered.", |
| 118 | new Dpid(sw.getDpid()))); |
| 119 | } |
| 120 | |
| 121 | SwitchImpl s = getSwitchImpl(sw); |
| 122 | |
| 123 | s.addPort(port); |
| 124 | // XXX Check If port already exist, if so then what? deactivate old? |
Yuta HIGUCHI | 80829d1 | 2014-02-05 20:16:56 -0800 | [diff] [blame] | 125 | } |
| 126 | |
Yuta HIGUCHI | 4bfdd53 | 2014-02-07 13:47:36 -0800 | [diff] [blame^] | 127 | /** |
| 128 | * Deactivate and remove Ports. |
| 129 | * |
| 130 | * @param port |
| 131 | */ |
Yuta HIGUCHI | 80829d1 | 2014-02-05 20:16:56 -0800 | [diff] [blame] | 132 | void deactivatePort(Port port) { |
Yuta HIGUCHI | 765cd0d | 2014-02-06 12:46:41 -0800 | [diff] [blame] | 133 | if (port == null) { |
Yuta HIGUCHI | 80829d1 | 2014-02-05 20:16:56 -0800 | [diff] [blame] | 134 | throw new IllegalArgumentException("Port cannot be null"); |
| 135 | } |
Yuta HIGUCHI | 80829d1 | 2014-02-05 20:16:56 -0800 | [diff] [blame] | 136 | |
Yuta HIGUCHI | 4bfdd53 | 2014-02-07 13:47:36 -0800 | [diff] [blame^] | 137 | Switch sw = port.getSwitch(); |
| 138 | |
| 139 | if( !isSwitchInstanceInTopology(sw) ){ |
| 140 | // XXX Define or choose more appropriate Exception. |
| 141 | throw new RuntimeException( |
| 142 | String.format( |
| 143 | "Switch with dpid %s did not exist or different instance registered.", |
| 144 | new Dpid(sw.getDpid()))); |
| 145 | } |
| 146 | |
| 147 | |
| 148 | // remove Link |
| 149 | removeLink(port.getIncomingLink()); |
| 150 | removeLink(port.getOutgoingLink()); |
| 151 | |
| 152 | // remove Device |
| 153 | for(Device d: port.getDevices()) { |
| 154 | removeDevice(d); |
| 155 | } |
| 156 | |
| 157 | // remove Port from Switch |
| 158 | SwitchImpl s = getSwitchImpl(sw); |
| 159 | s.removePort(port); |
Yuta HIGUCHI | 80829d1 | 2014-02-05 20:16:56 -0800 | [diff] [blame] | 160 | } |
| 161 | |
| 162 | void addLink(Link link) { |
Yuta HIGUCHI | 765cd0d | 2014-02-06 12:46:41 -0800 | [diff] [blame] | 163 | if (link == null) { |
Yuta HIGUCHI | 80829d1 | 2014-02-05 20:16:56 -0800 | [diff] [blame] | 164 | throw new IllegalArgumentException("Link cannot be null"); |
| 165 | } |
Yuta HIGUCHI | 80829d1 | 2014-02-05 20:16:56 -0800 | [diff] [blame] | 166 | |
Yuta HIGUCHI | 4bfdd53 | 2014-02-07 13:47:36 -0800 | [diff] [blame^] | 167 | Switch srcSw = link.getSourceSwitch(); |
| 168 | if( !isSwitchInstanceInTopology(srcSw) ){ |
| 169 | // XXX Define or choose more appropriate Exception. |
| 170 | throw new RuntimeException( |
| 171 | String.format( |
| 172 | "Switch with dpid %s did not exist or different instance registered.", |
| 173 | new Dpid(srcSw.getDpid()))); |
| 174 | } |
| 175 | |
| 176 | Switch dstSw = link.getDestinationSwitch(); |
| 177 | if( !isSwitchInstanceInTopology(dstSw) ){ |
| 178 | // XXX Define or choose more appropriate Exception. |
| 179 | throw new RuntimeException( |
| 180 | String.format( |
| 181 | "Switch with dpid %s did not exist or different instance registered.", |
| 182 | new Dpid(dstSw.getDpid()))); |
| 183 | } |
| 184 | |
| 185 | PortImpl srcPort = getPortImpl( link.getSourcePort() ); |
| 186 | PortImpl dstPort = getPortImpl( link.getDestinationPort() ); |
| 187 | |
| 188 | // XXX check Existing Link first? |
| 189 | srcPort.setOutgoingLink(link); |
| 190 | dstPort.setIncomingLink(link); |
Yuta HIGUCHI | 80829d1 | 2014-02-05 20:16:56 -0800 | [diff] [blame] | 191 | } |
| 192 | |
| 193 | void removeLink(Link link) { |
Yuta HIGUCHI | 765cd0d | 2014-02-06 12:46:41 -0800 | [diff] [blame] | 194 | if (link == null) { |
Yuta HIGUCHI | 80829d1 | 2014-02-05 20:16:56 -0800 | [diff] [blame] | 195 | throw new IllegalArgumentException("Link cannot be null"); |
| 196 | } |
Yuta HIGUCHI | 80829d1 | 2014-02-05 20:16:56 -0800 | [diff] [blame] | 197 | |
Yuta HIGUCHI | 4bfdd53 | 2014-02-07 13:47:36 -0800 | [diff] [blame^] | 198 | Switch srcSw = link.getSourceSwitch(); |
| 199 | if( !isSwitchInstanceInTopology(srcSw) ){ |
| 200 | // XXX Define or choose more appropriate Exception. |
| 201 | throw new RuntimeException( |
| 202 | String.format( |
| 203 | "Switch with dpid %s did not exist or different instance registered.", |
| 204 | new Dpid(srcSw.getDpid()))); |
| 205 | } |
| 206 | |
| 207 | Switch dstSw = link.getDestinationSwitch(); |
| 208 | if( !isSwitchInstanceInTopology(dstSw) ){ |
| 209 | // XXX Define or choose more appropriate Exception. |
| 210 | throw new RuntimeException( |
| 211 | String.format( |
| 212 | "Switch with dpid %s did not exist or different instance registered.", |
| 213 | new Dpid(dstSw.getDpid()))); |
| 214 | } |
| 215 | |
| 216 | PortImpl srcPort = getPortImpl( link.getSourcePort() ); |
| 217 | PortImpl dstPort = getPortImpl( link.getDestinationPort() ); |
| 218 | |
| 219 | // XXX check Existing Link first? |
| 220 | if( srcPort.getOutgoingLink() != link || dstPort.getIncomingLink() != link) { |
| 221 | // XXX Define or choose more appropriate Exception. |
| 222 | throw new RuntimeException( |
| 223 | String.format("Link %s did not belong to Topology", link.toString()) |
| 224 | ); |
| 225 | } |
| 226 | // remove Link |
| 227 | srcPort.setOutgoingLink(null); |
| 228 | dstPort.setIncomingLink(null); |
Yuta HIGUCHI | 80829d1 | 2014-02-05 20:16:56 -0800 | [diff] [blame] | 229 | } |
| 230 | |
| 231 | void updateDevice(Device device) { |
Yuta HIGUCHI | 765cd0d | 2014-02-06 12:46:41 -0800 | [diff] [blame] | 232 | if (device == null) { |
Yuta HIGUCHI | 80829d1 | 2014-02-05 20:16:56 -0800 | [diff] [blame] | 233 | throw new IllegalArgumentException("Device cannot be null"); |
| 234 | } |
| 235 | // TODO Auto-generated method stub |
| 236 | |
| 237 | } |
| 238 | |
| 239 | void removeDevice(Device device) { |
Yuta HIGUCHI | 765cd0d | 2014-02-06 12:46:41 -0800 | [diff] [blame] | 240 | if (device == null) { |
Yuta HIGUCHI | 80829d1 | 2014-02-05 20:16:56 -0800 | [diff] [blame] | 241 | throw new IllegalArgumentException("Device cannot be null"); |
| 242 | } |
| 243 | // TODO Auto-generated method stub |
| 244 | |
| 245 | } |
| 246 | |
| 247 | private SwitchImpl getSwitchImpl(Switch sw) { |
Yuta HIGUCHI | 765cd0d | 2014-02-06 12:46:41 -0800 | [diff] [blame] | 248 | if (sw instanceof SwitchImpl) { |
Yuta HIGUCHI | 80829d1 | 2014-02-05 20:16:56 -0800 | [diff] [blame] | 249 | return (SwitchImpl) sw; |
| 250 | } |
Yuta HIGUCHI | 4bfdd53 | 2014-02-07 13:47:36 -0800 | [diff] [blame^] | 251 | throw new ClassCastException("SwitchImpl expected, but found: " + sw); |
| 252 | } |
| 253 | |
| 254 | private PortImpl getPortImpl(Port p) { |
| 255 | if (p instanceof PortImpl) { |
| 256 | return (PortImpl) p; |
| 257 | } |
| 258 | throw new ClassCastException("PortImpl expected, but found: " + p); |
| 259 | } |
| 260 | |
| 261 | public boolean isSwitchInstanceInTopology(Switch sw) { |
| 262 | // check if the sw instance is valid in Topology |
| 263 | if (sw != switches.get(sw.getDpid())) { |
| 264 | return false; |
| 265 | } |
| 266 | return true; |
Yuta HIGUCHI | 765cd0d | 2014-02-06 12:46:41 -0800 | [diff] [blame] | 267 | } |
| 268 | |
| 269 | public void loadWholeTopologyFromDB() { |
| 270 | // XXX clear everything first? |
| 271 | |
| 272 | for (RCSwitch sw : RCSwitch.getAllSwitches()) { |
| 273 | try { |
| 274 | sw.read(); |
| 275 | // TODO SwitchImpl probably should have a constructor from |
| 276 | // RCSwitch |
Toshio Koide | 2f570c1 | 2014-02-06 16:55:32 -0800 | [diff] [blame] | 277 | SwitchImpl memSw = new SwitchImpl(this, sw.getDpid()); |
Yuta HIGUCHI | 765cd0d | 2014-02-06 12:46:41 -0800 | [diff] [blame] | 278 | |
| 279 | addSwitch(memSw); |
| 280 | } catch (ObjectDoesntExistException e) { |
| 281 | log.error("Read Switch Failed, skipping", e); |
| 282 | } |
| 283 | } |
| 284 | |
| 285 | for (RCPort p : RCPort.getAllPorts()) { |
| 286 | try { |
| 287 | p.read(); |
| 288 | |
| 289 | // TODO PortImpl probably should have a constructor from RCPort |
Yuta HIGUCHI | 765cd0d | 2014-02-06 12:46:41 -0800 | [diff] [blame] | 290 | Switch sw = this.getSwitch(p.getDpid()); |
| 291 | if (sw == null) { |
| 292 | log.error("Switch {} missing when adding Port {}", |
| 293 | new Dpid(p.getDpid()), p); |
| 294 | continue; |
| 295 | } |
Toshio Koide | 2f570c1 | 2014-02-06 16:55:32 -0800 | [diff] [blame] | 296 | PortImpl memPort = new PortImpl(this, sw, p.getNumber()); |
Yuta HIGUCHI | 765cd0d | 2014-02-06 12:46:41 -0800 | [diff] [blame] | 297 | |
| 298 | addPort(memPort); |
| 299 | } catch (ObjectDoesntExistException e) { |
| 300 | log.error("Read Port Failed, skipping", e); |
| 301 | } |
| 302 | } |
| 303 | |
| 304 | // TODO Is Device going to be in DB? If so, read from DB. |
| 305 | // for (RCDevice d : RCDevice.getAllDevices()) { |
| 306 | // try { |
| 307 | // d.read(); |
| 308 | // |
| 309 | // } catch (ObjectDoesntExistException e) { |
| 310 | // log.debug("Read Device Failed, skipping", e); |
| 311 | // } |
| 312 | // } |
| 313 | |
| 314 | for (RCLink l : RCLink.getAllLinks()) { |
Yuta HIGUCHI | 80829d1 | 2014-02-05 20:16:56 -0800 | [diff] [blame] | 315 | try { |
Yuta HIGUCHI | 4bfdd53 | 2014-02-07 13:47:36 -0800 | [diff] [blame^] | 316 | l.read(); |
Yuta HIGUCHI | 80829d1 | 2014-02-05 20:16:56 -0800 | [diff] [blame] | 317 | |
Yuta HIGUCHI | 4bfdd53 | 2014-02-07 13:47:36 -0800 | [diff] [blame^] | 318 | Switch srcSw = this.getSwitch(l.getSrc().dpid); |
| 319 | if (srcSw == null) { |
| 320 | log.error("Switch {} missing when adding Link {}", |
| 321 | new Dpid(l.getSrc().dpid), l); |
| 322 | continue; |
| 323 | } |
Yuta HIGUCHI | 80829d1 | 2014-02-05 20:16:56 -0800 | [diff] [blame] | 324 | |
Yuta HIGUCHI | 4bfdd53 | 2014-02-07 13:47:36 -0800 | [diff] [blame^] | 325 | Switch dstSw = this.getSwitch(l.getDst().dpid); |
| 326 | if (dstSw == null) { |
| 327 | log.error("Switch {} missing when adding Link {}", |
| 328 | new Dpid(l.getDst().dpid), l); |
| 329 | continue; |
| 330 | } |
Yuta HIGUCHI | 80829d1 | 2014-02-05 20:16:56 -0800 | [diff] [blame] | 331 | |
Yuta HIGUCHI | 4bfdd53 | 2014-02-07 13:47:36 -0800 | [diff] [blame^] | 332 | LinkImpl memLink = new LinkImpl(this, |
| 333 | srcSw.getPort(l.getSrc().number), dstSw.getPort(l |
| 334 | .getDst().number)); |
Yuta HIGUCHI | 80829d1 | 2014-02-05 20:16:56 -0800 | [diff] [blame] | 335 | |
Yuta HIGUCHI | 4bfdd53 | 2014-02-07 13:47:36 -0800 | [diff] [blame^] | 336 | addLink(memLink); |
Yuta HIGUCHI | 80829d1 | 2014-02-05 20:16:56 -0800 | [diff] [blame] | 337 | } catch (ObjectDoesntExistException e) { |
Yuta HIGUCHI | 4bfdd53 | 2014-02-07 13:47:36 -0800 | [diff] [blame^] | 338 | log.debug("Delete Link Failed", e); |
Yuta HIGUCHI | 80829d1 | 2014-02-05 20:16:56 -0800 | [diff] [blame] | 339 | } |
Jonathan Hart | 062a2e8 | 2014-02-03 09:41:57 -0800 | [diff] [blame] | 340 | } |
Yuta HIGUCHI | 80829d1 | 2014-02-05 20:16:56 -0800 | [diff] [blame] | 341 | } |
Jonathan Hart | 062a2e8 | 2014-02-03 09:41:57 -0800 | [diff] [blame] | 342 | } |