Example #1
0
  /**
   * Sends an APR request for the target IP address to all ports except in-port.
   *
   * @param deviceId Switch device ID
   * @param targetAddress target IP address for ARP
   * @param inPort in-port
   */
  public void sendArpRequest(DeviceId deviceId, IpAddress targetAddress, ConnectPoint inPort) {
    byte[] senderMacAddress;
    byte[] senderIpAddress;

    try {
      senderMacAddress = config.getDeviceMac(deviceId).toBytes();
      senderIpAddress = config.getRouterIp(deviceId).toOctets();
    } catch (DeviceConfigNotFoundException e) {
      log.warn(e.getMessage() + " Aborting sendArpRequest.");
      return;
    }

    ARP arpRequest = new ARP();
    arpRequest
        .setHardwareType(ARP.HW_TYPE_ETHERNET)
        .setProtocolType(ARP.PROTO_TYPE_IP)
        .setHardwareAddressLength((byte) Ethernet.DATALAYER_ADDRESS_LENGTH)
        .setProtocolAddressLength((byte) Ip4Address.BYTE_LENGTH)
        .setOpCode(ARP.OP_REQUEST)
        .setSenderHardwareAddress(senderMacAddress)
        .setTargetHardwareAddress(MacAddress.ZERO.toBytes())
        .setSenderProtocolAddress(senderIpAddress)
        .setTargetProtocolAddress(targetAddress.toOctets());

    Ethernet eth = new Ethernet();
    eth.setDestinationMACAddress(MacAddress.BROADCAST.toBytes())
        .setSourceMACAddress(senderMacAddress)
        .setEtherType(Ethernet.TYPE_ARP)
        .setPayload(arpRequest);

    removeVlanAndFlood(eth, inPort);
  }
Example #2
0
/**
 * Monitors hosts on the dataplane to detect changes in host data.
 *
 * <p>The HostMonitor can monitor hosts that have already been detected for changes. At an
 * application's request, it can also monitor and actively probe for hosts that have not yet been
 * detected (specified by IP address).
 */
public class HostMonitor implements TimerTask {
  private PacketService packetService;
  private HostManager hostManager;
  private InterfaceService interfaceService;

  private final Set<IpAddress> monitoredAddresses;

  private final ConcurrentMap<ProviderId, HostProvider> hostProviders;

  private static final long DEFAULT_PROBE_RATE = 30000; // milliseconds
  private static final byte[] ZERO_MAC_ADDRESS = MacAddress.ZERO.toBytes();
  private long probeRate = DEFAULT_PROBE_RATE;

  private Timeout timeout;

  /**
   * Creates a new host monitor.
   *
   * @param packetService packet service used to send packets on the data plane
   * @param hostManager host manager used to look up host information and probe existing hosts
   * @param interfaceService interface service for interface information
   */
  public HostMonitor(
      PacketService packetService, HostManager hostManager, InterfaceService interfaceService) {

    this.packetService = packetService;
    this.hostManager = hostManager;
    this.interfaceService = interfaceService;

    monitoredAddresses = Collections.newSetFromMap(new ConcurrentHashMap<>());
    hostProviders = new ConcurrentHashMap<>();
  }

  /**
   * Adds an IP address to be monitored by the host monitor. The monitor will periodically probe the
   * host to detect changes.
   *
   * @param ip IP address of the host to monitor
   */
  void addMonitoringFor(IpAddress ip) {
    monitoredAddresses.add(ip);
  }

  /**
   * Stops monitoring the given IP address.
   *
   * @param ip IP address to stop monitoring on
   */
  void stopMonitoring(IpAddress ip) {
    monitoredAddresses.remove(ip);
  }

  /** Starts the host monitor. Does nothing if the monitor is already running. */
  void start() {
    synchronized (this) {
      if (timeout == null) {
        timeout = Timer.getTimer().newTimeout(this, 0, TimeUnit.MILLISECONDS);
      }
    }
  }

  /** Stops the host monitor. */
  void shutdown() {
    synchronized (this) {
      timeout.cancel();
      timeout = null;
    }
  }

  /**
   * Registers a host provider with the host monitor. The monitor can use the provider to probe
   * hosts.
   *
   * @param provider the host provider to register
   */
  void registerHostProvider(HostProvider provider) {
    hostProviders.put(provider.id(), provider);
  }

  @Override
  public void run(Timeout timeout) throws Exception {
    for (IpAddress ip : monitoredAddresses) {
      Set<Host> hosts = hostManager.getHostsByIp(ip);

      if (hosts.isEmpty()) {
        sendArpNdpRequest(ip);
      } else {
        for (Host host : hosts) {
          HostProvider provider = hostProviders.get(host.providerId());
          if (provider == null) {
            hostProviders.remove(host.providerId(), null);
          } else {
            provider.triggerProbe(host);
          }
        }
      }
    }

    this.timeout = Timer.getTimer().newTimeout(this, probeRate, TimeUnit.MILLISECONDS);
  }

  /**
   * Sends an ARP or Neighbor Discovery Protocol request for the given IP address.
   *
   * @param targetIp IP address to send the request for
   */
  private void sendArpNdpRequest(IpAddress targetIp) {
    Interface intf = interfaceService.getMatchingInterface(targetIp);

    if (intf == null) {
      return;
    }

    for (InterfaceIpAddress ia : intf.ipAddresses()) {
      if (ia.subnetAddress().contains(targetIp)) {
        sendArpNdpProbe(intf.connectPoint(), targetIp, ia.ipAddress(), intf.mac(), intf.vlan());
      }
    }
  }

  private void sendArpNdpProbe(
      ConnectPoint connectPoint,
      IpAddress targetIp,
      IpAddress sourceIp,
      MacAddress sourceMac,
      VlanId vlan) {
    Ethernet probePacket = null;

    if (targetIp.isIp4()) {
      // IPv4: Use ARP
      probePacket = buildArpRequest(targetIp, sourceIp, sourceMac, vlan);
    } else {
      // IPv6: Use Neighbor Discovery
      probePacket = buildNdpRequest(targetIp, sourceIp, sourceMac, vlan);
    }

    List<Instruction> instructions = new ArrayList<>();
    instructions.add(Instructions.createOutput(connectPoint.port()));

    TrafficTreatment treatment =
        DefaultTrafficTreatment.builder().setOutput(connectPoint.port()).build();

    OutboundPacket outboundPacket =
        new DefaultOutboundPacket(
            connectPoint.deviceId(), treatment, ByteBuffer.wrap(probePacket.serialize()));

    packetService.emit(outboundPacket);
  }

  private Ethernet buildArpRequest(
      IpAddress targetIp, IpAddress sourceIp, MacAddress sourceMac, VlanId vlan) {

    ARP arp = new ARP();
    arp.setHardwareType(ARP.HW_TYPE_ETHERNET)
        .setHardwareAddressLength((byte) Ethernet.DATALAYER_ADDRESS_LENGTH)
        .setProtocolType(ARP.PROTO_TYPE_IP)
        .setProtocolAddressLength((byte) IpAddress.INET_BYTE_LENGTH)
        .setOpCode(ARP.OP_REQUEST);

    arp.setSenderHardwareAddress(sourceMac.toBytes())
        .setSenderProtocolAddress(sourceIp.toOctets())
        .setTargetHardwareAddress(ZERO_MAC_ADDRESS)
        .setTargetProtocolAddress(targetIp.toOctets());

    Ethernet ethernet = new Ethernet();
    ethernet
        .setEtherType(Ethernet.TYPE_ARP)
        .setDestinationMACAddress(MacAddress.BROADCAST)
        .setSourceMACAddress(sourceMac)
        .setPayload(arp);

    if (!vlan.equals(VlanId.NONE)) {
      ethernet.setVlanID(vlan.toShort());
    }

    ethernet.setPad(true);

    return ethernet;
  }

  private Ethernet buildNdpRequest(
      IpAddress targetIp, IpAddress sourceIp, MacAddress sourceMac, VlanId vlan) {

    // Create the Ethernet packet
    Ethernet ethernet = new Ethernet();
    ethernet
        .setEtherType(Ethernet.TYPE_IPV6)
        .setDestinationMACAddress(MacAddress.BROADCAST)
        .setSourceMACAddress(sourceMac);
    if (!vlan.equals(VlanId.NONE)) {
      ethernet.setVlanID(vlan.toShort());
    }

    //
    // Create the IPv6 packet
    //
    // TODO: The destination IP address should be the
    // solicited-node multicast address
    IPv6 ipv6 = new IPv6();
    ipv6.setSourceAddress(sourceIp.toOctets());
    ipv6.setDestinationAddress(targetIp.toOctets());
    ipv6.setHopLimit((byte) 255);

    // Create the ICMPv6 packet
    ICMP6 icmp6 = new ICMP6();
    icmp6.setIcmpType(ICMP6.NEIGHBOR_SOLICITATION);
    icmp6.setIcmpCode((byte) 0);

    // Create the Neighbor Solication packet
    NeighborSolicitation ns = new NeighborSolicitation();
    ns.setTargetAddress(targetIp.toOctets());
    ns.addOption(NeighborDiscoveryOptions.TYPE_SOURCE_LL_ADDRESS, sourceMac.toBytes());

    icmp6.setPayload(ns);
    ipv6.setPayload(icmp6);
    ethernet.setPayload(ipv6);

    return ethernet;
  }
}