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); }
/** * 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); } }