Exemple #1
0
void BcmPort::init(bool warmBoot) {
  bool up = false;
  if (warmBoot) {
    // Get port status from HW on warm boot.
    // All ports are initially down on a cold boot.
    int linkStatus;
    opennsl_port_link_status_get(unit_, port_, &linkStatus);
    up = (linkStatus == OPENNSL_PORT_LINK_STATUS_UP);
  } else {
    // In open source code, we don't have any guarantees for the
    // state of the port at startup. Bringing them down guarantees
    // that things are in a known state.
    //
    // We should only be doing this on cold boot, since warm booting
    // should be initializing the state for us.
    auto rv = opennsl_port_enable_set(unit_, port_, false);
    bcmCheckError(rv, "failed to set port to known state: ", port_);
  }

  setPortStatus(up);

  // Linkscan should be enabled if the port is enabled already
  auto linkscan = isEnabled() ? OPENNSL_LINKSCAN_MODE_SW :
    OPENNSL_LINKSCAN_MODE_NONE;
  auto rv = opennsl_linkscan_mode_set(unit_, port_, linkscan);
  bcmCheckError(rv, "failed to set initial linkscan mode on port ", port_);
}
Exemple #2
0
void BcmPort::disable(const std::shared_ptr<Port>& swPort) {
  if (!isEnabled()) {
    // Already disabled
    return;
  }

  auto pbmp = getPbmp();
  for (auto entry : swPort->getVlans()) {
    auto rv = opennsl_vlan_port_remove(unit_, entry.first, pbmp);
    bcmCheckError(rv, "failed to remove disabled port ",
                  swPort->getID(), " from VLAN ", entry.first);
  }

  // Disable packet and byte counter statistic collection.
  auto rv = opennsl_port_stat_enable_set(unit_, gport_, false);
  bcmCheckError(rv, "Unexpected error disabling counter DMA on port ",
                swPort->getID());

  // Disable linkscan
  rv = opennsl_linkscan_mode_set(unit_, port_, OPENNSL_LINKSCAN_MODE_NONE);
  bcmCheckError(rv, "Failed to disable linkscan on port ", swPort->getID());

  rv = opennsl_port_enable_set(unit_, port_, false);
  bcmCheckError(rv, "failed to disable port ", swPort->getID());
}
Exemple #3
0
void BcmPort::setIngressVlan(const shared_ptr<Port>& swPort) {
  opennsl_vlan_t currVlan;
  auto rv = opennsl_port_untagged_vlan_get(unit_, port_, &currVlan);
  bcmCheckError(rv, "failed to get ingress VLAN for port ", swPort->getID());

  opennsl_vlan_t bcmVlan = swPort->getIngressVlan();
  if (bcmVlan != currVlan) {
    rv = opennsl_port_untagged_vlan_set(unit_, port_, bcmVlan);
    bcmCheckError(rv, "failed to set ingress VLAN for port ",
                  swPort->getID(), " to ", swPort->getIngressVlan());
  }
}
Exemple #4
0
cfg::PortSpeed BcmPort::getSpeed() const {
  int curSpeed{0};
  auto rv = opennsl_port_speed_get(unit_, port_, &curSpeed);
  bcmCheckError(
    rv, "Failed to get current speed for port ", port_);
  return cfg::PortSpeed(curSpeed);
}
Exemple #5
0
void BcmPort::init(bool warmBoot) {
  bool up = false;
  if (warmBoot) {
    // Get port status from HW on warm boot.
    // All ports are initially down on a cold boot.
    int linkStatus;
    opennsl_port_link_status_get(unit_, port_, &linkStatus);
    up = (linkStatus == OPENNSL_PORT_LINK_STATUS_UP);
  } else {
    // In open source code, we don't have any guarantees for the
    // state of the port at startup. Bringing them down guarantees
    // that things are in a known state.
    //
    // We should only be doing this on cold boot, since warm booting
    // should be initializing the state for us.
    auto rv = opennsl_port_enable_set(unit_, port_, false);
    bcmCheckError(rv, "failed to set port to known state: ", port_);
  }

  // Notify platform port of initial state/speed
  getPlatformPort()->linkSpeedChanged(getSpeed());
  getPlatformPort()->linkStatusChanged(up, isEnabled());

  enableLinkscan();
}
Exemple #6
0
void BcmUnit::detach() {
  attached_.store(false, std::memory_order_release);

  // Clean up SDK state, without touching the hardware
  auto rv = _opennsl_shutdown(unit_);
  bcmCheckError(rv, "failed to clean up BCM state during warm boot shutdown");
}
Exemple #7
0
BcmPort::BcmPort(BcmSwitch* hw, opennsl_port_t port,
                 BcmPlatformPort* platformPort)
    : hw_(hw),
      port_(port),
      platformPort_(platformPort),
      unit_(hw->getUnit()) {
  // Obtain the gport handle from the port handle.
  int rv = opennsl_port_gport_get(unit_, port_, &gport_);
  bcmCheckError(rv, "Failed to get gport for BCM port ", port_);

  disablePause();

  // Initialize our stats data structures
  auto statMap = fbData->getStatMap();
  const auto expType = stats::AVG;
  outQueueLen_ = statMap->getLockAndStatItem(statName("out_queue_length"),
                                             &expType);
  auto histMap = fbData->getHistogramMap();
  stats::ExportedHistogram pktLenHist(1, 0, kInPktLengthStats.size());
  inPktLengths_ = histMap->getOrCreateUnlocked(statName("in_pkt_lengths"),
                                               &pktLenHist);
  outPktLengths_ = histMap->getOrCreateUnlocked(statName("out_pkt_lengths"),
                                                &pktLenHist);

  setConfiguredMaxSpeed();

  VLOG(2) << "created BCM port:" << port_ << ", gport:" << gport_
          << ", FBOSS PortID:" << platformPort_->getPortID();
}
Exemple #8
0
void BcmPort::enable(const std::shared_ptr<Port>& swPort) {
  if (isEnabled()) {
    // Port is already enabled, don't need to do anything
    return;
  }

  auto pbmp = getPbmp();
  opennsl_pbmp_t emptyPortList;
  OPENNSL_PBMP_CLEAR(emptyPortList);
  int rv;
  for (auto entry : swPort->getVlans()) {
    if (!entry.second.tagged) {
      rv = opennsl_vlan_port_add(unit_, entry.first, pbmp, pbmp);
    } else {
      rv = opennsl_vlan_port_add(unit_, entry.first, pbmp, emptyPortList);
    }
    bcmCheckError(rv, "failed to add enabled port ",
                  swPort->getID(), " to VLAN ", entry.first);
  }

  // Drop packets to/from this port that are tagged with a VLAN that this
  // port isn't a member of.
  rv = opennsl_port_vlan_member_set(unit_, port_,
                                    OPENNSL_PORT_VLAN_MEMBER_INGRESS |
                                    OPENNSL_PORT_VLAN_MEMBER_EGRESS);
  bcmCheckError(rv, "failed to set VLAN filtering on port ",
                swPort->getID());

  // Set the speed and ingress vlan before enabling
  program(swPort);

  // Enable packet and byte counter statistic collection.
  rv = opennsl_port_stat_enable_set(unit_, gport_, true);
  if (rv != OPENNSL_E_EXISTS) {
    // Don't throw an error if counter collection is already enabled
    bcmCheckError(rv, "Unexpected error enabling counter DMA on port ",
                  swPort->getID());
  }

  // Enable linkscan
  rv = opennsl_linkscan_mode_set(unit_, port_, OPENNSL_LINKSCAN_MODE_SW);
  bcmCheckError(rv, "Failed to enable linkscan on port ", swPort->getID());

  rv = opennsl_port_enable_set(unit_, port_, true);
  bcmCheckError(rv, "failed to enable port ", swPort->getID());
}
Exemple #9
0
bool BcmPort::isUp() {
  if (!isEnabled()) {
    return false;
  }
  int linkStatus;
  auto rv = opennsl_port_link_status_get(hw_->getUnit(), port_, &linkStatus);
  bcmCheckError(rv, "could not find if the port ", port_, " is up or down...");
  return linkStatus == OPENNSL_PORT_LINK_STATUS_UP;
}
Exemple #10
0
void BcmRoute::programLpmRoute(opennsl_if_t egressId,
    const RouteNextHopEntry& fwd) {
  opennsl_l3_route_t rt;
  initL3RouteT(&rt);
  rt.l3a_intf = egressId;
  if (fwd.getNextHopSet().size() > 1) {         // multipath
    rt.l3a_flags |= OPENNSL_L3_MULTIPATH;
  }

  bool addRoute = false;
  const auto warmBootCache = hw_->getWarmBootCache();
  auto vrfAndPfx2RouteCitr = warmBootCache->findRoute(vrf_, prefix_, len_);
  if (vrfAndPfx2RouteCitr != warmBootCache->vrfAndPrefix2Route_end()) {
    // Lambda to compare if the routes are equivalent and thus we need to
    // do nothing
    auto equivalent =
      [=] (const opennsl_l3_route_t& newRoute,
           const opennsl_l3_route_t& existingRoute) {
      // Compare flags (primarily MULTIPATH vs non MULTIPATH
      // and egress id.
      return existingRoute.l3a_flags == newRoute.l3a_flags &&
      existingRoute.l3a_intf == newRoute.l3a_intf;
    };
    if (!equivalent(rt, vrfAndPfx2RouteCitr->second)) {
      VLOG (3) << "Updating route for : " << prefix_ << "/"
        << static_cast<int>(len_) << " in vrf : " << vrf_;
      // This is a change
      rt.l3a_flags |= OPENNSL_L3_REPLACE;
      addRoute = true;
    } else {
      VLOG(3) << " Route for : " << prefix_ << "/" << static_cast<int>(len_)
        << " in vrf : " << vrf_ << " already exists";
    }
  } else {
    addRoute = true;
  }
  if (addRoute) {
    if (vrfAndPfx2RouteCitr == warmBootCache->vrfAndPrefix2Route_end()) {
      VLOG (3) << "Adding route for : " << prefix_ << "/"
        << static_cast<int>(len_) << " in vrf : " << vrf_;
    }
    if (added_) {
      rt.l3a_flags |= OPENNSL_L3_REPLACE;
    }
    auto rc = opennsl_l3_route_add(hw_->getUnit(), &rt);
    bcmCheckError(rc, "failed to create a route entry for ", prefix_, "/",
        static_cast<int>(len_), " @ ", fwd, " @egress ", egressId);
    VLOG(3) << "created a route entry for " << prefix_.str() << "/"
      << static_cast<int>(len_) << " @egress " << egressId
      << " with " << fwd;
  }
  if (vrfAndPfx2RouteCitr != warmBootCache->vrfAndPrefix2Route_end()) {
    warmBootCache->programmed(vrfAndPfx2RouteCitr);
  }
}
Exemple #11
0
void BcmUnit::attach() {
  if (attached_.load(std::memory_order_acquire)) {
    throw FbossError("unit ", unit_, " already initialized");
  }

  auto rv = opennsl_switch_event_register(unit_, switchEventCallback, this);
  bcmCheckError(rv, "unable to register switch event callback for unit ",
                unit_);

  attached_.store(true, std::memory_order_release);
}
Exemple #12
0
BcmPort::BcmPort(BcmSwitch* hw, opennsl_port_t port,
                 BcmPlatformPort* platformPort)
    : hw_(hw),
      port_(port),
      platformPort_(platformPort),
      unit_(hw->getUnit()) {
  // Obtain the gport handle from the port handle.
  int rv = opennsl_port_gport_get(unit_, port_, &gport_);
  bcmCheckError(rv, "Failed to get gport for BCM port ", port_);

  // Initialize our stats data structures
  reinitPortStats();

  VLOG(2) << "created BCM port:" << port_ << ", gport:" << gport_
          << ", FBOSS PortID:" << platformPort_->getPortID();
}
Exemple #13
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);
  }
}
Exemple #14
0
void BcmPort::enableLinkscan() {
  int rv = opennsl_linkscan_mode_set(unit_, port_, OPENNSL_LINKSCAN_MODE_SW);
  bcmCheckError(rv, "Failed to enable linkscan on port ", port_);
}
Exemple #15
0
bool BcmPort::isEnabled() {
  int enabled;
  auto rv = opennsl_port_enable_get(unit_, port_, &enabled);
  bcmCheckError(rv, "Failed to determine if port is already disabled");
  return static_cast<bool>(enabled);
}
Exemple #16
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());
    }
  }
}