Esempio n. 1
0
void BcmPort::setSpeed(const shared_ptr<Port>& swPort) {
  int ret;
  cfg::PortSpeed desiredPortSpeed;
  if (swPort->getSpeed() == cfg::PortSpeed::DEFAULT) {
    int speed;
    ret = opennsl_port_speed_max(unit_, port_, &speed);
    bcmCheckError(ret, "failed to get max speed for port", swPort->getID());
    desiredPortSpeed = cfg::PortSpeed(speed);
  } else {
    desiredPortSpeed = swPort->getSpeed();
  }

  int desiredSpeed = static_cast<int>(desiredPortSpeed);
  // Unnecessarily updating BCM port speed actually causes
  // the port to flap, even if this should be a noop, so check current
  // speed before making speed related changes. Doing so fixes
  // the interface flaps we were seeing during warm boots

  int curSpeed = static_cast<int>(getSpeed());

  // If the port is down or disabled its safe to update mode and speed to
  // desired values
  bool portUp = isUp();

  // Update to correct mode and speed settings if the port is down/disabled
  // or if the speed changed. Ideally we would like to always update to the
  // desired mode and speed. However these changes are disruptive, in that
  // they cause a port flap. So to avoid that, we don't update to desired
  // mode if the port is UP and running at the desired speed. Speed changes
  // though are applied to UP ports as well, since running at wrong (lower than
  // desired) speed is pretty dangerous, and can trigger non obvious outages.
  //
  // Another practical reason for not updating to the desired mode on ports that
  // are UP is that there is at least one bug whereby SDK thinks that the ports
  // are in a different mode than they actually are. We are tracking that
  // separately. Once that is resolved, we can do a audit to see that if all
  // ports are in desired mode settings, we can make mode changes a first
  // class citizen as well.
  if (!portUp || curSpeed != desiredSpeed) {
    opennsl_port_if_t desiredMode = getDesiredInterfaceMode(desiredPortSpeed,
                                                        swPort->getID(),
                                                        swPort->getName());

    // Check whether we have the correct interface set
    opennsl_port_if_t curMode;
    ret = opennsl_port_interface_get(unit_, port_, &curMode);
    bcmCheckError(ret,
                  "Failed to get current interface setting for port ",
                  swPort->getID());

    if (curMode != desiredMode) {
      // Changes to the interface setting only seem to take effect on the next
      // call to opennsl_port_speed_set()
      ret = opennsl_port_interface_set(unit_, port_, desiredMode);
      bcmCheckError(
          ret, "failed to set interface type for port ", swPort->getID());
    }

    if (portUp) {
      // Changing the port speed causes traffic disruptions, but not doing
      // it would cause inconsistency.  Warn the user.
      LOG(WARNING) << "Changing port speed on up port. This will "
                   << "disrupt traffic. Port: " << swPort->getName()
                   << " id: " << swPort->getID();
    }

    // Note that we call speed_set even if the speed is already set
    // properly and port is down. This is because speed_set
    // reinitializes the MAC layer of the port and allows us to pick
    // up changes in interface mode and finalize flex port
    // transitions. We ensure that the port is down for these
    // potentially unnecessary calls, as otherwise this will cause
    // port flaps on ports where link is up.
    ret = opennsl_port_speed_set(unit_, port_, desiredSpeed);
    bcmCheckError(
      ret,
      "failed to set speed to ",
      desiredSpeed,
      " from ",
      curSpeed,
      ", on port ",
      swPort->getID());
    getPlatformPort()->linkSpeedChanged(desiredPortSpeed);
  }
}
Esempio n. 2
0
void BcmPort::setSpeed(const shared_ptr<Port>& swPort) {
  if (isEnabled()) {
    LOG(ERROR) << "Cannot set port speed while the port is enabled. Port: "
               << swPort->getName() << " id: " << swPort->getID();
    return;
  }
  int ret;
  cfg::PortSpeed desiredPortSpeed;
  if (swPort->getSpeed() == cfg::PortSpeed::DEFAULT) {
    int speed;
    ret = opennsl_port_speed_max(unit_, port_, &speed);
    bcmCheckError(ret, "failed to get max speed for port", swPort->getID());
    desiredPortSpeed = cfg::PortSpeed(speed);
  } else {
    desiredPortSpeed = swPort->getSpeed();
  }

  opennsl_port_if_t desiredMode = getDesiredInterfaceMode(desiredPortSpeed,
                                                          swPort->getID(),
                                                          swPort->getName());

  opennsl_port_if_t curMode;
  ret = opennsl_port_interface_get(unit_, port_, &curMode);
  bcmCheckError(ret,
                "Failed to get current interface setting for port ",
                swPort->getID());

  bool updateSpeed = false;

  if (curMode != desiredMode) {
    ret = opennsl_port_interface_set(unit_, port_, desiredMode);
    bcmCheckError(
        ret, "failed to set interface type for port ", swPort->getID());
    // Changes to the interface setting only seem to take effect on the next
    // call to opennsl_port_speed_set().  Therefore make sure we update the
    // speed below, even if the speed is already at the desired setting.
    updateSpeed = true;
  }

  int desiredSpeed = static_cast<int>(desiredPortSpeed);
  // Unnecessarily updating BCM port speed actually causes
  // the port to flap, even if this should be a noop, so check current
  // speed before making speed related changes. Doing so fixes
  // the interface flaps we were seeing during warm boots
  if (!updateSpeed && desiredMode != OPENNSL_PORT_IF_KR4) {
    int curSpeed;
    ret = opennsl_port_speed_get(unit_, port_, &curSpeed);
    bcmCheckError(
        ret, "Failed to get current speed for port ", swPort->getID());
    updateSpeed |= (curSpeed != desiredSpeed);
  }

  if (updateSpeed) {
    if (desiredMode == OPENNSL_PORT_IF_KR4) {
      // We don't need to set speed when mode is KR4, since ports in KR4 mode
      // do autonegotiation to figure out the speed.
      setKR4Ability();
    } else {
      ret = opennsl_port_speed_set(unit_, port_, desiredSpeed);
      bcmCheckError(ret,
                    "failed to set speed, ",
                    desiredSpeed,
                    ", to port ",
                    swPort->getID());
    }
  }
}