Package net.floodlightcontroller.core

Source Code of net.floodlightcontroller.core.OFMessageFilterManager$TimeoutFilterTask

/**
*    Copyright 2011, Big Switch Networks, Inc.
*    Originally created by David Erickson, Stanford University
*
*    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 net.floodlightcontroller.core;

import java.util.Collection;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Iterator;
import java.util.Map;
import java.util.Timer;
import java.util.TimerTask;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ScheduledExecutorService;

import org.jboss.netty.buffer.ChannelBuffer;
import org.jboss.netty.buffer.ChannelBuffers;
import org.openflow.protocol.OFFlowMod;
import org.openflow.protocol.OFMessage;
import org.openflow.protocol.OFPacketIn;
import org.openflow.protocol.OFPacketOut;
import org.openflow.protocol.OFType;
import org.openflow.util.HexString;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.util.List;
import java.util.ArrayList;
import org.apache.thrift.TException;
import org.apache.thrift.transport.TFramedTransport;
import org.apache.thrift.transport.TTransport;
import org.apache.thrift.transport.TSocket;
import org.apache.thrift.protocol.TBinaryProtocol;
import org.apache.thrift.protocol.TProtocol;

import net.floodlightcontroller.core.annotations.LogMessageCategory;
import net.floodlightcontroller.core.annotations.LogMessageDoc;
import net.floodlightcontroller.core.module.FloodlightModuleContext;
import net.floodlightcontroller.core.module.FloodlightModuleException;
import net.floodlightcontroller.core.module.IFloodlightModule;
import net.floodlightcontroller.core.module.IFloodlightService;
import net.floodlightcontroller.packet.Ethernet;
import net.floodlightcontroller.packetstreamer.thrift.*;
import net.floodlightcontroller.threadpool.IThreadPoolService;

@LogMessageCategory("OpenFlow Message Tracing")
public class OFMessageFilterManager
        implements IOFMessageListener, IFloodlightModule, IOFMessageFilterManagerService {

    /**
     * @author Srini
     */
    protected static Logger log = LoggerFactory.getLogger(OFMessageFilterManager.class);

    // The port and client reference for packet streaming
    protected int serverPort = 9090;
    protected final int MaxRetry = 1;
    protected static volatile TTransport transport = null;
    protected static volatile PacketStreamer.Client packetClient = null;

    protected IFloodlightProviderService floodlightProvider = null;
    protected IThreadPoolService threadPool = null;
    // filter List is a key value pair.  Key is the session id,
    // value is the filter rules.
    protected ConcurrentHashMap<String,
                                ConcurrentHashMap<String,
                                                  String>> filterMap = null;
    protected ConcurrentHashMap<String, Long> filterTimeoutMap = null;
    protected Timer timer = null;

    protected int MAX_FILTERS=5;
    protected long MAX_FILTER_TIME= 300000; // maximum filter time is 5 minutes.
    protected int TIMER_INTERVAL = 1000// 1 second time interval.

    public static final String SUCCESS                     = "0";
    public static final String FILTER_SETUP_FAILED         = "-1001";
    public static final String FILTER_NOT_FOUND            = "-1002";
    public static final String FILTER_LIMIT_REACHED        = "-1003";
    public static final String FILTER_SESSION_ID_NOT_FOUND = "-1004";
    public static final String SERVICE_UNAVAILABLE         = "-1005";

    public enum FilterResult {
        /*
         * FILTER_NOT_DEFINED: Filter is not defined
         * FILTER_NO_MATCH:    Filter is defined and the packet doesn't
         *                     match the filter
         * FILTER_MATCH:       Filter is defined and the packet matches
         *                     the filter
         */
        FILTER_NOT_DEFINED, FILTER_NO_MATCH, FILTER_MATCH
    }

    protected String addFilter(ConcurrentHashMap<String,String> f, long delta) {

        // Create unique session ID. 
        int prime = 33791;
        String s = null;
        int i;

        if ((filterMap == null) || (filterTimeoutMap == null))
            return String.format("%s", FILTER_SETUP_FAILED);

        for (i=0; i<MAX_FILTERS; ++i) {
            Integer x = prime + i;
            s = String.format("%d", x.hashCode());
            // implies you can use this key for session id.   
            if (!filterMap.containsKey(s)) break;
        }

        if (i==MAX_FILTERS) {
            return FILTER_LIMIT_REACHED;
        }

        filterMap.put(s, f);
        if (filterTimeoutMap.containsKey(s))  filterTimeoutMap.remove(s);
        filterTimeoutMap.put(s, delta);

        // set the timer as there will be no existing timers.
        if (filterMap.size() == 1) {
            TimeoutFilterTask task = new TimeoutFilterTask(this);
            Timer timer = new Timer();
            timer.schedule (task, TIMER_INTERVAL);               
            // Keep the listeners to avoid race condition
            //startListening();
        }  
        return s;  // the return string is the session ID.
    }

    @Override
    public String setupFilter(String sid,
                              ConcurrentHashMap<String,String> f,
                              int deltaInMilliSeconds) {

        if (sid == null) {
            // Delta in filter needs to be milliseconds
            log.debug("Adding new filter: {} for {} ms", f, deltaInMilliSeconds);
            return addFilter(f, deltaInMilliSeconds);
        } else {// this is the session id.
            // we will ignore the hash map features.
            if (deltaInMilliSeconds > 0
                return refreshFilter(sid, deltaInMilliSeconds);
            else
                return deleteFilter(sid);
        }
    }

    public int timeoutFilters() {               
        Iterator<String> i = filterTimeoutMap.keySet().iterator();

        while(i.hasNext()) {
            String s = i.next();

            Long t = filterTimeoutMap.get(s);
            if (t != null) {
                i.remove();
                t -= TIMER_INTERVAL;
                if (t > 0) {
                    filterTimeoutMap.put(s, t);
                } else deleteFilter(s);
            } else deleteFilter(s);
        }
        return filterMap.size();
    }

    protected String refreshFilter(String s, int delta) {
        Long t = filterTimeoutMap.get(s);
        if (t != null) {
            filterTimeoutMap.remove(s);
            t += delta;  // time is in milliseconds
            if (t > MAX_FILTER_TIME) t = MAX_FILTER_TIME;
            filterTimeoutMap.put(s, t);
            return SUCCESS;
        } else return FILTER_SESSION_ID_NOT_FOUND;
    }

    @LogMessageDoc(level="ERROR",
                   message="Error while terminating packet " +
                           "filter session",
                   explanation="An unknown error occurred while terminating " +
                       "a packet filter session.",
                   recommendation=LogMessageDoc.GENERIC_ACTION)
    protected String deleteFilter(String sessionId) {

        if (filterMap.containsKey(sessionId)) {
            filterMap.remove(sessionId);
            try {
                if (packetClient != null)
                    packetClient.terminateSession(sessionId);
            } catch (TException e) {
                log.error("Error while terminating packet " +
                      "filter session", e);
            }
            log.debug("Deleted Filter {}.  # of filters" +
                 " remaining: {}", sessionId, filterMap.size());
            return SUCCESS;
        } else return FILTER_SESSION_ID_NOT_FOUND;
    }

    public HashSet<String> getMatchedFilters(OFMessage m, FloodlightContext cntx) { 

        HashSet<String> matchedFilters = new HashSet<String>();

        // This default function is written to match on packet ins and
        // packet outs.
        Ethernet eth = null;

        if (m.getType() == OFType.PACKET_IN) {
            eth = IFloodlightProviderService.bcStore.get(cntx,
                    IFloodlightProviderService.CONTEXT_PI_PAYLOAD);
        } else if (m.getType() == OFType.PACKET_OUT) {
            eth = new Ethernet();
            OFPacketOut p = (OFPacketOut) m;
           
            // No MAC match if packetOut doesn't have the packet.
            if (p.getPacketData() == null) return null;
           
            eth.deserialize(p.getPacketData(), 0, p.getPacketData().length);
        } else if (m.getType() == OFType.FLOW_MOD) {
            // flow-mod can't be matched by mac.
            return null;
        }

        if (eth == null) return null;

        Iterator<String> filterIt = filterMap.keySet().iterator();
        while (filterIt.hasNext()) {   // for every filter
            boolean filterMatch = false;
            String filterSessionId = filterIt.next();
            Map<String,String> filter = filterMap.get(filterSessionId);

            // If the filter has empty fields, then it is not considered as a match.
            if (filter == null || filter.isEmpty()) continue;                 
            Iterator<String> fieldIt = filter.keySet().iterator();
            while (fieldIt.hasNext()) {  
                String filterFieldType = fieldIt.next();
                String filterFieldValue = filter.get(filterFieldType);
                if (filterFieldType.equals("mac")) {

                    String srcMac = HexString.toHexString(eth.getSourceMACAddress());
                    String dstMac = HexString.toHexString(eth.getDestinationMACAddress());
                    log.debug("srcMac: {}, dstMac: {}", srcMac, dstMac);

                    if (filterFieldValue.equals(srcMac) ||
                            filterFieldValue.equals(dstMac)){
                        filterMatch = true;
                    } else {
                        filterMatch = false;
                        break;
                    }
                }
            }
            if (filterMatch) {
                matchedFilters.add(filterSessionId);
            }
        }

        if (matchedFilters.isEmpty())
            return null;   
        else
            return matchedFilters;
    }
   
    @LogMessageDoc(level="ERROR",
                   message="Failed to establish connection with the " +
                           "packetstreamer server.",
                   explanation="The message tracing server is not running " +
                       "or otherwise unavailable.",
                   recommendation=LogMessageDoc.CHECK_CONTROLLER)
    public boolean connectToPSServer() {
        int numRetries = 0;
        if (transport != null && transport.isOpen()) {
            return true;
        }

        while (numRetries++ < MaxRetry) {
            try {
                TFramedTransport t =
                        new TFramedTransport(new TSocket("localhost",
                                                         serverPort));
                t.open();

                TProtocol protocol = new  TBinaryProtocol(t);
                packetClient = new PacketStreamer.Client(protocol);

                log.debug("Have a connection to packetstreamer server " +
                      "localhost:{}", serverPort);
                transport = t;
                break;
            } catch (TException x) {
                try {
                    // Wait for 1 second before retry
                    if (numRetries < MaxRetry) {
                        Thread.sleep(1000);
                    }
                } catch (Exception e) {}
            }
        }

        if (numRetries > MaxRetry) {
            log.error("Failed to establish connection with the " +
                  "packetstreamer server.");
            return false;
        }
        return true;
    }

    public void disconnectFromPSServer() {
        if (transport != null && transport.isOpen()) {
            log.debug("Close the connection to packetstreamer server" +
                  " localhost:{}", serverPort);
            transport.close();
        }
    }

    @Override
    public String getName() {
        return "messageFilterManager";
    }

    @Override
    public boolean isCallbackOrderingPrereq(OFType type, String name) {
        return (type == OFType.PACKET_IN && name.equals("devicemanager"));
    }

    @Override
    public boolean isCallbackOrderingPostreq(OFType type, String name) {
        return (type == OFType.PACKET_IN && name.equals("learningswitch"));
    }

    @Override
    @LogMessageDoc(level="ERROR",
                   message="Error while sending packet",
                   explanation="Failed to send a message to the message " +
                       "tracing server",
                   recommendation=LogMessageDoc.CHECK_CONTROLLER)
    public Command receive(IOFSwitch sw, OFMessage msg,
                           FloodlightContext cntx) {

        if (filterMap == null || filterMap.isEmpty()) return Command.CONTINUE;

        HashSet<String> matchedFilters = null;
        if (log.isDebugEnabled()) {
            log.debug("Received packet {} from switch {}",
                      msg, sw.getStringId());
        }

        matchedFilters = getMatchedFilters(msg, cntx);
        if (matchedFilters == null) {
            return Command.CONTINUE;
        } else {
            try {
                sendPacket(matchedFilters, sw, msg, cntx, true);
            } catch (Exception e) {
                log.error("Error while sending packet", e);
            }
        }
       
        return Command.CONTINUE;
    }


    public class TimeoutFilterTask extends TimerTask {

        OFMessageFilterManager filterManager;
        ScheduledExecutorService ses = threadPool.getScheduledExecutor();

        public TimeoutFilterTask(OFMessageFilterManager manager) {
            filterManager = manager;
        }

        public void run() {
            int x = filterManager.timeoutFilters();

            if (x > 0) {  // there's at least one filter still active.
                Timer timer = new Timer();
                timer.schedule(new TimeoutFilterTask(filterManager),
                               TIMER_INTERVAL);
            } else {
                // Don't stop the listener to avoid race condition
                //stopListening();
            }
        }
    }

    public int getNumberOfFilters() {
        return filterMap.size();
    }

    public int getMaxFilterSize() {
        return MAX_FILTERS;
    }

    protected void sendPacket(HashSet<String> matchedFilters, IOFSwitch sw,
            OFMessage msg, FloodlightContext cntx, boolean sync)
                    throws TException {
        Message sendMsg = new Message();
        Packet packet = new Packet();
        ChannelBuffer bb;
        sendMsg.setPacket(packet);

        List<String> sids = new ArrayList<String>(matchedFilters);

        sendMsg.setSessionIDs(sids);
        packet.setMessageType(OFMessageType.findByValue((msg.getType().ordinal())));

        switch (msg.getType()) {
            case PACKET_IN:
                OFPacketIn pktIn = (OFPacketIn)msg;
                packet.setSwPortTuple(new SwitchPortTuple(sw.getId(),
                                                          pktIn.getInPort()));
                bb = ChannelBuffers.buffer(pktIn.getLength());
                pktIn.writeTo(bb);
                packet.setData(OFMessage.getData(sw, msg, cntx));
                break;
            case PACKET_OUT:
                OFPacketOut pktOut = (OFPacketOut)msg;
                packet.setSwPortTuple(new SwitchPortTuple(sw.getId(),
                                                          pktOut.getInPort()));
                bb = ChannelBuffers.buffer(pktOut.getLength());
                pktOut.writeTo(bb);
                packet.setData(OFMessage.getData(sw, msg, cntx));
                break;
            case FLOW_MOD:
                OFFlowMod offlowMod = (OFFlowMod)msg;
                packet.setSwPortTuple(new SwitchPortTuple(sw.getId(),
                                                          offlowMod.
                                                          getOutPort()));
                bb = ChannelBuffers.buffer(offlowMod.getLength());
                offlowMod.writeTo(bb);
                packet.setData(OFMessage.getData(sw, msg, cntx));
                break;
            default:
                packet.setSwPortTuple(new SwitchPortTuple(sw.getId(),
                                                          (short)0));
                String strData = "Unknown packet";
                packet.setData(strData.getBytes());
                break;
        }

        try {
            if (transport == null ||
                !transport.isOpen() ||
                packetClient == null) {
                if (!connectToPSServer()) {
                    // No need to sendPacket if can't make connection to
                    // the server
                    return;
                }
            }
            if (sync) {
                log.debug("Send packet sync: {}", packet.toString());
                packetClient.pushMessageSync(sendMsg);
            } else {
                log.debug("Send packet sync: ", packet.toString());
                packetClient.pushMessageAsync(sendMsg);
            }
        } catch (Exception e) {
            log.error("Error while sending packet", e);
            disconnectFromPSServer();
            connectToPSServer();
        }
    }

    // IFloodlightModule methods
   
    @Override
    public Collection<Class<? extends IFloodlightService>> getModuleServices() {
        Collection<Class<? extends IFloodlightService>> l =
                new ArrayList<Class<? extends IFloodlightService>>();
        l.add(IOFMessageFilterManagerService.class);
        return l;
    }

    @Override
    public Map<Class<? extends IFloodlightService>, IFloodlightService>
            getServiceImpls() {
        Map<Class<? extends IFloodlightService>,
        IFloodlightService> m =
            new HashMap<Class<? extends IFloodlightService>,
                        IFloodlightService>();
        // We are the class that implements the service
        m.put(IOFMessageFilterManagerService.class, this);
        return m;
    }

    @Override
    public Collection<Class<? extends IFloodlightService>> getModuleDependencies() {
        Collection<Class<? extends IFloodlightService>> l =
                new ArrayList<Class<? extends IFloodlightService>>();
        l.add(IFloodlightProviderService.class);
        l.add(IThreadPoolService.class);
        return l;
    }

    @Override
    public void init(FloodlightModuleContext context)
            throws FloodlightModuleException {
        this.floodlightProvider =
                context.getServiceImpl(IFloodlightProviderService.class);
        this.threadPool =
                context.getServiceImpl(IThreadPoolService.class);
    }

    @Override
    public void startUp(FloodlightModuleContext context) {
        // This is our 'constructor'
       
        filterMap = new ConcurrentHashMap<String, ConcurrentHashMap<String,String>>();
        filterTimeoutMap = new ConcurrentHashMap<String, Long>();
        serverPort =
                Integer.parseInt(System.getProperty("net.floodlightcontroller." +
                    "packetstreamer.port", "9090"));
       
        floodlightProvider.addOFMessageListener(OFType.PACKET_IN, this);
        floodlightProvider.addOFMessageListener(OFType.PACKET_OUT, this);
        floodlightProvider.addOFMessageListener(OFType.FLOW_MOD, this);
    }
}
TOP

Related Classes of net.floodlightcontroller.core.OFMessageFilterManager$TimeoutFilterTask

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.