Handling packets on the OpenDaylight controller

One of the actions that an OpenFlow switch can take is to punt a packet to the controller.  This example will take a look at how we can see those packets, and do something with them.  I hope to follow this up with another post that does something more exciting, but for now I’ll just try to print out what type of packet it is.  This is one of the things that (as far as I know)  you would only be able to do with an OSGi module, and is not available via the REST API.

First we create our Maven pom.xml with the required imports. In this case we’ll need some parts of the SAL and switchmanager:


<project xmlns="http://maven.apache.org/POM/4.0.0&quot; xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance&quot;
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd"&gt;
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>org.opendaylight.controller</groupId>
<artifactId>commons.opendaylight</artifactId>
<version>1.4.0-SNAPSHOT</version>
<relativePath>../../../controller/opendaylight/commons/opendaylight</relativePath>
</parent>
<groupId>com.example</groupId>
<artifactId>getpackets</artifactId>
<name>getpackets</name>
<url>http://maven.apache.org</url&gt;
<packaging>bundle</packaging>
<build>
<plugins>
<plugin>
<groupId>org.apache.felix</groupId>
<artifactId>maven-bundle-plugin</artifactId>
<version>2.3.6</version>
<extensions>true</extensions>
<configuration>
<instructions>
<Import-Package>
org.opendaylight.controller.sal.core,
org.opendaylight.controller.sal.packet,
org.opendaylight.controller.sal.utils,
org.opendaylight.controller.switchmanager,
org.slf4j,
org.apache.felix.dm
</Import-Package>
<Bundle-Activator>
com.example.getpackets.Activator
</Bundle-Activator>
<Export-Package>
com.example.getpackets
</Export-Package>
</instructions>
</configuration>
</plugin>
</plugins>
</build>
<dependencies>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>3.8.1</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.opendaylight.controller</groupId>
<artifactId>switchmanager</artifactId>
<version>0.4.0-SNAPSHOT</version>
</dependency>
<dependency>
<groupId>org.opendaylight.controller</groupId>
<artifactId>sal</artifactId>
<version>0.5.0-SNAPSHOT</version>
</dependency>
</dependencies>
</project>

view raw

pom.xml

hosted with ❤ by GitHub

 
Now we can create our activator. The key ingredient here is to register for callbacks from the Data Packet Service via OSGi in our public void configureInstance method:

            c.add(createContainerServiceDependency(containerName).setService(
                    IDataPacketService.class).setCallbacks(
                    "setDataPacketService", "unsetDataPacketService")
                    .setRequired(true));

This ties into methods that we implement in our GetPackets class:

    void setDataPacketService(IDataPacketService s) {
        this.dataPacketService = s;
    }

    void unsetDataPacketService(IDataPacketService s) {
        if (this.dataPacketService == s) {
            this.dataPacketService = null;
        }
    }

We make the class implement the IListenDataPacket interface to get notified of packets received on the controller:

public class GetPackets implements IListenDataPacket

And we override the public PacketResult receiveDataPacket(RawPacket inPkt) method:

    @Override
    public PacketResult receiveDataPacket(RawPacket inPkt) {
        if (inPkt == null) {
            return PacketResult.IGNORED;
        }
        log.trace("Received a frame of size: {}",
                        inPkt.getPacketData().length);
        Packet formattedPak = this.dataPacketService.decodeDataPacket(inPkt);
        System.out.println("packet");
        System.out.println(formattedPak);        
        if (formattedPak instanceof Ethernet) {
            System.out.println(formattedPak);
            Object nextPak = formattedPak.getPayload();
            if (nextPak instanceof IPv4) {
                IPv4 ipPak = (IPv4)nextPak;
                System.out.println("IP");
                log.trace("Handled IP packet");
                int sipAddr = ipPak.getSourceAddress();
                InetAddress sip = NetUtils.getInetAddress(sipAddr);
                int dipAddr = ipPak.getDestinationAddress();
                InetAddress dip = NetUtils.getInetAddress(dipAddr);
                System.out.println("SRC IP:");
                System.out.println(sip);
                System.out.println("DST IP:");
                System.out.println(dip);

                Object frame = ipPak.getPayload();
                if (frame instanceof ICMP) {
                    System.out.println("ICMP from instance");
                }
                String protocol = IPProtocols.getProtocolName(ipPak.getProtocol());
                if (protocol == IPProtocols.ICMP.toString()) {
                    ICMP icmpPak = (ICMP)ipPak.getPayload();
                    System.out.println("ICMP from checking protocol");
                    handleICMPPacket((Ethernet) formattedPak, icmpPak, inPkt.getIncomingNodeConnector());
                }
            }
        }
        return PacketResult.IGNORED;
    }

You’ll notice that we can keep going into the different payloads of the frame/packet to get to the next network layer. However, using instanceof can be slow, so an alternative is to pull out the protocol field, and do a comparison. In my example I’ve specifically handled ICMP packets, and used both methods for determining if the IP packet is ICMP.

15 thoughts on “Handling packets on the OpenDaylight controller

  1. Excellent Stuff indeed Fred… I was wondering whether the controller need to examine/snoop all packets on the network but your “Punting” method is really Nice.

      • init0 says:

        Hi fredhsu, the system.out.println is used inside the receiveDataPacket function, and now opendaylight log shows some TRACE infos, but still no system.out.println string.

  2. pankaj says:

    Hi,
    Thanks for uploading your knowledge. Its really helpful.
    Actually i was trying to create an ODL application which would capture a packet from OVS and reply to ovs switch. But i needed OF 1.3, so i used integration version of ODL. The directory structure is different than the controller version of ODL.
    can you suggest me what are the things that i need to consider in this case?

    Thanks,
    Pankaj

    • Hi Pankaj, sorry for the delayed response. I haven’t really looked at ODL lately, but I’m guessing the wiki or IRC channel are your best bet. If you have something specific that you’re trying to do I can try to help.

  3. jayakeerthi says:

    [SwitchEvent Thread] WARN o.o.c.s.i.internal.DataPacketService – Failed to decode packet: 133
    please let me know how to solve this issue.

  4. Kavita says:

    Hello Fred

    I am trying to receive packets from switch on my opendaylight. I am using receiveDataPackets() routine to receive packets, following ODL examples. For some reason, I am not receiving any packet from the switch. I would appreciate your insight

    thanks

    Kavita

Leave a reply to fredhsu Cancel reply