Beispiel #1
0
    /**
     * 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();
      }
    }
Beispiel #2
0
    /**
     * 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);
    }
Beispiel #3
0
    /**
     * 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();
      }
    }