eu.netide.shim.NetIDEShimController.java Source code

Java tutorial

Introduction

Here is the source code for eu.netide.shim.NetIDEShimController.java

Source

/*
 *  Copyright (c) 2016, 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), Fraunhofer-Institut fr
 *  Produktionstechnologie (IPT), Telcaria Ideas SL (TELCA) )
 *
 *  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: Antonio Marsico (antonio.marsico@create-net.org)
 */

package eu.netide.shim;

import com.google.common.collect.Maps;
import com.google.common.collect.Sets;
import eu.netide.lib.netip.HelloMessage;
import eu.netide.lib.netip.Message;
import eu.netide.lib.netip.MessageType;
import eu.netide.lib.netip.NetIPUtils;
import eu.netide.lib.netip.Protocol;
import eu.netide.lib.netip.ProtocolVersions;
import io.netty.buffer.ByteBuf;
import org.javatuples.Pair;
import org.jboss.netty.buffer.ChannelBuffer;
import org.jboss.netty.buffer.ChannelBuffers;
import org.onosproject.openflow.controller.Dpid;
import org.onosproject.openflow.controller.OpenFlowController;
import org.onosproject.openflow.controller.OpenFlowSwitch;
import org.projectfloodlight.openflow.protocol.OFActionType;
import org.projectfloodlight.openflow.protocol.OFBarrierReply;
import org.projectfloodlight.openflow.protocol.OFBarrierRequest;
import org.projectfloodlight.openflow.protocol.OFCapabilities;
import org.projectfloodlight.openflow.protocol.OFConfigFlags;
import org.projectfloodlight.openflow.protocol.OFDescStatsReply;
import org.projectfloodlight.openflow.protocol.OFDescStatsRequest;
import org.projectfloodlight.openflow.protocol.OFEchoReply;
import org.projectfloodlight.openflow.protocol.OFEchoRequest;
import org.projectfloodlight.openflow.protocol.OFFactories;
import org.projectfloodlight.openflow.protocol.OFFactory;
import org.projectfloodlight.openflow.protocol.OFFeaturesReply;
import org.projectfloodlight.openflow.protocol.OFFlowMod;
import org.projectfloodlight.openflow.protocol.OFGetConfigReply;
import org.projectfloodlight.openflow.protocol.OFGetConfigRequest;
import org.projectfloodlight.openflow.protocol.OFMessage;
import org.projectfloodlight.openflow.protocol.OFMessageReader;
import org.projectfloodlight.openflow.protocol.OFPortDescStatsReply;
import org.projectfloodlight.openflow.protocol.OFSetConfig;
import org.projectfloodlight.openflow.protocol.OFStatsReply;
import org.projectfloodlight.openflow.protocol.OFStatsReplyFlags;
import org.projectfloodlight.openflow.protocol.OFStatsRequest;
import org.projectfloodlight.openflow.protocol.OFVersion;
import org.projectfloodlight.openflow.types.DatapathId;
import org.slf4j.Logger;

import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;

import static org.slf4j.LoggerFactory.getLogger;

public class NetIDEShimController implements ICoreListener {

    private OpenFlowController controller;

    private static final int ONOS_DEFAULT_PRIORITY = 5;

    private Pair<Protocol, ProtocolVersions> supportedProtocol;
    private final Logger log = getLogger(getClass());

    private ZeroMQBaseConnector coreConnector;

    private HashMap<Long, Integer> xids;

    public NetIDEShimController(ZeroMQBaseConnector connector, OpenFlowController controller) {
        coreConnector = connector;
        this.controller = controller;
        this.xids = Maps.newHashMap();
    }

    public Pair<Protocol, ProtocolVersions> getSupportedProtocol() {
        return this.supportedProtocol;
    }

    public void setSupportedProtocol(byte version) {
        this.supportedProtocol = new Pair<Protocol, ProtocolVersions>(Protocol.OPENFLOW,
                ProtocolVersions.parse(Protocol.OPENFLOW, version));
    }

    public Integer getAndDeleteModuleId(Long xid) {
        return this.xids.remove(xid);
    }

    public boolean containsXid(Long xid) {
        return this.xids.containsKey(xid);
    }

    @Override
    public void onOpenFlowCoreMessage(Long datapathId, ByteBuf msg, int moduleId) {

        //TODO: Handle messages that requires replies (e.g. barrier)
        Dpid dpid = new Dpid(datapathId);
        log.debug("Dpid {}", dpid);
        OpenFlowSwitch sw = controller.getSwitch(dpid);

        ChannelBuffer buffer = ChannelBuffers.copiedBuffer(msg.array());
        OFMessageReader<OFMessage> reader = OFFactories.getGenericReader();
        try {
            OFMessage message = reader.readFrom(buffer);
            switch (message.getType()) {

            case FLOW_MOD:
                OFFlowMod flowMod = (OFFlowMod) message;
                if (flowMod.getPriority() > ONOS_DEFAULT_PRIORITY) {
                    sw.sendMsg(message);
                } else {
                    OFFlowMod.Builder flowModBuilder = flowMod.createBuilder();
                    flowModBuilder.setPriority(ONOS_DEFAULT_PRIORITY + 1);
                    sw.sendMsg(flowModBuilder.build());
                }
                break;

            case STATS_REQUEST:
                OFStatsRequest reply = (OFStatsRequest) message;
                switch (reply.getStatsType()) {
                case DESC:
                    OFDescStatsRequest ofDescStatsRequest = (OFDescStatsRequest) reply;
                    OFDescStatsReply.Builder ofDescReply = sw.factory().buildDescStatsReply();
                    ofDescReply.setXid(ofDescStatsRequest.getXid());
                    sendOpenFlowMessageToCore(ofDescReply.build(), ofDescReply.getXid(), sw.getId(), moduleId);
                    break;
                default:
                    //Save the xid
                    xids.put(message.getXid(), moduleId);
                    sw.sendMsg(message);
                }
                break;

            case BARRIER_REQUEST:
                xids.put(message.getXid(), moduleId);
                sw.sendMsg(message);
                break;

            case ECHO_REQUEST:

                OFEchoRequest echoRequest = (OFEchoRequest) message;
                ChannelBuffer buf = ChannelBuffers.dynamicBuffer();
                echoRequest.writeTo(buf);
                byte[] payload = buf.array();
                OFEchoReply.Builder echoReply = sw.factory().buildEchoReply();
                echoReply.setXid(echoRequest.getXid());
                echoReply.setData(payload);
                sendOpenFlowMessageToCore(echoReply.build(), echoReply.getXid(), sw.getId(), moduleId);
                break;

            case FEATURES_REQUEST:
                OFFeaturesReply featuresReply = getFeatureReply(sw);
                sendOpenFlowMessageToCore(featuresReply, featuresReply.getXid(), sw.getId(), moduleId);

                //Create OFPortDescStatsReply for OF_13
                if (sw.factory().getVersion() == OFVersion.OF_13) {
                    OFPortDescStatsReply.Builder statsReplyBuilder = sw.factory().buildPortDescStatsReply();
                    statsReplyBuilder.setEntries(sw.getPorts()).setXid(0);
                    OFPortDescStatsReply ofPortStatsReply = statsReplyBuilder.build();
                    sendOpenFlowMessageToCore(ofPortStatsReply, ofPortStatsReply.getXid(), sw.getId(), moduleId);
                }
                break;

            case PACKET_OUT:
                sw.sendMsg(message);
                break;

            case GET_CONFIG_REQUEST:
                OFGetConfigRequest setConfig = (OFGetConfigRequest) message;
                OFGetConfigReply.Builder configReply = sw.factory().buildGetConfigReply();
                configReply.setXid(setConfig.getXid());
                Set<OFConfigFlags> flags = Sets.newHashSet(OFConfigFlags.FRAG_NORMAL);
                configReply.setFlags(flags);
                configReply.setMissSendLen(0);
                sendOpenFlowMessageToCore(configReply.build(), configReply.getXid(), sw.getId(), moduleId);
                break;

            case SET_CONFIG:
                OFSetConfig ofSetConfig = (OFSetConfig) message;
                OFGetConfigReply.Builder ofGetConfigReply = sw.factory().buildGetConfigReply();
                ofGetConfigReply.setXid(ofSetConfig.getXid());
                Set<OFConfigFlags> flagsSet = Sets.newHashSet(OFConfigFlags.FRAG_NORMAL);
                ofGetConfigReply.setFlags(flagsSet);
                ofGetConfigReply.setMissSendLen(0);
                //sendOpenFlowMessageToCore(ofGetConfigReply.build(),ofGetConfigReply.getXid(),sw.getId(),moduleId);
                break;
            default:
                //sw.sendMsg(message);
                log.error("Unhandled OF message {}", message);
                break;
            }

        } catch (Exception e) {
            log.error("Error in decoding OFMessage from the CORE {}", e);
        }
    }

    @Override
    public void onHelloCoreMessage(List<Pair<Protocol, ProtocolVersions>> requestedProtocols, int moduleId) {

        for (Pair<Protocol, ProtocolVersions> requested : requestedProtocols) {
            if (getSupportedProtocol() != null) {
                if (requested.getValue0().getValue() == getSupportedProtocol().getValue0().getValue()
                        && requested.getValue1().getValue() == getSupportedProtocol().getValue1().getValue()) {
                    HelloMessage msg = new HelloMessage();
                    log.info("Supported protocols {}", getSupportedProtocol());
                    msg.getSupportedProtocols().add(getSupportedProtocol());
                    msg.getHeader().setPayloadLength((short) 2);
                    msg.getHeader().setModuleId(moduleId);
                    coreConnector.SendData(msg.toByteRepresentation());
                    log.debug("NetIDE HELLO message sent to the core...");

                    for (OpenFlowSwitch sw : controller.getSwitches()) {

                        OFFeaturesReply featuresReply = getFeatureReply(sw);
                        sendOpenFlowMessageToCore(featuresReply, featuresReply.getXid(), sw.getId(), moduleId);

                        //Create OFPortDescStatsReply for OF_13
                        if (sw.factory().getVersion() == OFVersion.OF_13) {
                            OFPortDescStatsReply.Builder statsReplyBuilder = sw.factory().buildPortDescStatsReply();
                            statsReplyBuilder.setEntries(sw.getPorts()).setXid(0);
                            OFPortDescStatsReply ofPortStatsReply = statsReplyBuilder.build();
                            sendOpenFlowMessageToCore(ofPortStatsReply, ofPortStatsReply.getXid(), sw.getId(), 0);
                        }
                    }

                }
            }
        }
    }

    public void sendOpenFlowMessageToCore(OFMessage msg, long xId, long datapathId, int moduleId) {

        ChannelBuffer buf = ChannelBuffers.dynamicBuffer();
        msg.writeTo(buf);
        byte[] payload = buf.array();
        Message message = new Message(NetIPUtils.StubHeaderFromPayload(payload), payload);
        message.getHeader().setMessageType(MessageType.OPENFLOW);
        message.getHeader().setDatapathId(datapathId);
        message.getHeader().setModuleId(moduleId);
        message.getHeader().setTransactionId((int) xId);
        coreConnector.SendData(message.toByteRepresentation());
    }

    public OFFeaturesReply getFeatureReply(OpenFlowSwitch dev) {
        //TODO: handle different OF versions
        OFFactory factory = dev.factory();

        OFFeaturesReply.Builder fea = factory.buildFeaturesReply();
        fea.setDatapathId(DatapathId.of(dev.getId()));
        fea.setXid(0);
        if (factory.getVersion() == OFVersion.OF_10) {
            Set<OFActionType> actions = new HashSet<>();
            actions.add(OFActionType.COPY_TTL_IN);
            actions.add(OFActionType.COPY_TTL_OUT);
            actions.add(OFActionType.ENQUEUE);
            actions.add(OFActionType.OUTPUT);
            actions.add(OFActionType.SET_DL_DST);
            actions.add(OFActionType.SET_DL_SRC);
            actions.add(OFActionType.SET_NW_DST);
            actions.add(OFActionType.SET_NW_SRC);
            actions.add(OFActionType.SET_NW_TOS);
            actions.add(OFActionType.SET_VLAN_VID);
            actions.add(OFActionType.SET_VLAN_PCP);
            actions.add(OFActionType.STRIP_VLAN);
            actions.add(OFActionType.SET_TP_DST);
            actions.add(OFActionType.SET_TP_SRC);
            fea.setActions(actions);
            fea.setPorts(dev.getPorts());
        }
        Set<OFCapabilities> capabilities = new HashSet<OFCapabilities>();
        capabilities.add(OFCapabilities.FLOW_STATS);
        capabilities.add(OFCapabilities.PORT_STATS);
        capabilities.add(OFCapabilities.QUEUE_STATS);
        fea.setCapabilities(capabilities);
        fea.setNBuffers(4096);

        return fea.build();
    }

}