Ejemplo n.º 1
0
void UnresolvedNhopsProber::timeoutExpired() noexcept {
  std::lock_guard<std::mutex> g(lock_);
  auto state = sw_->getState();
  for (const auto& ridAndNhopsRefCounts : nhops2RouteCount_) {
    for (const auto& nhopAndRefCount : ridAndNhopsRefCounts.second) {
      const auto& nhop = nhopAndRefCount.first;
      auto intf = state->getInterfaces()->getInterfaceIf(nhop.intf);
      if (!intf) {
        continue; // interface got unconfigured
      }
      // Probe all nexthops for which either don't have a L2 entry
      // or the entry is not resolved (port == 0). Note that we do
      // not exclude pending entries here since in case of recursive
      // routes we might get packets with destination set to prefix
      // that needs to be resolved recursively. In ARP and NDP code
      // we do not do route lookup when deciding to send ARP/NDP requests.
      // So we would only try to ARP/NDP for the destination if it
      // is in one of the interface subnets (which it won't be else
      // we won't have needed recursive resolution). So ARP/NDP for
      // all unresolved next hops. We could also consider doing route
      // lookups in ARP/NDP code, but by probing all unresolved next
      // hops we effectively do the same thing, since the next hops
      // probed come from after the route was (recursively) resolved.
      auto vlan = state->getVlans()->getVlanIf(intf->getVlanID());
      CHECK(vlan); // must have vlan for configrued inteface
      if (nhop.nexthop.isV4()) {
        auto nhop4 = nhop.nexthop.asV4();
        auto arpEntry = vlan->getArpTable()->getEntryIf(nhop4);
        if (!arpEntry || arpEntry->getPort() == 0) {
          VLOG(2) <<" Sending probe for unresolved next hop: " << nhop4;
          ArpHandler::sendArpRequest(sw_, vlan, nhop4);
        }
      } else {
        auto nhop6 = nhop.nexthop.asV6();
        auto ndpEntry = vlan->getNdpTable()->getEntryIf(nhop6);
        if (!ndpEntry || ndpEntry->getPort() == 0) {
          VLOG(2) <<" Sending probe for unresolved next hop: " << nhop6;
          IPv6Handler::sendNeighborSolicitation(sw_, nhop6, vlan);
        }
      }
    }
  }
  scheduleTimeout(interval_);

}
Ejemplo n.º 2
0
void IPv4Handler::handlePacket(unique_ptr<RxPacket> pkt,
                               MacAddress dst,
                               MacAddress src,
                               Cursor cursor) {
  SwitchStats* stats = sw_->stats();
  PortID port = pkt->getSrcPort();

  const uint32_t l3Len = pkt->getLength() - (cursor - Cursor(pkt->buf()));
  stats->port(port)->ipv4Rx();
  IPv4Hdr v4Hdr(cursor);
  VLOG(4) << "Rx IPv4 packet (" << l3Len << " bytes) " << v4Hdr.srcAddr.str()
          << " --> " << v4Hdr.dstAddr.str()
          << " proto: 0x" << std::hex << static_cast<int>(v4Hdr.protocol);

  // retrieve the current switch state
  auto state = sw_->getState();
  // Need to check if the packet is for self or not. We store our IP
  // in the ARP response table. Use that for now.
  auto vlan = state->getVlans()->getVlanIf(pkt->getSrcVlan());
  if (!vlan) {
    stats->port(port)->pktDropped();
    return;
  }

  if (v4Hdr.protocol == IPPROTO_UDP) {
    Cursor udpCursor(cursor);
    UDPHeader udpHdr;
    udpHdr.parse(sw_, port, &udpCursor);
    VLOG(4) << "UDP packet, Source port :" << udpHdr.srcPort
        << " destination port: " << udpHdr.dstPort;
    if (DHCPv4Handler::isDHCPv4Packet(udpHdr)) {
      DHCPv4Handler::handlePacket(sw_, std::move(pkt), src, dst, v4Hdr,
          udpHdr, udpCursor);
      return;
    }
  }

  auto dstIP = v4Hdr.dstAddr;
  // Handle packets destined for us
  // TODO: assume vrf 0 now
  if (state->getInterfaces()->getInterfaceIf(RouterID(0), IPAddress(dstIP))) {
    // TODO: Also check to see if this is the broadcast address for one of the
    // interfaces on this VLAN.  We should probably build up a more efficient
    // data structure to look up this information.
    stats->port(port)->ipv4Mine();
    // Anything not handled by the controller, we will forward it to the host,
    // i.e. ping, ssh, bgp...
    // FixME: will do another diff to set length in RxPacket, so that it
    // can be reused here.
    if (sw_->sendPacketToHost(std::move(pkt))) {
      stats->port(port)->pktToHost(l3Len);
    } else {
      stats->port(port)->pktDropped();
    }
    return;
  }

  // if packet is not for us, check the ttl exceed
  if (v4Hdr.ttl <= 1) {
    VLOG(4) << "Rx IPv4 Packet with TTL expired";
    stats->port(port)->pktDropped();
    stats->port(port)->ipv4TtlExceeded();
    // Look up cpu mac from platform
    MacAddress cpuMac = sw_->getPlatform()->getLocalMac();
    sendICMPTimeExceeded(pkt->getSrcVlan(), cpuMac, cpuMac, v4Hdr, cursor);
    return;
  }

  // Handle broadcast packets.
  // TODO: Also check to see if this is the broadcast address for one of the
  // interfaces on this VLAN. We should probably build up a more efficient
  // data structure to look up this information.
  if (dstIP.isLinkLocalBroadcast()) {
    stats->port(port)->pktDropped();
    return;
  }

  // TODO: check the reason of punt, for now, assume it is for
  // resolving the address
  // We will need to manage the rate somehow. Either from HW
  // or a SW control here
  stats->port(port)->ipv4Nexthop();
  if (!resolveMac(state.get(), dstIP)) {
    stats->port(port)->ipv4NoArp();
    VLOG(3) << "Cannot find the interface to send out ARP request for "
      << dstIP.str();
  }
  // TODO: ideally, we need to store this packet until the ARP is done and
  // then send this pkt out. For now, just drop it.
  stats->port(port)->pktDropped();
}
Ejemplo n.º 3
0
shared_ptr<SwitchState> ThriftConfigApplier::run() {
    auto newState = orig_->clone();
    bool changed = false;

    processVlanPorts();

    {
        auto newPorts = updatePorts();
        if (newPorts) {
            newState->resetPorts(std::move(newPorts));
            changed = true;
        }
    }

    {
        auto newIntfs = updateInterfaces();
        if (newIntfs) {
            newState->resetIntfs(std::move(newIntfs));
            changed = true;
        }
    }

    // Note: updateInterfaces() must be called before updateVlans(),
    // as updateInterfaces() populates the vlanInterfaces_ data structure.
    {
        auto newVlans = updateVlans();
        if (newVlans) {
            newState->resetVlans(std::move(newVlans));
            changed = true;
        }
    }

    // Note: updateInterfaces() must be called before updateRouteTables(),
    // as updateInterfaces() populates the intfRouteTables_ data structure.
    {
        auto newTables = updateRouteTables();
        if (newTables) {
            newState->resetRouteTables(std::move(newTables));
            changed = true;
        }
    }

    // Make sure all interfaces refer to valid VLANs.
    auto newVlans = newState->getVlans();
    for (const auto& vlanInfo : vlanInterfaces_) {
        if (newVlans->getVlanIf(vlanInfo.first) == nullptr) {
            throw FbossError("Interface ",
                             *(vlanInfo.second.interfaces.begin()),
                             " refers to non-existent VLAN ", vlanInfo.first);
        }
    }

    VlanID dfltVlan(cfg_->defaultVlan);
    if (orig_->getDefaultVlan() != dfltVlan) {
        if (newVlans->getVlanIf(dfltVlan) == nullptr) {
            throw FbossError("Default VLAN ", dfltVlan, " does not exist");
        }
        newState->setDefaultVlan(dfltVlan);
        changed = true;
    }

    std::chrono::seconds arpAgerInterval(cfg_->arpAgerInterval);
    if (orig_->getArpAgerInterval() != arpAgerInterval) {
        newState->setArpAgerInterval(arpAgerInterval);
        changed = true;
    }

    if (!changed) {
        return nullptr;
    }
    return newState;
}