org.opendaylight.openflowplugin.pyretic.ODLHandlerSimpleImpl.java Source code

Java tutorial

Introduction

Here is the source code for org.opendaylight.openflowplugin.pyretic.ODLHandlerSimpleImpl.java

Source

/**
 * Copyright (c) 2014, NetIDE Consortium (Create-Net (CN), Telefonica Investigacion Y Desarrollo SA (TID), Fujitsu 
 * Technology Solutions GmbH (FTS), Thales Communications & Security SAS (THALES), Fundacion Imdea Networks (IMDEA),
 * Universitaet Paderborn (UPB), Intel Research & Innovation Ireland Ltd (IRIIL) )
 *
 * All rights reserved. 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
 *
 * Authors:
 *     Telefonica I+D
 */
/**
 * Copyright (c) 2014 Cisco Systems, Inc. and others.  All rights reserved.
 *
 * 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.opendaylight.openflowplugin.pyretic;

import java.util.Arrays;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Map;
import java.util.Set;
import java.util.concurrent.atomic.AtomicLong;

import org.opendaylight.controller.sal.action.Output;
import org.opendaylight.openflowplugin.pyretic.Utils.FlowUtils;
import org.opendaylight.openflowplugin.pyretic.Utils.InstanceIdentifierUtils;
import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.yang.types.rev100924.MacAddress;
import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.FlowId;
import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.tables.Table;
import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.tables.table.Flow;
import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.tables.table.FlowBuilder;
import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.tables.table.FlowKey;
import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.NodeConnectorId;
import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.NodeConnectorRef;
import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.NodeId;
import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.NodeRef;
import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.node.NodeConnector;
import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.node.NodeConnectorKey;
import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.nodes.Node;
import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.nodes.NodeKey;
import org.opendaylight.yang.gen.v1.urn.opendaylight.packet.service.rev130709.*;
import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import org.json.simple.JSONObject;
import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.Nodes;
import com.telefonica.pyretic.backendchannel.BackendChannel;

import java.util.ArrayList;
import java.util.List;
import org.opendaylight.openflowplugin.pyretic.Utils.OutputUtils;

/**
 * Simple Learning Switch implementation which does mac learning for one switch.
 *
 /**
 * Created by Jennifer Hernndez Bcares
 */
public class ODLHandlerSimpleImpl implements ODLHandler, PacketProcessingListener {

    private static final Logger LOG = LoggerFactory.getLogger(ODLHandler.class);

    private static final byte[] ETH_TYPE_IPV4 = new byte[] { 0x08, 0x00 };
    private static final byte[] ETH_TYPE_IPV6 = new byte[] { (byte) 0x86, (byte) 0xdd };
    private static final byte[] ETH_TYPE_LLDP = new byte[] { (byte) 0x88, (byte) 0xcc };
    private static final byte[] ETH_TYPE_ARP = new byte[] { (byte) 0x08, (byte) 0x06 };

    private static final int DIRECT_FLOW_PRIORITY = 512;

    private DataChangeListenerRegistrationHolder registrationPublisher;
    private FlowCommitWrapper dataStoreAccessor;
    private PacketProcessingService packetProcessingService;

    private boolean iAmLearning = false;

    private NodeId nodeId;
    private AtomicLong flowIdInc = new AtomicLong();
    private AtomicLong flowCookieInc = new AtomicLong(0x2a00000000000000L);

    private InstanceIdentifier<Node> nodePath;
    private InstanceIdentifier<Table> tablePath;

    private Map<MacAddress, NodeConnectorRef> mac2portMapping;
    private Set<String> coveredMacPaths;

    private BackendChannel channel;
    private int switches = 0;

    @Override
    public synchronized void onSwitchAppeared(InstanceIdentifier<Table> appearedTablePath) {

        if (iAmLearning) {
            LOG.debug("already learning a node, skipping {}", nodeId.getValue());
            return;
        }

        LOG.debug("expected table acquired, learning ..");

        // disable listening - simple learning handles only one node (switch)
        if (registrationPublisher != null) {
            try {
                LOG.debug("closing dataChangeListenerRegistration");
                registrationPublisher.getDataChangeListenerRegistration().close();
            } catch (Exception e) {
                LOG.error("closing registration upon flowCapable node update listener failed: " + e.getMessage(),
                        e);
            }
        }

        iAmLearning = true;

        tablePath = appearedTablePath;
        nodePath = tablePath.firstIdentifierOf(Node.class);
        nodeId = nodePath.firstKeyOf(Node.class, NodeKey.class).getId();
        mac2portMapping = new HashMap<>();
        coveredMacPaths = new HashSet<>();

        // start forwarding all packages to controller
        FlowId flowId = new FlowId(String.valueOf(flowIdInc.getAndIncrement()));
        FlowKey flowKey = new FlowKey(flowId);
        InstanceIdentifier<Flow> flowPath = InstanceIdentifierUtils.createFlowPath(tablePath, flowKey);

        int priority = 0;
        // create flow in table with id = 0, priority = 4 (other params are
        // defaulted in OFDataStoreUtil)
        FlowBuilder allToCtrlFlow = FlowUtils
                .createFwdAllToControllerFlow(InstanceIdentifierUtils.getTableId(tablePath), priority, flowId);

        System.out.println("--->writing packetForwardToController flow");
        LOG.debug("writing packetForwardToController flow");
        dataStoreAccessor.writeFlowToConfig(flowPath, allToCtrlFlow.build());

        // FIXME
        switches++;
        String p = "[\"switch\", \"join\", " + switches + ", \"BEGIN\"]";
        String p21 = "[\"port\", \"join\", " + switches
                + ", 1, true, false, [\"OFPPF_COPPER\", \"OFPPF_10GB_FD\"]]";
        String p22 = "[\"port\", \"join\", " + switches
                + ", 2, true, false, [\"OFPPF_COPPER\", \"OFPPF_10GB_FD\"]]";
        String p23 = "[\"port\", \"join\", " + switches
                + ", 3, true, false, [\"OFPPF_COPPER\", \"OFPPF_10GB_FD\"]]";
        String p3 = "[\"switch\", \"join\", " + switches + ", \"END\"]";
        this.channel.push(p);
        sleep();
        this.channel.push(p21);
        sleep();
        this.channel.push(p22);
        sleep();
        this.channel.push(p23);
        sleep();
        this.channel.push(p3);
        System.out.println(p + "\n" + p21 + "\n" + p22 + "\n" + p23 + "\n" + p3);

    }

    // new
    private void sleep() {
        try {
            Thread.sleep(800);
        } catch (InterruptedException ex) {
            Thread.currentThread().interrupt();
        }
    }
    // end new

    @Override
    public void setRegistrationPublisher(DataChangeListenerRegistrationHolder registrationPublisher) {
        this.registrationPublisher = registrationPublisher;
    }

    @Override
    public void setDataStoreAccessor(FlowCommitWrapper dataStoreAccessor) {
        this.dataStoreAccessor = dataStoreAccessor;
    }

    @Override
    public void setPacketProcessingService(PacketProcessingService packetProcessingService) {
        this.packetProcessingService = packetProcessingService;
    }

    public synchronized void onPacketReceived(PacketReceived notification) {
        //LOG.debug("-----New packet arrived");

        byte[] etherType = PacketUtils.extractEtherType(notification.getPayload());
        byte[] dstMacRaw = PacketUtils.extractDstMac(notification.getPayload());
        byte[] srcMacRaw = PacketUtils.extractSrcMac(notification.getPayload());

        MacAddress dstMac = PacketUtils.rawMacToMac(dstMacRaw);
        MacAddress srcMac = PacketUtils.rawMacToMac(srcMacRaw);

        /* LOG.debug("srcmac init");
         LOG.debug(srcMac.getValue());
         LOG.debug("dstmac init");
         LOG.debug(dstMac.getValue());*/

        NodeConnectorKey ingressKey = InstanceIdentifierUtils
                .getNodeConnectorKey(notification.getIngress().getValue());
        String path = ingressKey.getId().getValue();

        String[] msg = null;
        String switch_s = null;
        String inport = null;
        if (path.contains(":")) {
            msg = path.split(":");
            switch_s = msg[1];
            inport = msg[2];

            List<Integer> raw = new ArrayList<Integer>();
            for (byte b : notification.getPayload()) {
                int aux = (int) b;
                if (aux < 0) {
                    aux = 256 + aux;
                }
                raw.add(aux);
            }

            /*LOG.debug("Ethertype: " ); // + etherType.toString());
            for(int i = 0; i < etherType.length; i++) {
            LOG.debug("%02x ",0xff & etherType[i]);
            }
            LOG.debug("");*/

            if (Arrays.equals(ETH_TYPE_IPV4, etherType)) {
                //LOG.debug("IPV4 packet arrived");

                JSONObject json = new JSONObject();
                json.put("switch", Integer.parseInt(switch_s));
                json.put("inport", Integer.parseInt(inport));
                json.put("raw", raw);

                List<String> p = new ArrayList<String>();
                p.add("\"packet\"");
                p.add(json.toString());
                // LOG.debug("" + p);

                this.channel.push(p.toString() + "\n");
                //mac2portMapping.put(srcMac, notification.getIngress());
            } else if (Arrays.equals(ETH_TYPE_IPV6, etherType)) {
                // Handle IPV6 packet
                JSONObject json = new JSONObject();

                json.put("switch", Integer.parseInt(switch_s));
                json.put("inport", Integer.parseInt(inport));
                json.put("raw", raw);

                List<String> p = new ArrayList<String>();
                p.add("\"packet\"");
                p.add(json.toString());
                // LOG.debug("" + p);
                this.channel.push(p.toString() + "\n");
                //mac2portMapping.put(srcMac, notification.getIngress());
            } else if (Arrays.equals(ETH_TYPE_ARP, etherType)) {
                // Handle ARP packet
                // LOG.debug("ARP packet arrived");
                JSONObject json = new JSONObject();

                json.put("switch", Integer.parseInt(switch_s));
                json.put("inport", Integer.parseInt(inport));
                json.put("raw", raw);

                List<String> p = new ArrayList<String>();
                p.add("\"packet\"");
                p.add(json.toString());

                this.channel.push(p.toString() + "\n");
                mac2portMapping.put(srcMac, notification.getIngress());

            } else if (Arrays.equals(ETH_TYPE_LLDP, etherType)) {
                //Handle lldp packet
                //LOG.debug("LLDP packet arrived");

                JSONObject json = new JSONObject();

                json.put("switch", Integer.parseInt(switch_s));
                json.put("inport", Integer.parseInt(inport));
                json.put("raw", raw);

                List<String> p = new ArrayList<String>();
                p.add("\"packet\"");
                p.add(json.toString());
                this.channel.push(p.toString() + "\n");

                mac2portMapping.put(srcMac, notification.getIngress());
            } else {
                LOG.debug("Unknown packet arrived.\nThis shouldn't be happening");
            }
        } else {
            throw new IllegalArgumentException("String " + path + " does not contain -");
        }
    }

    public void setBackendChannel(BackendChannel channel) {
        this.channel = channel;
    }

    // basurilla
    static InstanceIdentifier<NodeConnector> createNodeConnectorId(String nodeKey, String nodeConnectorKey) {
        return InstanceIdentifier.builder(Nodes.class).child(Node.class, new NodeKey(new NodeId(nodeKey)))
                .child(NodeConnector.class, new NodeConnectorKey(new NodeConnectorId(nodeConnectorKey))).build();
    }
    //

    @Override
    public void sendToSwitch(JSONObject json, String type) {

        if (type.equals("packet")) {

            Integer swtch = ((Long) json.get("switch")).intValue();
            Integer inport = ((Long) json.get("inport")).intValue();
            Integer outport = ((Long) json.get("outport")).intValue();

            String inNodeKey = "openflow:" + swtch.toString();
            String inPort = inport.toString();
            String outPort = outport.toString(); //

            /* LOG.debug("innodekey: " + inNodeKey);
             LOG.debug("inport: " + inPort);
             LOG.debug("outport: " + outPort);*/

            ////////////////////////////////////////////////////////
            // Get the raw from the json
            List<Long> raw = (List<Long>) json.get("raw");
            StringBuilder sb = new StringBuilder("");
            for (Long b : raw) {
                sb.append(OutputUtils.fromDecimalToHex(b));
            }
            byte[] payload = OutputUtils.toByteArray(sb.toString());
            //System.out.println("My payload: " + sb.toString().toUpperCase());
            ////////////////////////////////////////////////////////

            /*
                        ////////////////////////////////////////////////////////
                        // Get the source mac from the json
                        raw = (List<Long>) json.get("srcmac");
                        sb = new StringBuilder("");
                        for (Long b : raw) {
            if (b != 58) sb.append((char)b.byteValue());
                        }
                        byte[] srcMac = OutputUtils.toByteArray(sb.toString());
                        System.out.println("My sb src: " + sb.toString().toUpperCase());
                        ////////////////////////////////////////////////////////
                
                
                        ////////////////////////////////////////////////////////
                        // Get the dst mac from the json
                        raw = (List<Long>) json.get("dstmac");
                        sb = new StringBuilder("");
                        for (Long b : raw) {
            if (b != 58) sb.append((char)b.byteValue());
                        }
                        byte[] dstMac = OutputUtils.toByteArray(sb.toString());
                        System.out.println("My sb dst: " + sb.toString().toUpperCase());
                        ////////////////////////////////////////////////////////
                
                        ////////////////////////////////////////////////////////
                        // Get the src ip from the json
                        raw = (List<Long>) json.get("srcip");
                        sb = new StringBuilder("");
                        for (Long b : raw) {
            if (b != 46) sb.append((char)b.byteValue());
                        }
                        byte[] srcip = OutputUtils.toByteArray(sb.toString());
                        System.out.println("My src ip: " + sb.toString().toUpperCase());
                        ////////////////////////////////////////////////////////
                
                
                        ////////////////////////////////////////////////////////
                        // Get the dst ip from the json
                        raw = (List<Long>) json.get("dstip");
                        sb = new StringBuilder("");
                        for (Long b : raw) {
            if (b != 46) sb.append((char)b.byteValue());
                        }
                        byte[] dstip = OutputUtils.toByteArray(sb.toString());
                        System.out.println("My dst ip: " + sb.toString().toUpperCase());
                        ////////////////////////////////////////////////////////
            */
            /*
            Ethernet types in pyretic:
                         HEX    -> Decimal
            LLDP_TYPE  = 0x88cc -> 35020
            ARP_TYPE   = 0x806  -> 2054
            IP_TYPE    = 0x800  -> 2048
            IPV6_TYPE  = 0x86dd -> 34525
            */
            TransmitPacketInput input = null;
            /* Integer ethtype = ((Long) json.get("ethtype")).intValue();
             if (ethtype == 2054) {
            LOG.debug("ARP");
             }
             else if (ethtype == 2048)
            LOG.debug("IP");*/

            input = OutputUtils.createPacketOut(inNodeKey, payload, outPort, inPort);

            packetProcessingService.transmitPacket(input);
            // LOG.debug("Transmitted <<<");
        }

        else {
            LOG.debug("Different type <<<<<< " + type);
        }
    }

}