org.sdnmq.jms_demoapps.SimplePacketSender.java Source code

Java tutorial

Introduction

Here is the source code for org.sdnmq.jms_demoapps.SimplePacketSender.java

Source

/**
 * SimplePacketSender
 * Copyright (c) 2014 Frank Duerr
 *
 * SimplePacketSender is part of SDN-MQ. This program and the accompanying materials 
 * are made available under the terms of the Eclipse Public License v1.0 which 
 * accompanies this distribution, and is available at http://www.eclipse.org/legal/epl-v10.html
 */

package org.sdnmq.jms_demoapps;

import java.net.InetAddress;
import java.net.UnknownHostException;

import javax.jms.JMSException;
import javax.jms.Queue;
import javax.jms.QueueConnection;
import javax.jms.QueueConnectionFactory;
import javax.jms.QueueSender;
import javax.jms.QueueSession;
import javax.jms.Session;
import javax.jms.TextMessage;
import javax.naming.Context;
import javax.naming.InitialContext;
import javax.naming.NameNotFoundException;
import javax.naming.NamingException;
import javax.xml.bind.DatatypeConverter;

import org.json.JSONArray;
import org.json.JSONObject;
import org.opendaylight.controller.sal.packet.Ethernet;
import org.opendaylight.controller.sal.packet.IPv4;
import org.opendaylight.controller.sal.packet.PacketException;
import org.opendaylight.controller.sal.packet.RawPacket;
import org.opendaylight.controller.sal.packet.UDP;
import org.sdnmq.jms.json.ActionAttributes;
import org.sdnmq.jms.json.FlowAttributes;
import org.sdnmq.jms.json.FlowProgrammerRequestAttributes;
import org.sdnmq.jms.json.MatchAttributes;
import org.sdnmq.jms.json.NodeAttributes;
import org.sdnmq.jms.json.PacketForwarderRequestAttributes;

/**
 * Demo applications for SDN-MQ showing how to use the packer forwarder.
 * 
 * For a general introduction to JMS, you might want to read this tutorial:
 * http://docs.oracle.com/javaee/1.3/jms/tutorial/
 * 
 * @author Frank Duerr
 */
public class SimplePacketSender {
    static final String PACKETFORWARDER_QUEUE_NAME = "org.sdnmq.packetout";

    private static Context ctx = null;
    private static QueueConnectionFactory queueFactory = null;
    private static QueueConnection connection = null;
    private static QueueSession session = null;
    private static Queue packetForwarderQueue = null;
    private static QueueSender sender = null;

    private static void die(int status) {
        if (sender != null) {
            try {
                sender.close();
            } catch (JMSException e) {
            }
        }

        if (session != null) {
            try {
                session.close();
            } catch (JMSException e) {
            }
        }

        if (connection != null) {
            try {
                connection.close();
            } catch (JMSException e) {
            }
        }

        System.exit(status);
    }

    public static void main(String[] args) {
        // Standard JMS setup.
        try {
            // Uses settings from file jndi.properties if file is in CLASSPATH.
            ctx = new InitialContext();
        } catch (NamingException e) {
            System.err.println(e.getMessage());
            die(-1);
        }

        try {
            queueFactory = (QueueConnectionFactory) ctx.lookup("QueueConnectionFactory");
        } catch (NamingException e) {
            System.err.println(e.getMessage());
            die(-1);
        }

        try {
            connection = queueFactory.createQueueConnection();
        } catch (JMSException e) {
            System.err.println(e.getMessage());
            die(-1);
        }

        try {
            session = connection.createQueueSession(false, Session.AUTO_ACKNOWLEDGE);
        } catch (JMSException e) {
            System.err.println(e.getMessage());
            die(-1);
        }

        try {
            packetForwarderQueue = (Queue) ctx.lookup(PACKETFORWARDER_QUEUE_NAME);
        } catch (NameNotFoundException e) {
            System.err.println(e.getMessage());
            die(-1);
        } catch (NamingException e) {
            System.err.println(e.getMessage());
            die(-1);
        }

        try {
            sender = session.createSender(packetForwarderQueue);
        } catch (JMSException e) {
            System.err.println(e.getMessage());
            die(-1);
        }

        try {
            connection.start();
        } catch (JMSException e) {
            System.err.println(e.getMessage());
            die(-1);
        }

        // Create packet using OpenDaylight packet classes (or any other packet parser/constructor you like most)
        // In most use cases, you will not create the complete packet yourself from scratch
        // but rather use a packet received from a packet-in event as basis. Let's assume that
        // the received packet-in event looks like this (in JSON representation as delivered by
        // the packet-in handler):
        //
        // {"node":{"id":"00:00:00:00:00:00:00:01","type":"OF"},"ingressPort":"1","protocol":1,"etherType":2048,"nwDst":"10.0.0.2","packet":"Io6q62g3mn66JKnjCABFAABUAABAAEABJqcKAAABCgAAAggAGFlGXgABELmmUwAAAAAVaA4AAAAAABAREhMUFRYXGBkaGxwdHh8gISIjJCUmJygpKissLS4vMDEyMzQ1Njc=","dlDst":"22:8E:AA:EB:68:37","nwSrc":"10.0.0.1","dlSrc":"9A:7E:BA:24:A9:E3"}
        //
        // Thus, we can use the "packet" field to re-construct the raw packet data from Base64-encoding:
        String packetInBase64 = "Io6q62g3mn66JKnjCABFAABUAABAAEABJqcKAAABCgAAAggAGFlGXgABELmmUwAAAAAVaA4AAAAAABAREhMUFRYXGBkaGxwdHh8gISIjJCUmJygpKissLS4vMDEyMzQ1Njc=";
        byte[] packetData = DatatypeConverter.parseBase64Binary(packetInBase64);
        // Now we can use the OpenDaylight classes to get Java objects for this packet:
        Ethernet ethPkt = new Ethernet();
        try {
            ethPkt.deserialize(packetData, 0, packetData.length * 8);
        } catch (Exception e) {
            System.err.println("Failed to decode packet");
            die(-1);
        }
        if (ethPkt.getEtherType() == 0x800) {
            IPv4 ipv4Pkt = (IPv4) ethPkt.getPayload();
            // We could go on parsing layer by layer ... but you got the idea already I think.
            // So let's make some change to the packet to make it more interesting:
            InetAddress newDst = null;
            try {
                newDst = InetAddress.getByName("10.0.0.2");
            } catch (UnknownHostException e) {
                die(-1);
            }
            assert (newDst != null);
            ipv4Pkt.setDestinationAddress(newDst);
        }
        // Now we can get the binary data of the new packet to be forwarded.
        byte[] pktBinary = null;
        try {
            pktBinary = ethPkt.serialize();
        } catch (PacketException e1) {
            System.err.println("Failed to serialize packet");
            die(-1);
        }
        assert (pktBinary != null);

        // Encode packet to Base64 textual representation to be sent in JSON.
        String pktBase64 = DatatypeConverter.printBase64Binary(pktBinary);

        // We need to tell the packet forwarder, which node should forward the packet.
        // In OpenDaylight, a node is identified by node id and node type (like "OF" for OpenFlow).
        // For a list of all node attributes, cf. class NodeAttributes.
        // For a list of possible node types, cf. class NodeAttributes.TypeValues.
        JSONObject nodeJson = new JSONObject();
        String nodeId = "00:00:00:00:00:00:00:01";
        nodeJson.put(NodeAttributes.Keys.ID.toJSON(), nodeId);
        nodeJson.put(NodeAttributes.Keys.TYPE.toJSON(), NodeAttributes.TypeValues.OF.toJSON());

        // Create a packet forwarding request in JSON representation.
        // All attributes are described in class PacketForwarderRequestAttributes.
        JSONObject packetFwdRequestJson = new JSONObject();
        packetFwdRequestJson.put(PacketForwarderRequestAttributes.Keys.NODE.toJSON(), nodeJson);
        packetFwdRequestJson.put(PacketForwarderRequestAttributes.Keys.EGRESS_PORT.toJSON(), 1);
        packetFwdRequestJson.put(PacketForwarderRequestAttributes.Keys.PACKET.toJSON(), pktBase64);

        // Send the request by posting it to the packet forwarder queue.

        System.out.println("Sending packet forwarding request: ");
        System.out.println(packetFwdRequestJson.toString());

        try {
            TextMessage msg = session.createTextMessage();
            msg.setText(packetFwdRequestJson.toString());
            sender.send(msg);
        } catch (JMSException e) {
            System.err.println(e.getMessage());
            die(-1);
        }

        die(0);
    }

}