Beispiel #1
0
  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;
  }
Beispiel #2
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);
  }
Beispiel #3
0
  private void handleArpReply(DeviceId deviceId, ConnectPoint inPort, Ethernet payload) {
    ARP arpReply = (ARP) payload.getPayload();
    VlanId vlanId = VlanId.vlanId(payload.getVlanID());
    HostId targetHostId =
        HostId.hostId(MacAddress.valueOf(arpReply.getTargetHardwareAddress()), vlanId);

    // ARP reply for router. Process all pending IP packets.
    if (isArpForRouter(deviceId, arpReply)) {
      Ip4Address hostIpAddress = Ip4Address.valueOf(arpReply.getSenderProtocolAddress());
      srManager.ipHandler.forwardPackets(deviceId, hostIpAddress);
    } else {
      Host targetHost = srManager.hostService.getHost(targetHostId);
      // ARP reply for known hosts. Forward to the host.
      if (targetHost != null) {
        removeVlanAndForward(payload, targetHost.location());
        // ARP reply for unknown host, Flood in the subnet.
      } else {
        // Don't flood to non-edge ports
        if (vlanId.equals(VlanId.vlanId(SegmentRoutingManager.ASSIGNED_VLAN_NO_SUBNET))) {
          return;
        }
        removeVlanAndFlood(payload, inPort);
      }
    }
  }
Beispiel #4
0
  /**
   * Deserializer function for ARP packets.
   *
   * @return deserializer function
   */
  public static Deserializer<ARP> deserializer() {
    return (data, offset, length) -> {
      checkInput(data, offset, length, INITIAL_HEADER_LENGTH);

      ARP arp = new ARP();
      final ByteBuffer bb = ByteBuffer.wrap(data, offset, length);
      arp.setHardwareType(bb.getShort());
      arp.setProtocolType(bb.getShort());

      byte hwAddressLength = bb.get();
      arp.setHardwareAddressLength(hwAddressLength);

      byte protocolAddressLength = bb.get();
      arp.setProtocolAddressLength(protocolAddressLength);
      arp.setOpCode(bb.getShort());

      // Check we have enough space for the addresses
      checkHeaderLength(
          length, INITIAL_HEADER_LENGTH + 2 * hwAddressLength + 2 * protocolAddressLength);

      arp.senderHardwareAddress = new byte[0xff & hwAddressLength];
      bb.get(arp.senderHardwareAddress, 0, arp.senderHardwareAddress.length);
      arp.senderProtocolAddress = new byte[0xff & protocolAddressLength];
      bb.get(arp.senderProtocolAddress, 0, arp.senderProtocolAddress.length);
      arp.targetHardwareAddress = new byte[0xff & hwAddressLength];
      bb.get(arp.targetHardwareAddress, 0, arp.targetHardwareAddress.length);
      arp.targetProtocolAddress = new byte[0xff & protocolAddressLength];
      bb.get(arp.targetProtocolAddress, 0, arp.targetProtocolAddress.length);

      return arp;
    };
  }
  @Test
  public void emit() {

    MacAddress mac1 = MacAddress.of("00:00:00:11:00:01");
    MacAddress mac2 = MacAddress.of("00:00:00:22:00:02");

    ARP arp = new ARP();
    arp.setSenderProtocolAddress(ANY)
        .setSenderHardwareAddress(mac1.getBytes())
        .setTargetHardwareAddress(mac2.getBytes())
        .setTargetProtocolAddress(ANY)
        .setHardwareType((short) 0)
        .setProtocolType((short) 0)
        .setHardwareAddressLength((byte) 6)
        .setProtocolAddressLength((byte) 4)
        .setOpCode((byte) 0);

    Ethernet eth = new Ethernet();
    eth.setVlanID(VLANID)
        .setEtherType(Ethernet.TYPE_ARP)
        .setSourceMACAddress("00:00:00:11:00:01")
        .setDestinationMACAddress("00:00:00:22:00:02")
        .setPayload(arp);

    // the should-be working setup.
    OutboundPacket passPkt = outPacket(DID, TR, eth);
    sw.setRole(RoleState.MASTER);
    provider.emit(passPkt);
    assertEquals("invalid switch", sw, controller.current);
    assertEquals("message not sent", PLIST.size(), sw.sent.size());
    sw.sent.clear();

    // wrong Role
    // sw.setRole(RoleState.SLAVE);
    // provider.emit(passPkt);
    // assertEquals("invalid switch", sw, controller.current);
    // assertEquals("message sent incorrectly", 0, sw.sent.size());

    // sw.setRole(RoleState.MASTER);

    // missing switch
    OutboundPacket swFailPkt = outPacket(DID_MISSING, TR, eth);
    provider.emit(swFailPkt);
    assertNull("invalid switch", controller.current);
    assertEquals("message sent incorrectly", 0, sw.sent.size());

    // to missing port
    // OutboundPacket portFailPkt = outPacket(DID, TR_MISSING, eth);
    // provider.emit(portFailPkt);
    // assertEquals("extra message sent", 1, sw.sent.size());

  }
    @Override
    public InboundPacket inPacket() {
      ARP arp = new ARP();
      arp.setSenderProtocolAddress(IP)
          .setSenderHardwareAddress(MAC.toBytes())
          .setTargetHardwareAddress(BCMAC.toBytes())
          .setTargetProtocolAddress(IP);

      Ethernet eth = new Ethernet();
      eth.setEtherType(Ethernet.TYPE_ARP)
          .setVlanID(VLAN.toShort())
          .setSourceMACAddress(MAC.toBytes())
          .setDestinationMACAddress(BCMAC)
          .setPayload(arp);
      ConnectPoint receivedFrom = new ConnectPoint(deviceId(deviceId), portNumber(INPORT));
      return new DefaultInboundPacket(receivedFrom, eth, ByteBuffer.wrap(eth.serialize()));
    }
Beispiel #7
0
  private void sendArpResponse(ARP arpRequest, MacAddress targetMac, VlanId vlanId) {
    ARP arpReply = new ARP();
    arpReply
        .setHardwareType(ARP.HW_TYPE_ETHERNET)
        .setProtocolType(ARP.PROTO_TYPE_IP)
        .setHardwareAddressLength((byte) Ethernet.DATALAYER_ADDRESS_LENGTH)
        .setProtocolAddressLength((byte) Ip4Address.BYTE_LENGTH)
        .setOpCode(ARP.OP_REPLY)
        .setSenderHardwareAddress(targetMac.toBytes())
        .setSenderProtocolAddress(arpRequest.getTargetProtocolAddress())
        .setTargetHardwareAddress(arpRequest.getSenderHardwareAddress())
        .setTargetProtocolAddress(arpRequest.getSenderProtocolAddress());

    Ethernet eth = new Ethernet();
    eth.setDestinationMACAddress(arpRequest.getSenderHardwareAddress())
        .setSourceMACAddress(targetMac.toBytes())
        .setEtherType(Ethernet.TYPE_ARP)
        .setPayload(arpReply);

    MacAddress hostMac = MacAddress.valueOf(arpReply.getTargetHardwareAddress());
    HostId dstId = HostId.hostId(hostMac, vlanId);
    Host dst = srManager.hostService.getHost(dstId);
    if (dst == null) {
      log.warn("Cannot send ARP response to host {}", dstId);
      return;
    }

    TrafficTreatment treatment =
        DefaultTrafficTreatment.builder().setOutput(dst.location().port()).build();
    OutboundPacket packet =
        new DefaultOutboundPacket(
            dst.location().deviceId(), treatment, ByteBuffer.wrap(eth.serialize()));

    srManager.packetService.emit(packet);
  }
Beispiel #8
0
  /**
   * Processes incoming ARP packets.
   *
   * <p>If it is an ARP request to router itself or known hosts, then it sends ARP response. If it
   * is an ARP request to unknown hosts in its own subnet, then it flood the ARP request to the
   * ports. If it is an ARP response, then set a flow rule for the host and forward any IP packets
   * to the host in the packet buffer to the host.
   *
   * <p>Note: We handles all ARP packet in, even for those ARP packets between hosts in the same
   * subnet. For an ARP packet with broadcast destination MAC, some switches pipelines will send it
   * to the controller due to table miss, other swithches will flood the packets directly in the
   * data plane without packet in. We can deal with both cases.
   *
   * @param pkt incoming packet
   */
  public void processPacketIn(InboundPacket pkt) {

    Ethernet ethernet = pkt.parsed();
    ARP arp = (ARP) ethernet.getPayload();

    ConnectPoint connectPoint = pkt.receivedFrom();
    PortNumber inPort = connectPoint.port();
    DeviceId deviceId = connectPoint.deviceId();
    byte[] senderMacAddressByte = arp.getSenderHardwareAddress();
    Ip4Address hostIpAddress = Ip4Address.valueOf(arp.getSenderProtocolAddress());

    srManager.routingRulePopulator.populateIpRuleForHost(
        deviceId, hostIpAddress, MacAddress.valueOf(senderMacAddressByte), inPort);

    if (arp.getOpCode() == ARP.OP_REQUEST) {
      handleArpRequest(deviceId, connectPoint, ethernet);
    } else {
      handleArpReply(deviceId, connectPoint, ethernet);
    }
  }
Beispiel #9
0
  private void handleArpRequest(DeviceId deviceId, ConnectPoint inPort, Ethernet payload) {
    ARP arpRequest = (ARP) payload.getPayload();
    VlanId vlanId = VlanId.vlanId(payload.getVlanID());
    HostId targetHostId =
        HostId.hostId(MacAddress.valueOf(arpRequest.getTargetHardwareAddress()), vlanId);

    // ARP request for router. Send ARP reply.
    if (isArpForRouter(deviceId, arpRequest)) {
      Ip4Address targetAddress = Ip4Address.valueOf(arpRequest.getTargetProtocolAddress());
      sendArpResponse(arpRequest, config.getRouterMacForAGatewayIp(targetAddress), vlanId);
    } else {
      Host targetHost = srManager.hostService.getHost(targetHostId);
      // ARP request for known hosts. Send proxy ARP reply on behalf of the target.
      if (targetHost != null) {
        removeVlanAndForward(payload, targetHost.location());
        // ARP request for unknown host in the subnet. Flood in the subnet.
      } else {
        removeVlanAndFlood(payload, inPort);
      }
    }
  }
Beispiel #10
0
  /**
   * Builds an ARP reply based on a request.
   *
   * @param srcIp the IP address to use as the reply source
   * @param srcMac the MAC address to use as the reply source
   * @param request the ARP request we got
   * @return an Ethernet frame containing the ARP reply
   */
  public static Ethernet buildArpReply(Ip4Address srcIp, MacAddress srcMac, Ethernet request) {

    Ethernet eth = new Ethernet();
    eth.setDestinationMACAddress(request.getSourceMAC());
    eth.setSourceMACAddress(srcMac);
    eth.setEtherType(Ethernet.TYPE_ARP);
    eth.setVlanID(request.getVlanID());

    ARP arp = new ARP();
    arp.setOpCode(ARP.OP_REPLY);
    arp.setProtocolType(ARP.PROTO_TYPE_IP);
    arp.setHardwareType(ARP.HW_TYPE_ETHERNET);

    arp.setProtocolAddressLength((byte) Ip4Address.BYTE_LENGTH);
    arp.setHardwareAddressLength((byte) Ethernet.DATALAYER_ADDRESS_LENGTH);
    arp.setSenderHardwareAddress(srcMac.toBytes());
    arp.setTargetHardwareAddress(request.getSourceMACAddress());

    arp.setTargetProtocolAddress(((ARP) request.getPayload()).getSenderProtocolAddress());
    arp.setSenderProtocolAddress(srcIp.toInt());

    eth.setPayload(arp);
    return eth;
  }
Beispiel #11
0
 private boolean isArpForRouter(DeviceId deviceId, ARP arpMsg) {
   Ip4Address targetProtocolAddress = Ip4Address.valueOf(arpMsg.getTargetProtocolAddress());
   Set<Ip4Address> gatewayIpAddresses = null;
   try {
     if (targetProtocolAddress.equals(config.getRouterIp(deviceId))) {
       return true;
     }
     gatewayIpAddresses = config.getPortIPs(deviceId);
   } catch (DeviceConfigNotFoundException e) {
     log.warn(e.getMessage() + " Aborting check for router IP in processing arp");
   }
   if (gatewayIpAddresses != null && gatewayIpAddresses.contains(targetProtocolAddress)) {
     return true;
   }
   return false;
 }
    @Override
    public void process(PacketContext context) {
      if (context == null) {
        return;
      }
      Ethernet eth = context.inPacket().parsed();

      if (eth == null) {
        return;
      }

      VlanId vlan = VlanId.vlanId(eth.getVlanID());
      ConnectPoint heardOn = context.inPacket().receivedFrom();

      // If this is not an edge port, bail out.
      Topology topology = topologyService.currentTopology();
      if (topologyService.isInfrastructure(topology, heardOn)) {
        return;
      }

      HostLocation hloc = new HostLocation(heardOn, System.currentTimeMillis());

      HostId hid = HostId.hostId(eth.getSourceMAC(), vlan);

      // ARP: possible new hosts, update both location and IP
      if (eth.getEtherType() == Ethernet.TYPE_ARP) {
        ARP arp = (ARP) eth.getPayload();
        IpAddress ip = IpAddress.valueOf(IpAddress.Version.INET, arp.getSenderProtocolAddress());
        HostDescription hdescr = new DefaultHostDescription(eth.getSourceMAC(), vlan, hloc, ip);
        providerService.hostDetected(hid, hdescr);

        // IPv4: update location only
      } else if (eth.getEtherType() == Ethernet.TYPE_IPV4) {
        HostDescription hdescr = new DefaultHostDescription(eth.getSourceMAC(), vlan, hloc);
        providerService.hostDetected(hid, hdescr);

        // NeighborAdvertisement and NeighborSolicitation: possible new hosts, update both location
        // and IP
        // IPv6: update location only
      } else if (eth.getEtherType() == Ethernet.TYPE_IPV6) {
        IpAddress ip = null;
        IPv6 ipv6 = (IPv6) eth.getPayload();

        IPacket iPkt = ipv6;
        while (iPkt != null) {
          if (iPkt instanceof NeighborAdvertisement || iPkt instanceof NeighborSolicitation) {
            IpAddress sourceAddress =
                IpAddress.valueOf(IpAddress.Version.INET6, ipv6.getSourceAddress());
            // Ignore DAD packets, in which source address is all zeros.
            if (!sourceAddress.isZero()) {
              ip = sourceAddress;
              break;
            }
          }
          iPkt = iPkt.getPayload();
        }
        HostDescription hdescr =
            (ip == null)
                ? new DefaultHostDescription(eth.getSourceMAC(), vlan, hloc)
                : new DefaultHostDescription(eth.getSourceMAC(), vlan, hloc, ip);
        providerService.hostDetected(hid, hdescr);
      }
    }