/** * Given a new or modified port newPort, returns the list of PortChangeEvents to "transform" the * current ports stored by this switch to include / represent the new port. The ports stored by * this switch are <b>NOT</b> updated. * * <p>This method acquires the readlock and is thread-safe by itself. Most callers will need to * acquire the write lock before calling this method though (if the caller wants to update the * ports stored by this switch) * * @param newPort the new or modified port. * @return the list of changes */ public OrderedCollection<PortChangeEvent> getSinglePortChanges(OFPortDesc newPort) { lock.readLock().lock(); try { OrderedCollection<PortChangeEvent> events = new LinkedHashSetWrapper<PortChangeEvent>(); // Check if we have a port by the same number in our // old map. OFPortDesc prevPort = portsByNumber.get(newPort.getPortNo()); if (newPort.equals(prevPort)) { // nothing has changed return events; } if (prevPort != null && prevPort.getName().equals(newPort.getName())) { // A simple modify of a exiting port // A previous port with this number exists and it's name // also matches the new port. Find the differences if ((!prevPort.getState().contains(OFPortState.LINK_DOWN) && !prevPort.getConfig().contains(OFPortConfig.PORT_DOWN)) && (newPort.getState().contains(OFPortState.LINK_DOWN) || newPort.getConfig().contains(OFPortConfig.PORT_DOWN))) { events.add(new PortChangeEvent(newPort, PortChangeType.DOWN)); } else if ((prevPort.getState().contains(OFPortState.LINK_DOWN) || prevPort.getConfig().contains(OFPortConfig.PORT_DOWN)) && (!newPort.getState().contains(OFPortState.LINK_DOWN) && !newPort.getConfig().contains(OFPortConfig.PORT_DOWN))) { events.add(new PortChangeEvent(newPort, PortChangeType.UP)); } else { events.add(new PortChangeEvent(newPort, PortChangeType.OTHER_UPDATE)); } return events; } if (prevPort != null) { // There exists a previous port with the same port // number but the port name is different (otherwise we would // never have gotten here) // Remove the port. Name-number mapping(s) have changed events.add(new PortChangeEvent(prevPort, PortChangeType.DELETE)); } // We now need to check if there exists a previous port sharing // the same name as the new/updated port. prevPort = portsByName.get(newPort.getName().toLowerCase()); if (prevPort != null) { // There exists a previous port with the same port // name but the port number is different (otherwise we // never have gotten here). // Remove the port. Name-number mapping(s) have changed events.add(new PortChangeEvent(prevPort, PortChangeType.DELETE)); } // We always need to add the new port. Either no previous port // existed or we just deleted previous ports with inconsistent // name-number mappings events.add(new PortChangeEvent(newPort, PortChangeType.ADD)); return events; } finally { lock.readLock().unlock(); } }
@Override public boolean portEnabled(String portName) { OFPortDesc p = portManager.getPort(portName); if (p == null) return false; return (!p.getState().contains(OFPortState.BLOCKED) && !p.getState().contains(OFPortState.LINK_DOWN) && !p.getState().contains(OFPortState.STP_BLOCK)); }
/** * Set the internal data structure storing this switch's port to the ports specified by * newPortsByNumber * * <p>CALLER MUST HOLD WRITELOCK * * @param newPortsByNumber * @throws IllegaalStateException if called without holding the writelock */ private void updatePortsWithNewPortsByNumber(Map<OFPort, OFPortDesc> newPortsByNumber) { if (!lock.writeLock().isHeldByCurrentThread()) { throw new IllegalStateException("Method called without " + "holding writeLock"); } Map<String, OFPortDesc> newPortsByName = new HashMap<String, OFPortDesc>(); List<OFPortDesc> newPortList = new ArrayList<OFPortDesc>(); List<OFPortDesc> newEnabledPortList = new ArrayList<OFPortDesc>(); List<OFPort> newEnabledPortNumbers = new ArrayList<OFPort>(); for (OFPortDesc p : newPortsByNumber.values()) { newPortList.add(p); newPortsByName.put(p.getName().toLowerCase(), p); if (!p.getState().contains(OFPortState.LINK_DOWN) && !p.getConfig().contains(OFPortConfig.PORT_DOWN)) { newEnabledPortList.add(p); newEnabledPortNumbers.add(p.getPortNo()); } } portsByName = Collections.unmodifiableMap(newPortsByName); portsByNumber = Collections.unmodifiableMap(newPortsByNumber); enabledPortList = Collections.unmodifiableList(newEnabledPortList); enabledPortNumbers = Collections.unmodifiableList(newEnabledPortNumbers); portList = Collections.unmodifiableList(newPortList); }
/** * Compare the current ports stored in this switch instance with the new port list given and * return the differences in the form of PortChangeEvents. If the doUpdate flag is true, * newPortList will replace the current list of this switch (and update the port maps) * * <p>Implementation note: Since this method can optionally modify the current ports and since * it's not possible to upgrade a read-lock to a write-lock we need to hold the write-lock for * the entire operation. If this becomes a problem and if compares() are common we can consider * splitting in two methods but this requires lots of code duplication * * @param newPorts the list of new ports. * @param doUpdate If true the newPortList will replace the current port list for this switch. * If false this switch will not be changed. * @return The list of differences between the current ports and newPorts * @throws NullPointerException if newPortsList is null * @throws IllegalArgumentException if either port names or port numbers are duplicated in the * newPortsList. */ private OrderedCollection<PortChangeEvent> compareAndUpdatePorts( Collection<OFPortDesc> newPorts, boolean doUpdate) { if (newPorts == null) { throw new NullPointerException("newPortsList must not be null"); } lock.writeLock().lock(); try { OrderedCollection<PortChangeEvent> events = new LinkedHashSetWrapper<PortChangeEvent>(); Map<OFPort, OFPortDesc> newPortsByNumber = new HashMap<OFPort, OFPortDesc>(); Map<String, OFPortDesc> newPortsByName = new HashMap<String, OFPortDesc>(); List<OFPortDesc> newEnabledPortList = new ArrayList<OFPortDesc>(); List<OFPort> newEnabledPortNumbers = new ArrayList<OFPort>(); List<OFPortDesc> newPortsList = new ArrayList<OFPortDesc>(newPorts); for (OFPortDesc p : newPortsList) { if (p == null) { throw new NullPointerException("portList must not " + "contain null values"); } // Add the port to the new maps and lists and check // that every port is unique OFPortDesc duplicatePort; duplicatePort = newPortsByNumber.put(p.getPortNo(), p); if (duplicatePort != null) { String msg = String.format( "Cannot have two ports " + "with the same number: %s <-> %s", String.format("%s (%d)", p.getName(), p.getPortNo().getPortNumber()), String.format( "%s (%d)", duplicatePort.getName(), duplicatePort.getPortNo().getPortNumber())); throw new IllegalArgumentException(msg); } duplicatePort = newPortsByName.put(p.getName().toLowerCase(), p); if (duplicatePort != null) { String msg = String.format( "Cannot have two ports " + "with the same name: %s <-> %s", String.format("%s (%d)", p.getName(), p.getPortNo().getPortNumber()), String.format( "%s (%d)", duplicatePort.getName(), duplicatePort.getPortNo().getPortNumber())); throw new IllegalArgumentException(msg); } // Enabled = not down admin (config) or phys (state) if (!p.getConfig().contains(OFPortConfig.PORT_DOWN) && !p.getState().contains(OFPortState.LINK_DOWN)) { newEnabledPortList.add(p); newEnabledPortNumbers.add(p.getPortNo()); } // get changes events.addAll(getSinglePortChanges(p)); } // find deleted ports // We need to do this after looping through all the new ports // to we can handle changed name<->number mappings correctly // We could pull it into the loop of we address this but // it's probably not worth it for (OFPortDesc oldPort : this.portList) { if (!newPortsByNumber.containsKey(oldPort.getPortNo())) { PortChangeEvent ev = new PortChangeEvent(oldPort, PortChangeType.DELETE); events.add(ev); } } if (doUpdate) { portsByName = Collections.unmodifiableMap(newPortsByName); portsByNumber = Collections.unmodifiableMap(newPortsByNumber); enabledPortList = Collections.unmodifiableList(newEnabledPortList); enabledPortNumbers = Collections.unmodifiableList(newEnabledPortNumbers); portList = Collections.unmodifiableList(newPortsList); } return events; } finally { lock.writeLock().unlock(); } }