IcmpHandler.java 5.42 KB
/*
 * Copyright 2015 Open Networking Laboratory
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
package org.onosproject.bgprouter;

import java.nio.ByteBuffer;

import org.onlab.packet.Ethernet;
import org.onlab.packet.ICMP;
import org.onlab.packet.IPv4;
import org.onlab.packet.IpAddress;
import org.onosproject.net.ConnectPoint;
import org.onosproject.net.flow.DefaultTrafficTreatment;
import org.onosproject.net.flow.TrafficTreatment;
import org.onosproject.net.host.InterfaceIpAddress;
import org.onosproject.net.packet.DefaultOutboundPacket;
import org.onosproject.net.packet.InboundPacket;
import org.onosproject.net.packet.OutboundPacket;
import org.onosproject.net.packet.PacketContext;
import org.onosproject.net.packet.PacketProcessor;
import org.onosproject.net.packet.PacketService;
import org.onosproject.routing.config.Interface;
import org.onosproject.routing.config.RoutingConfigurationService;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

public class IcmpHandler {

    private static final Logger log = LoggerFactory.getLogger(IcmpHandler.class);

    private final PacketService packetService;
    private final RoutingConfigurationService configService;

    private final IcmpProcessor processor = new IcmpProcessor();


    public IcmpHandler(RoutingConfigurationService configService,
                       PacketService packetService) {
        this.configService = configService;
        this.packetService = packetService;
    }

    public void start() {
        packetService.addProcessor(processor, PacketProcessor.ADVISOR_MAX + 4);
    }

    public void stop() {
        packetService.removeProcessor(processor);
    }

    private void processPacketIn(InboundPacket pkt) {

        boolean ipMatches = false;
        Ethernet ethernet = pkt.parsed();
        IPv4 ipv4 = (IPv4) ethernet.getPayload();
        ConnectPoint connectPoint = pkt.receivedFrom();
        IpAddress destIpAddress = IpAddress.valueOf(ipv4.getDestinationAddress());
        Interface targetInterface = configService.getMatchingInterface(destIpAddress);

        if (targetInterface == null) {
            log.trace("No matching interface for {}", destIpAddress);
            return;
        }

        for (InterfaceIpAddress interfaceIpAddress: targetInterface.ipAddresses()) {
            if (interfaceIpAddress.ipAddress().equals(destIpAddress)) {
                ipMatches = true;
                break;
            }
        }

        if (((ICMP) ipv4.getPayload()).getIcmpType() == ICMP.TYPE_ECHO_REQUEST &&
                ipMatches) {
            sendICMPResponse(ethernet, connectPoint);
        }
    }

    private void sendICMPResponse(Ethernet icmpRequest, ConnectPoint outport) {

        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 = (ICMP) icmpRequestIpv4.getPayload().clone();
        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());
        icmpReplyEth.setVlanID(icmpRequest.getVlanID());

        sendPacketOut(outport, icmpReplyEth);

    }

    private void sendPacketOut(ConnectPoint outport, Ethernet payload) {
        TrafficTreatment treatment = DefaultTrafficTreatment.builder().
                setOutput(outport.port()).build();
        OutboundPacket packet = new DefaultOutboundPacket(outport.deviceId(),
                treatment, ByteBuffer.wrap(payload.serialize()));
        packetService.emit(packet);
    }

    /**
     * Packet processor responsible receiving and filtering ICMP packets.
     */
    private class IcmpProcessor implements PacketProcessor {

        @Override
        public void process(PacketContext context) {
            // Stop processing if the packet has been handled, since we
            // can't do any more to it.

            if (context.isHandled()) {
                return;
            }

            Ethernet packet = context.inPacket().parsed();

            if (packet == null) {
                return;
            }

            if (packet.getEtherType() == Ethernet.TYPE_IPV4) {
                IPv4 ipv4Packet = (IPv4) packet.getPayload();
                if (ipv4Packet.getProtocol() == IPv4.PROTOCOL_ICMP) {
                    processPacketIn(context.inPacket());
                }
            }
        }
    }

}