Package net.floodlightcontroller.flowcache

Source Code of net.floodlightcontroller.flowcache.PortDownReconciliation

/**
*    Copyright 2012, Jason Parraga, Marist College
*
*    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.flowcache;

import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
import java.util.concurrent.Future;
import java.util.concurrent.TimeUnit;

import org.openflow.protocol.OFFlowMod;
import org.openflow.protocol.OFMatch;
import org.openflow.protocol.OFMatchWithSwDpid;
import org.openflow.protocol.OFMessage;
import org.openflow.protocol.OFStatisticsRequest;
import org.openflow.protocol.OFType;
import org.openflow.protocol.statistics.OFFlowStatisticsReply;
import org.openflow.protocol.statistics.OFFlowStatisticsRequest;
import org.openflow.protocol.statistics.OFStatistics;
import org.openflow.protocol.statistics.OFStatisticsType;
import org.openflow.util.HexString;
import org.openflow.util.U16;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import net.floodlightcontroller.core.FloodlightContext;
import net.floodlightcontroller.core.IFloodlightProviderService;
import net.floodlightcontroller.core.IOFSwitch;
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.flowcache.IFlowReconcileListener;
import net.floodlightcontroller.flowcache.IFlowReconcileService;
import net.floodlightcontroller.flowcache.OFMatchReconcile;
import net.floodlightcontroller.flowcache.PriorityPendingQueue.EventPriority;
import net.floodlightcontroller.linkdiscovery.ILinkDiscovery;
import net.floodlightcontroller.linkdiscovery.LinkInfo;
import net.floodlightcontroller.linkdiscovery.ILinkDiscovery.LDUpdate;
import net.floodlightcontroller.linkdiscovery.ILinkDiscoveryService;
import net.floodlightcontroller.routing.Link;
import net.floodlightcontroller.topology.ITopologyListener;
import net.floodlightcontroller.topology.ITopologyService;

/**
* Flow reconciliation module that is triggered by PORT_DOWN events. This module
* will recursively trace back all flows from the immediately affected switch
* and remove them (specifically flows with an idle timeout that would not be
* exhausted). Once the flows are deleted Floodlight will re-evaluate the path
* the traffic should take with it's updated topology map.
*
* @author Jason Parraga
*/

public class PortDownReconciliation implements IFloodlightModule,
    ITopologyListener, IFlowReconcileListener {
    protected static Logger log = LoggerFactory.getLogger(PortDownReconciliation.class);

    protected ITopologyService topology;
    protected IFloodlightProviderService floodlightProvider;
    protected IFlowReconcileService frm;
    protected ILinkDiscoveryService lds;
    protected Map<Link, LinkInfo> links;
    protected FloodlightContext cntx;
    protected static boolean waiting = false;
    protected int statsQueryXId;
    protected static List<OFFlowStatisticsReply> statsReply;

    // ITopologyListener
    @Override
    public void topologyChanged(List<LDUpdate> appliedUpdates) {
        for (LDUpdate ldu : appliedUpdates) {
            if (ldu.getOperation()
                   .equals(ILinkDiscovery.UpdateOperation.PORT_DOWN)) {

                // Get the switch ID for the OFMatchWithSwDpid object
                long affectedSwitch = floodlightProvider.getSwitch(ldu.getSrc())
                                                        .getId();

                // Create an OFMatchReconcile object
                OFMatchReconcile ofmr = new OFMatchReconcile();

                // Generate an OFMatch objects for the OFMatchWithSwDpid object
                OFMatch match = new OFMatch().setWildcards(OFMatch.OFPFW_ALL);

                // Generate the OFMatchWithSwDpid
                OFMatchWithSwDpid ofmatchsw = new OFMatchWithSwDpid(match,
                                                                    affectedSwitch);

                // Set the action to update the path to remove flows routing
                // towards the downed port
                ofmr.rcAction = OFMatchReconcile.ReconcileAction.UPDATE_PATH;

                // Set the match, with the switch dpid
                ofmr.ofmWithSwDpid = ofmatchsw;

                // Assign the downed port to the OFMatchReconcile's outPort data
                // member (I added this to
                // the OFMatchReconcile class)
                ofmr.outPort = ldu.getSrcPort();

                // Tell the reconcile manager to reconcile matching flows
                frm.reconcileFlow(ofmr, EventPriority.HIGH);
            }
        }
    }

    @Override
    public Collection<Class<? extends IFloodlightService>>
            getModuleServices() {
        return null;
    }

    @Override
    public Map<Class<? extends IFloodlightService>, IFloodlightService>
            getServiceImpls() {
        return null;
    }

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

    @Override
    public
            void
            init(FloodlightModuleContext context)
                                                 throws FloodlightModuleException {
        floodlightProvider = context.getServiceImpl(IFloodlightProviderService.class);
        topology = context.getServiceImpl(ITopologyService.class);
        frm = context.getServiceImpl(IFlowReconcileService.class);
        lds = context.getServiceImpl(ILinkDiscoveryService.class);
        cntx = new FloodlightContext();
    }

    @Override
    public void startUp(FloodlightModuleContext context) {
        topology.addListener(this);
        frm.addFlowReconcileListener(this);
    }

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

    @Override
    public boolean isCallbackOrderingPrereq(OFType type, String name) {
        return false;
    }

    @Override
    public boolean isCallbackOrderingPostreq(OFType type, String name) {
        return true;
    }

    /**
     * Base case for the reconciliation of flows. This is triggered at the
     * switch which is immediately affected by the PORT_DOWN event
     *
     * @return the Command whether to STOP or Continue
     */
    @Override
    public net.floodlightcontroller.core.IListener.Command
            reconcileFlows(ArrayList<OFMatchReconcile> ofmRcList) {
        if (lds != null) {
            links = new HashMap<Link, LinkInfo>();
            // Get all the switch links from the topology
            if (lds.getLinks() != null) links.putAll(lds.getLinks());

            for (OFMatchReconcile ofmr : ofmRcList) {
                // We only care about OFMatchReconcile objects that wish to
                // update the path to a switch
                if (ofmr.rcAction.equals(OFMatchReconcile.ReconcileAction.UPDATE_PATH)) {
                    // Get the switch object from the OFMatchReconcile
                    IOFSwitch sw = floodlightProvider
                            .getSwitch(ofmr.ofmWithSwDpid.getSwitchDataPathId());

                    // Map data structure that holds the invalid matches and the
                    // ingress ports of those matches
                    Map<Short, List<OFMatch>> invalidBaseIngressAndMatches = new HashMap<Short, List<OFMatch>>();

                    // Get the invalid flows
                    List<OFFlowStatisticsReply> flows = getFlows(sw,
                                                                 ofmr.outPort);

                    // Analyze all the flows with outPorts equaling the downed
                    // port and extract OFMatch's to trace back to neighbors
                    for (OFFlowStatisticsReply flow : flows) {
                        // Create a reference to the match for ease
                        OFMatch match = flow.getMatch();

                        // Here we utilize an index of input ports which point
                        // to multiple invalid matches
                        if (invalidBaseIngressAndMatches.containsKey(match.getInputPort()))
                            // If the input port is already in the index, add
                            // the match to it's list
                            invalidBaseIngressAndMatches.get(match.getInputPort())
                                                        .add(match);
                        else {
                            // Otherwise create a new list and add it to the
                            // index
                            List<OFMatch> matches = new ArrayList<OFMatch>();
                            matches.add(match);
                            invalidBaseIngressAndMatches.put(match.getInputPort(),
                                                             matches);
                        }
                    }

                    // Remove invalid flows from the base switch, if they exist
                    if (!flows.isEmpty()) {
                        log.debug("Removing flows on switch : " + sw.getId()
                                  + " with outport: " + ofmr.outPort);
                        clearFlowMods(sw, ofmr.outPort);
                    }

                    // Create a list of neighboring switches we need to remove
                    // invalid flows from
                    Map<IOFSwitch, Map<Short, List<OFMatch>>> neighborSwitches = new HashMap<IOFSwitch, Map<Short, List<OFMatch>>>();

                    // Loop through all the links
                    for (Link link : links.keySet()) {
                        // Filter out links we care about
                        if (link.getDst() == sw.getId()) {
                            // Loop through the links to neighboring switches
                            // which have invalid flows
                            for (Entry<Short, List<OFMatch>> invalidBaseIngressAndMatch : invalidBaseIngressAndMatches.entrySet()) {
                                // Find links on the network which link to the
                                // ingress ports that have invalidly routed
                                // flows
                                if (link.getDstPort() == invalidBaseIngressAndMatch.getKey()) {
                                    Map<Short, List<OFMatch>> invalidNeighborOutportAndMatch = new HashMap<Short, List<OFMatch>>();
                                    // Insert the neighbor's outPort to the base
                                    // switch and the invalid match
                                    invalidNeighborOutportAndMatch.put(link.getSrcPort(),
                                                                       invalidBaseIngressAndMatch.getValue());
                                    // Link a neighbor switch's invalid match
                                    // and outport to their Switch object
                                    neighborSwitches.put(floodlightProvider.getSwitch(link.getSrc()),
                                                         invalidNeighborOutportAndMatch);
                                }
                            }
                        }
                    }
                    log.debug("We have " + neighborSwitches.size()
                              + " neighboring switches to deal with!");
                    // Loop through all the switches we found to have potential
                    // issues
                    for (IOFSwitch neighborSwitch : neighborSwitches.keySet()) {
                        log.debug("NeighborSwitch ID : "
                                  + neighborSwitch.getId());
                        if (neighborSwitches.get(neighborSwitch) != null)
                                                                         deleteInvalidFlows(neighborSwitch,
                                                                                            neighborSwitches.get(neighborSwitch));
                    }
                }
                return Command.CONTINUE;
            }
        } else {
            log.error("Link Discovery Service Is Null");
        }
        return Command.CONTINUE;
    }

    /**
     * @param sw
     *            the switch object that we wish to get flows from
     * @param outPort
     *            the output action port we wish to find flows with
     * @return a list of OFFlowStatisticsReply objects or essentially flows
     */
    public List<OFFlowStatisticsReply> getFlows(IOFSwitch sw, Short outPort) {

        statsReply = new ArrayList<OFFlowStatisticsReply>();
        List<OFStatistics> values = null;
        Future<List<OFStatistics>> future;

        // Statistics request object for getting flows
        OFStatisticsRequest req = new OFStatisticsRequest();
        req.setStatisticType(OFStatisticsType.FLOW);
        int requestLength = req.getLengthU();
        OFFlowStatisticsRequest specificReq = new OFFlowStatisticsRequest();
        specificReq.setMatch(new OFMatch().setWildcards(0xffffffff));
        specificReq.setOutPort(outPort);
        specificReq.setTableId((byte) 0xff);
        req.setStatistics(Collections.singletonList((OFStatistics) specificReq));
        requestLength += specificReq.getLength();
        req.setLengthU(requestLength);

        try {
            // System.out.println(sw.getStatistics(req));
            future = sw.queryStatistics(req);
            values = future.get(10, TimeUnit.SECONDS);
            if (values != null) {
                for (OFStatistics stat : values) {
                    statsReply.add((OFFlowStatisticsReply) stat);
                }
            }
        } catch (Exception e) {
            log.error("Failure retrieving statistics from switch " + sw, e);
        }

        return statsReply;
    }

    /**
     * @param sw
     *            The switch we wish to remove flows from
     * @param outPort
     *            The specific Output Action OutPort of specific flows we wish
     *            to delete
     */
    public void clearFlowMods(IOFSwitch sw, Short outPort) {
        // Delete all pre-existing flows with the same output action port or
        // outPort
        OFMatch match = new OFMatch().setWildcards(OFMatch.OFPFW_ALL);
        OFMessage fm = ((OFFlowMod) floodlightProvider.getOFMessageFactory()
                                                      .getMessage(OFType.FLOW_MOD)).setMatch(match)
                                                                                   .setCommand(OFFlowMod.OFPFC_DELETE)
                                                                                   .setOutPort(outPort)
                                                                                   .setLength(U16.t(OFFlowMod.MINIMUM_LENGTH));
        try {
            List<OFMessage> msglist = new ArrayList<OFMessage>(1);
            msglist.add(fm);
            sw.write(msglist, cntx);
        } catch (Exception e) {
            log.error("Failed to clear flows on switch {} - {}", this, e);
        }
    }

    /**
     * @param sw
     *            The switch we wish to remove flows from
     * @param match
     *            The specific OFMatch object of specific flows we wish to
     *            delete
     * @param outPort
     *            The specific Output Action OutPort of specific flows we wish
     *            to delete
     */
    public void clearFlowMods(IOFSwitch sw, OFMatch match, Short outPort) {
        // Delete pre-existing flows with the same match, and output action port
        // or outPort
        match.setWildcards(OFMatch.OFPFW_ALL);
        OFMessage fm = ((OFFlowMod) floodlightProvider.getOFMessageFactory()
                                                      .getMessage(OFType.FLOW_MOD)).setMatch(match)
                                                                                   .setCommand(OFFlowMod.OFPFC_DELETE)
                                                                                   .setOutPort(outPort)
                                                                                   .setLength(U16.t(OFFlowMod.MINIMUM_LENGTH));
        try {
            List<OFMessage> msglist = new ArrayList<OFMessage>(1);
            msglist.add(fm);
            sw.write(msglist, cntx);
        } catch (Exception e) {
            log.error("Failed to clear flows on switch {} - {}", this, e);
        }
    }

    /**
     * Deletes flows with similar matches and output action ports on the
     * specified switch
     *
     * @param sw
     *            the switch to query flows on
     * @param match
     *            the problematic OFMatch from the base switch which we wish to
     *            find and remove
     * @param outPort
     *            the output action port wanted from the flows, which follows
     *            the route to the base switch
     */
    public
            void
            deleteInvalidFlows(IOFSwitch sw,
                               Map<Short, List<OFMatch>> invalidOutportAndMatch) {
        log.debug("Deleting invalid flows on switch : " + sw.getId());

        // A map that holds the input ports and invalid matches on a switch
        Map<Short, List<OFMatch>> invalidNeighborIngressAndMatches = new HashMap<Short, List<OFMatch>>();

        for (Short outPort : invalidOutportAndMatch.keySet()) {
            // Get the flows on the switch
            List<OFFlowStatisticsReply> flows = getFlows(sw, outPort);

            // Analyze all the flows with outPorts pointing to problematic route
            for (OFFlowStatisticsReply flow : flows) {
                // Loop through all the problematic matches
                for (OFMatch match : invalidOutportAndMatch.get(outPort)) {
                    // Compare the problematic matches with the match of the
                    // flow on the switch
                    if (HexString.toHexString(flow.getMatch()
                                                  .getDataLayerDestination())
                                 .equals(HexString.toHexString(match.getDataLayerDestination()))
                        && HexString.toHexString(flow.getMatch()
                                                     .getDataLayerSource())
                                    .equals(HexString.toHexString(match.getDataLayerSource()))
                        && flow.getMatch().getDataLayerType() == match.getDataLayerType()
                        && flow.getMatch().getDataLayerVirtualLan() == match.getDataLayerVirtualLan()
                        && flow.getMatch().getNetworkDestination() == match.getNetworkDestination()
                        && flow.getMatch().getNetworkDestinationMaskLen() == match.getNetworkDestinationMaskLen()
                        && flow.getMatch().getNetworkProtocol() == match.getNetworkProtocol()
                        && flow.getMatch().getNetworkSource() == match.getNetworkSource()
                        && flow.getMatch().getNetworkSourceMaskLen() == match.getNetworkSourceMaskLen()
                        && flow.getMatch().getNetworkTypeOfService() == match.getNetworkTypeOfService()) {

                        // Here we utilize an index of input ports which point
                        // to multiple invalid matches
                        if (invalidNeighborIngressAndMatches.containsKey(match.getInputPort()))
                            // If the input port is already in the index, add
                            // the match to it's list
                            invalidNeighborIngressAndMatches.get(match.getInputPort())
                                                            .add(match);
                        else {
                            // Otherwise create a new list and add it to the
                            // index
                            List<OFMatch> matches = new ArrayList<OFMatch>();
                            matches.add(match);
                            invalidNeighborIngressAndMatches.put(match.getInputPort(),
                                                                 matches);
                        }
                        // Remove flows from the switch with the invalid match
                        // and outPort
                        clearFlowMods(sw, flow.getMatch(), outPort);
                    }
                }
            }

            // Create a list of neighboring switches we need to check for
            // invalid flows
            Map<IOFSwitch, Map<Short, List<OFMatch>>> neighborSwitches = new HashMap<IOFSwitch, Map<Short, List<OFMatch>>>();

            // Loop through all the links
            for (Link link : links.keySet()) {
                // Filter out links we care about
                if (link.getDst() == sw.getId()) {
                    // Loop through the ingressPorts that are involved in
                    // invalid flows on neighboring switches
                    for (Entry<Short, List<OFMatch>> ingressPort : invalidNeighborIngressAndMatches.entrySet()) {
                        // Filter out invalid links by matching the link
                        // destination port to our invalid flows ingress port
                        if (link.getDstPort() == ingressPort.getKey()) {
                            // Generate a match and outPort map since I don't
                            // want to create an object
                            Map<Short, List<OFMatch>> invalidNeighborOutportAndMatch = new HashMap<Short, List<OFMatch>>();
                            invalidNeighborOutportAndMatch.put(link.getSrcPort(),
                                                               ingressPort.getValue());
                            // Link a neighbor switch's invalid match and
                            // outport to their Switch object
                            neighborSwitches.put(floodlightProvider.getSwitch(link.getSrc()),
                                                 invalidNeighborOutportAndMatch);
                        }
                    }
                }
            }
            log.debug("We have " + neighborSwitches.size()
                      + " neighbors to deal with!");

            // Loop through all the neighbor switches we found to have
            // invalid matches
            for (IOFSwitch neighborSwitch : neighborSwitches.keySet()) {
                log.debug("NeighborSwitch ID : " + neighborSwitch.getId());
                // Recursively seek out and delete invalid flows on the
                // neighbor switch
                deleteInvalidFlows(neighborSwitch,
                                   neighborSwitches.get(neighborSwitch));
            }
        }
    }
}
TOP

Related Classes of net.floodlightcontroller.flowcache.PortDownReconciliation

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.