private void sendPacketOut(ConnectPoint outport, Ethernet payload, int sid) { IPv4 ipPacket = (IPv4) payload.getPayload(); Ip4Address destIpAddress = Ip4Address.valueOf(ipPacket.getDestinationAddress()); if (sid == -1 || config.getSegmentId(payload.getDestinationMAC()) == sid || config.inSameSubnet(outport.deviceId(), destIpAddress)) { TrafficTreatment treatment = DefaultTrafficTreatment.builder().setOutput(outport.port()).build(); OutboundPacket packet = new DefaultOutboundPacket( outport.deviceId(), treatment, ByteBuffer.wrap(payload.serialize())); srManager.packetService.emit(packet); } else { log.info("Send a MPLS packet as a ICMP response"); TrafficTreatment treatment = DefaultTrafficTreatment.builder().setOutput(outport.port()).build(); payload.setEtherType(Ethernet.MPLS_UNICAST); MPLS mplsPkt = new MPLS(); mplsPkt.setLabel(sid); mplsPkt.setTtl(((IPv4) payload.getPayload()).getTtl()); mplsPkt.setPayload(payload.getPayload()); payload.setPayload(mplsPkt); OutboundPacket packet = new DefaultOutboundPacket( outport.deviceId(), treatment, ByteBuffer.wrap(payload.serialize())); srManager.packetService.emit(packet); } }
@Override public InboundPacket inPacket() { IPv4 ipv4 = new IPv4(); ipv4.setDestinationAddress("10.0.0.1"); ipv4.setSourceAddress(IP_ADDRESS.toString()); Ethernet eth = new Ethernet(); eth.setEtherType(Ethernet.TYPE_IPV4) .setVlanID(VLAN.toShort()) .setSourceMACAddress(MAC) .setDestinationMACAddress(MacAddress.valueOf("00:00:00:00:00:01")) .setPayload(ipv4); ConnectPoint receivedFrom = new ConnectPoint(deviceId(deviceId), portNumber(INPORT)); return new DefaultInboundPacket(receivedFrom, eth, ByteBuffer.wrap(eth.serialize())); }
private void transformAndSend(IPv4 ipv4, Interface egressInterface, MacAddress macAddress) { Ethernet eth = new Ethernet(); eth.setDestinationMACAddress(macAddress); eth.setSourceMACAddress(egressInterface.mac()); eth.setEtherType(EthType.EtherType.IPV4.ethType().toShort()); eth.setPayload(ipv4); if (!egressInterface.vlan().equals(VlanId.NONE)) { eth.setVlanID(egressInterface.vlan().toShort()); } ipv4.setTtl((byte) (ipv4.getTtl() - 1)); ipv4.setChecksum((short) 0); send(eth, egressInterface.connectPoint()); }
private void handle(Ethernet eth) { checkNotNull(eth); if (!(eth.getEtherType() == EthType.EtherType.IPV4.ethType().toShort())) { return; } IPv4 ipv4 = (IPv4) eth.getPayload().clone(); Ip4Address dstIp = Ip4Address.valueOf(ipv4.getDestinationAddress()); Interface egressInterface = interfaceService.getMatchingInterface(dstIp); if (egressInterface == null) { log.info("No egress interface found for {}", dstIp); return; } Optional<Host> host = hostService .getHostsByIp(dstIp) .stream() .filter(h -> h.location().equals(egressInterface.connectPoint())) .filter(h -> h.vlan().equals(egressInterface.vlan())) .findAny(); if (host.isPresent()) { transformAndSend(ipv4, egressInterface, host.get().mac()); } else { hostService.startMonitoringIp(dstIp); ipPacketCache .asMap() .compute( dstIp, (ip, queue) -> { if (queue == null) { queue = new ConcurrentLinkedQueue(); } queue.add(ipv4); return queue; }); } }
/** * Process incoming ICMP packet. If it is an ICMP request to router or known host, then sends an * ICMP response. If it is an ICMP packet to known host and forward the packet to the host. If it * is an ICMP packet to unknown host in a subnet, then sends an ARP request to the subnet. * * @param pkt inbound packet */ public void processPacketIn(InboundPacket pkt) { Ethernet ethernet = pkt.parsed(); IPv4 ipv4 = (IPv4) ethernet.getPayload(); ConnectPoint connectPoint = pkt.receivedFrom(); DeviceId deviceId = connectPoint.deviceId(); Ip4Address destinationAddress = Ip4Address.valueOf(ipv4.getDestinationAddress()); Set<Ip4Address> gatewayIpAddresses = config.getPortIPs(deviceId); Ip4Address routerIp; try { routerIp = config.getRouterIp(deviceId); } catch (DeviceConfigNotFoundException e) { log.warn(e.getMessage() + " Aborting processPacketIn."); return; } IpPrefix routerIpPrefix = IpPrefix.valueOf(routerIp, IpPrefix.MAX_INET_MASK_LENGTH); Ip4Address routerIpAddress = routerIpPrefix.getIp4Prefix().address(); // ICMP to the router IP or gateway IP if (((ICMP) ipv4.getPayload()).getIcmpType() == ICMP.TYPE_ECHO_REQUEST && (destinationAddress.equals(routerIpAddress) || gatewayIpAddresses.contains(destinationAddress))) { sendICMPResponse(ethernet, connectPoint); // ICMP for any known host } else if (!srManager.hostService.getHostsByIp(destinationAddress).isEmpty()) { // TODO: known host packet should not be coming to controller - resend flows? srManager.ipHandler.forwardPackets(deviceId, destinationAddress); // ICMP for an unknown host in the subnet of the router } else if (config.inSameSubnet(deviceId, destinationAddress)) { srManager.arpHandler.sendArpRequest(deviceId, destinationAddress, connectPoint); // ICMP for an unknown host } else { log.debug("ICMP request for unknown host {} ", destinationAddress); // Do nothing } }
// Install a rule forwarding the packet to the specified port. private void installRule(PacketContext context, PortNumber portNumber) { // // We don't support (yet) buffer IDs in the Flow Service so // packet out first. // Ethernet inPkt = context.inPacket().parsed(); TrafficSelector.Builder selectorBuilder = DefaultTrafficSelector.builder(); // If PacketOutOnly or ARP packet than forward directly to output port if (packetOutOnly || inPkt.getEtherType() == Ethernet.TYPE_ARP) { packetOut(context, portNumber); return; } // // If matchDstMacOnly // Create flows matching dstMac only // Else // Create flows with default matching and include configured fields // if (matchDstMacOnly) { selectorBuilder.matchEthDst(inPkt.getDestinationMAC()); } else { selectorBuilder .matchInPort(context.inPacket().receivedFrom().port()) .matchEthSrc(inPkt.getSourceMAC()) .matchEthDst(inPkt.getDestinationMAC()); // If configured Match Vlan ID if (matchVlanId && inPkt.getVlanID() != Ethernet.VLAN_UNTAGGED) { selectorBuilder.matchVlanId(VlanId.vlanId(inPkt.getVlanID())); } // // If configured and EtherType is IPv4 - Match IPv4 and // TCP/UDP/ICMP fields // if (matchIpv4Address && inPkt.getEtherType() == Ethernet.TYPE_IPV4) { IPv4 ipv4Packet = (IPv4) inPkt.getPayload(); byte ipv4Protocol = ipv4Packet.getProtocol(); Ip4Prefix matchIp4SrcPrefix = Ip4Prefix.valueOf(ipv4Packet.getSourceAddress(), Ip4Prefix.MAX_MASK_LENGTH); Ip4Prefix matchIp4DstPrefix = Ip4Prefix.valueOf(ipv4Packet.getDestinationAddress(), Ip4Prefix.MAX_MASK_LENGTH); selectorBuilder .matchEthType(Ethernet.TYPE_IPV4) .matchIPSrc(matchIp4SrcPrefix) .matchIPDst(matchIp4DstPrefix); if (matchIpv4Dscp) { byte dscp = ipv4Packet.getDscp(); byte ecn = ipv4Packet.getEcn(); selectorBuilder.matchIPDscp(dscp).matchIPEcn(ecn); } if (matchTcpUdpPorts && ipv4Protocol == IPv4.PROTOCOL_TCP) { TCP tcpPacket = (TCP) ipv4Packet.getPayload(); selectorBuilder .matchIPProtocol(ipv4Protocol) .matchTcpSrc(tcpPacket.getSourcePort()) .matchTcpDst(tcpPacket.getDestinationPort()); } if (matchTcpUdpPorts && ipv4Protocol == IPv4.PROTOCOL_UDP) { UDP udpPacket = (UDP) ipv4Packet.getPayload(); selectorBuilder .matchIPProtocol(ipv4Protocol) .matchUdpSrc(udpPacket.getSourcePort()) .matchUdpDst(udpPacket.getDestinationPort()); } if (matchIcmpFields && ipv4Protocol == IPv4.PROTOCOL_ICMP) { ICMP icmpPacket = (ICMP) ipv4Packet.getPayload(); selectorBuilder .matchIPProtocol(ipv4Protocol) .matchIcmpType(icmpPacket.getIcmpType()) .matchIcmpCode(icmpPacket.getIcmpCode()); } } // // If configured and EtherType is IPv6 - Match IPv6 and // TCP/UDP/ICMP fields // if (matchIpv6Address && inPkt.getEtherType() == Ethernet.TYPE_IPV6) { IPv6 ipv6Packet = (IPv6) inPkt.getPayload(); byte ipv6NextHeader = ipv6Packet.getNextHeader(); Ip6Prefix matchIp6SrcPrefix = Ip6Prefix.valueOf(ipv6Packet.getSourceAddress(), Ip6Prefix.MAX_MASK_LENGTH); Ip6Prefix matchIp6DstPrefix = Ip6Prefix.valueOf(ipv6Packet.getDestinationAddress(), Ip6Prefix.MAX_MASK_LENGTH); selectorBuilder .matchEthType(Ethernet.TYPE_IPV6) .matchIPv6Src(matchIp6SrcPrefix) .matchIPv6Dst(matchIp6DstPrefix); if (matchIpv6FlowLabel) { selectorBuilder.matchIPv6FlowLabel(ipv6Packet.getFlowLabel()); } if (matchTcpUdpPorts && ipv6NextHeader == IPv6.PROTOCOL_TCP) { TCP tcpPacket = (TCP) ipv6Packet.getPayload(); selectorBuilder .matchIPProtocol(ipv6NextHeader) .matchTcpSrc(tcpPacket.getSourcePort()) .matchTcpDst(tcpPacket.getDestinationPort()); } if (matchTcpUdpPorts && ipv6NextHeader == IPv6.PROTOCOL_UDP) { UDP udpPacket = (UDP) ipv6Packet.getPayload(); selectorBuilder .matchIPProtocol(ipv6NextHeader) .matchUdpSrc(udpPacket.getSourcePort()) .matchUdpDst(udpPacket.getDestinationPort()); } if (matchIcmpFields && ipv6NextHeader == IPv6.PROTOCOL_ICMP6) { ICMP6 icmp6Packet = (ICMP6) ipv6Packet.getPayload(); selectorBuilder .matchIPProtocol(ipv6NextHeader) .matchIcmpv6Type(icmp6Packet.getIcmpType()) .matchIcmpv6Code(icmp6Packet.getIcmpCode()); } } } TrafficTreatment treatment = DefaultTrafficTreatment.builder().setOutput(portNumber).build(); ForwardingObjective forwardingObjective = DefaultForwardingObjective.builder() .withSelector(selectorBuilder.build()) .withTreatment(treatment) .withPriority(flowPriority) .withFlag(ForwardingObjective.Flag.VERSATILE) .fromApp(appId) .makeTemporary(flowTimeout) .add(); flowObjectiveService.forward(context.inPacket().receivedFrom().deviceId(), forwardingObjective); // // If packetOutOfppTable // Send packet back to the OpenFlow pipeline to match installed flow // Else // Send packet direction on the appropriate port // if (packetOutOfppTable) { packetOut(context, PortNumber.TABLE); } else { packetOut(context, portNumber); } }
/** * Sends an ICMP reply message. * * <p>Note: we assume that packets sending from the edge switches to the hosts have untagged VLAN. * * @param icmpRequest the original ICMP request * @param outport the output port where the ICMP reply should be sent to */ private void sendICMPResponse(Ethernet icmpRequest, ConnectPoint outport) { // Note: We assume that packets arrive at the edge switches have // untagged VLAN. Ethernet icmpReplyEth = new Ethernet(); IPv4 icmpRequestIpv4 = (IPv4) icmpRequest.getPayload(); IPv4 icmpReplyIpv4 = new IPv4(); int destAddress = icmpRequestIpv4.getDestinationAddress(); icmpReplyIpv4.setDestinationAddress(icmpRequestIpv4.getSourceAddress()); icmpReplyIpv4.setSourceAddress(destAddress); icmpReplyIpv4.setTtl((byte) 64); icmpReplyIpv4.setChecksum((short) 0); ICMP icmpReply = new ICMP(); icmpReply.setPayload(((ICMP) icmpRequestIpv4.getPayload()).getPayload()); icmpReply.setIcmpType(ICMP.TYPE_ECHO_REPLY); icmpReply.setIcmpCode(ICMP.SUBTYPE_ECHO_REPLY); icmpReply.setChecksum((short) 0); icmpReplyIpv4.setPayload(icmpReply); icmpReplyEth.setPayload(icmpReplyIpv4); icmpReplyEth.setEtherType(Ethernet.TYPE_IPV4); icmpReplyEth.setDestinationMACAddress(icmpRequest.getSourceMACAddress()); icmpReplyEth.setSourceMACAddress(icmpRequest.getDestinationMACAddress()); Ip4Address destIpAddress = Ip4Address.valueOf(icmpReplyIpv4.getDestinationAddress()); Ip4Address destRouterAddress = config.getRouterIpAddressForASubnetHost(destIpAddress); int sid = config.getSegmentId(destRouterAddress); if (sid < 0) { log.warn("Cannot find the Segment ID for {}", destAddress); return; } sendPacketOut(outport, icmpReplyEth, sid); }