Skip to content
Snippets Groups Projects
Commit c31e2848 authored by kwanggithub's avatar kwanggithub
Browse files

Updating floodlight subtree

parents e34357c9 7106b844
No related branches found
No related tags found
No related merge requests found
......@@ -49,6 +49,8 @@ public class OFMatchReconcile {
public String newAppInstName;
/** The reconcile action. */
public ReconcileAction rcAction;
/** Outport in the event of UPDATE_PATH action**/
public short outPort;
// The context for the reconcile action
public FloodlightContext cntx;
......@@ -72,6 +74,7 @@ public class OFMatchReconcile {
appInstName = copy.appInstName;
newAppInstName = copy.newAppInstName;
rcAction = copy.rcAction;
outPort = copy.outPort;
cntx = new FloodlightContext();
}
......@@ -79,6 +82,6 @@ public class OFMatchReconcile {
public String toString() {
return "OFMatchReconcile [" + ofmWithSwDpid + " priority=" + priority + " action=" + action +
" cookie=" + cookie + " appInstName=" + appInstName + " newAppInstName=" + newAppInstName +
" ReconcileAction=" + rcAction + "]";
" ReconcileAction=" + rcAction + "outPort=" + outPort + "]";
}
}
}
\ No newline at end of file
/**
* 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.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() {
for (LDUpdate ldu : topology.getLastLinkUpdates()) {
if (ldu.getOperation().equals(
ILinkDiscovery.UpdateOperation.PORT_DOWN)) {
// Get the switch ID for the OFMatchWithSwDpid object
long affectedSwitch = floodlightProvider.getSwitches()
.get(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);
}
}
}
@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((ITopologyListener) this);
frm.addFlowReconcileListener((IFlowReconcileListener) 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.getSwitches().get(
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
.getSwitches().get(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.getStatistics(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
.getSwitches().get(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));
}
}
}
}
\ No newline at end of file
/**
* 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 static org.easymock.EasyMock.capture;
import static org.easymock.EasyMock.createMock;
import static org.easymock.EasyMock.expect;
import static org.easymock.EasyMock.expectLastCall;
import static org.easymock.EasyMock.replay;
import static org.easymock.EasyMock.verify;
import java.util.ArrayList;
import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.concurrent.Callable;
import java.util.concurrent.Future;
import java.util.concurrent.FutureTask;
import org.easymock.Capture;
import org.easymock.CaptureType;
import org.easymock.EasyMock;
import org.junit.Before;
import org.junit.Test;
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.action.OFAction;
import org.openflow.protocol.action.OFActionOutput;
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.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.test.MockFloodlightProvider;
import net.floodlightcontroller.core.test.MockThreadPoolService;
import net.floodlightcontroller.devicemanager.IEntityClassifierService;
import net.floodlightcontroller.devicemanager.internal.DefaultEntityClassifier;
import net.floodlightcontroller.flowcache.FlowReconcileManager;
import net.floodlightcontroller.flowcache.IFlowReconcileService;
import net.floodlightcontroller.flowcache.OFMatchReconcile;
import net.floodlightcontroller.linkdiscovery.ILinkDiscoveryService;
import net.floodlightcontroller.linkdiscovery.LinkInfo;
import net.floodlightcontroller.routing.Link;
import net.floodlightcontroller.test.FloodlightTestCase;
import net.floodlightcontroller.threadpool.IThreadPoolService;
import net.floodlightcontroller.topology.ITopologyService;
/**
* Unit test for PortDownReconciliation. To test the class I have generated
* there very simple network topologies. an OFMatchReconcile object with
* information about the PORT_DOWN event is passed to the class, where it begins
* breaking down the information,analyzing the switches for flows and deleting
* those that are invalid. This Test specifically verifies that each switch is
* queried for flows once and is sent the appropriate OFFlowMod delete
* message.
*
* @author Jason Parraga
*/
public class PortDownReconciliationTest extends FloodlightTestCase {
protected MockFloodlightProvider mockFloodlightProvider;
protected FloodlightModuleContext fmc;
protected ILinkDiscoveryService lds;
protected FlowReconcileManager flowReconcileMgr;
protected MockThreadPoolService tps;
protected DefaultEntityClassifier entityClassifier;
protected PortDownReconciliation pdr;
protected ITopologyService topology;
protected IOFSwitch sw1, sw2, sw3, sw4;
protected Map<Long, IOFSwitch> switches;
protected Capture<List<OFMessage>> wc1, wc2, wc3, wc4;
protected Capture<FloodlightContext> bc1, bc2, bc3, bc4;
protected OFMessage fmd, fmd2;
protected ArrayList<OFMatchReconcile> lofmr;
protected OFMatchReconcile ofmr;
protected static Logger log;
protected FloodlightContext cntx;
protected List<OFStatistics> statsReply;
@Before
public void setUp() throws Exception {
super.setUp();
log = LoggerFactory.getLogger(PortDownReconciliation.class);
fmc = new FloodlightModuleContext();
mockFloodlightProvider = getMockFloodlightProvider();
pdr = new PortDownReconciliation();
lds = createMock(ILinkDiscoveryService.class);
entityClassifier = new DefaultEntityClassifier();
tps = new MockThreadPoolService();
flowReconcileMgr = new FlowReconcileManager();
topology = createMock(ITopologyService.class);
cntx = new FloodlightContext();
statsReply = new ArrayList<OFStatistics>();
fmc.addService(IThreadPoolService.class, tps);
fmc.addService(IFloodlightProviderService.class,
getMockFloodlightProvider());
fmc.addService(IFlowReconcileService.class, flowReconcileMgr);
fmc.addService(ITopologyService.class, topology);
fmc.addService(IEntityClassifierService.class, entityClassifier);
fmc.addService(ILinkDiscoveryService.class, lds);
tps.init(fmc);
flowReconcileMgr.init(fmc);
entityClassifier.init(fmc);
getMockFloodlightProvider().init(fmc);
pdr.init(fmc);
tps.startUp(fmc);
flowReconcileMgr.startUp(fmc);
entityClassifier.startUp(fmc);
getMockFloodlightProvider().startUp(fmc);
pdr.startUp(fmc);
// The STATS_REQUEST object used when querying the switches for 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((short) 3);
specificReq.setTableId((byte) 0xff);
req.setStatistics(Collections.singletonList((OFStatistics) specificReq));
requestLength += specificReq.getLength();
req.setLengthU(requestLength);
// Actions for the STATS_REPLY object
OFFlowMod flow = new OFFlowMod();
OFActionOutput action = new OFActionOutput((short) 3, (short) 0xffff);
List<OFAction> actions = new ArrayList<OFAction>();
actions.add(action);
// Match for the STATS_REPLY object
OFMatch m = new OFMatch();
// Set the incoming port to 1 so that it will find the connected
m.setInputPort((short) 1);
// STATS_REPLY object
OFFlowStatisticsReply reply = new OFFlowStatisticsReply();
reply.setActions(actions);
reply.setMatch(m);
// Add the reply to the list of OFStatistics
statsReply.add(reply);
// Create the STATS_REPLY asynchronous reply object
Callable<List<OFStatistics>> replyFuture = new ReplyFuture();
// Assign the callable object to a Futuretask so that it will produce future results
FutureTask<List<OFStatistics>> futureStats = new FutureTask<List<OFStatistics>>(
replyFuture);
// Assign the results of calling the object (the asynchronous reply)
Future<List<OFStatistics>> results = getResults(futureStats);
// SW1 -- Mock switch for base and multiple switch test case
sw1 = EasyMock.createNiceMock(IOFSwitch.class);
// Expect that the switch's ID is 1
expect(sw1.getId()).andReturn(1L).anyTimes();
expect(sw1.getStatistics(req)).andReturn(results).once();
// Captures to hold resulting flowmod delete messages
wc1 = new Capture<List<OFMessage>>(CaptureType.ALL);
bc1 = new Capture<FloodlightContext>(CaptureType.ALL);
// Capture the parameters passed when sw1.write is invoked
sw1.write(capture(wc1), capture(bc1));
expectLastCall().once();
replay(sw1);
// SW2 -- Mock switch for extended test cases
sw2 = EasyMock.createNiceMock(IOFSwitch.class);
// Expect that the switch's ID is 2
expect(sw2.getId()).andReturn(2L).anyTimes();
expect(sw2.getStatistics(req)).andReturn(results).once();
wc2 = new Capture<List<OFMessage>>(CaptureType.ALL);
bc2 = new Capture<FloodlightContext>(CaptureType.ALL);
// Capture the parameters passwed when sw1.write is invoked
sw2.write(capture(wc2), capture(bc2));
expectLastCall().anyTimes();
replay(sw2);
// SW3 -- Mock switch for extended test cases
sw3 = EasyMock.createNiceMock(IOFSwitch.class);
// Expect that the switch's ID is 3
expect(sw3.getId()).andReturn(3L).anyTimes();
expect(sw3.getStatistics(req)).andReturn(results).once();
wc3 = new Capture<List<OFMessage>>(CaptureType.ALL);
bc3 = new Capture<FloodlightContext>(CaptureType.ALL);
// Capture the parameters passwed when sw1.write is invoked
sw3.write(capture(wc3), capture(bc3));
expectLastCall().anyTimes();
replay(sw3);
// SW4 -- Mock switch for extended test cases
sw4 = EasyMock.createNiceMock(IOFSwitch.class);
// Expect that the switch's ID is 4
expect(sw4.getId()).andReturn(4L).anyTimes();
expect(sw4.getStatistics(req)).andReturn(results).once();
wc4 = new Capture<List<OFMessage>>(CaptureType.ALL);
bc4 = new Capture<FloodlightContext>(CaptureType.ALL);
// Capture the parameters passed when sw1.write is invoked
sw4.write(capture(wc4), capture(bc4));
expectLastCall().anyTimes();
replay(sw4);
// Here we create the OFMatch Reconcile list we wish to pass
lofmr = new ArrayList<OFMatchReconcile>();
// Create the only OFMatch Reconcile object that will be in the list
ofmr = new OFMatchReconcile();
long affectedSwitch = sw1.getId();
OFMatch match = new OFMatch().setWildcards(OFMatch.OFPFW_ALL);
OFMatchWithSwDpid ofmatchsw = new OFMatchWithSwDpid(match,
affectedSwitch);
ofmr.rcAction = OFMatchReconcile.ReconcileAction.UPDATE_PATH;
ofmr.ofmWithSwDpid = ofmatchsw;
// We'll say port 3 went down
ofmr.outPort = 3;
// Add the OFMatch Reconcile object to the list
lofmr.add(ofmr);
// Expected Flow Mod Deletes Messages
// Flow Mod Delete for base switch
fmd = ((OFFlowMod) mockFloodlightProvider.getOFMessageFactory()
.getMessage(OFType.FLOW_MOD))
.setMatch(new OFMatch().setWildcards(OFMatch.OFPFW_ALL))
.setCommand(OFFlowMod.OFPFC_DELETE)
// Notice we specify an outPort
.setOutPort((short) 3)
.setLength(U16.t(OFFlowMod.MINIMUM_LENGTH));
// Flow Mod Delete for the neighborswitches
fmd2 = ((OFFlowMod) mockFloodlightProvider.getOFMessageFactory()
.getMessage(OFType.FLOW_MOD))
// Notice we used the base switch's flow's match
.setMatch(flow.getMatch())
.setCommand(OFFlowMod.OFPFC_DELETE)
// Notice we specific an outPort
.setOutPort((short) 3)
.setLength(U16.t(OFFlowMod.MINIMUM_LENGTH));
}
// This generates the asynchronous reply to sw.getStatistics()
public Future<List<OFStatistics>> getResults(
FutureTask<List<OFStatistics>> futureStats) {
Thread t = new Thread(futureStats);
t.start();
return futureStats;
}
// Class for the asynchronous reply
public class ReplyFuture implements Callable<List<OFStatistics>> {
@Override
public List<OFStatistics> call() throws Exception {
// return stats reply defined above
return statsReply;
}
}
/**
* This tests the port down reconciliation in the event that the base switch
* is the only switch involved in the PORT_DOWN event. It simply deletes
* flows concerning the downed port.
*
* @verify checks to see that a general clearFlowMods(Short outPort) is
* called
* @throws Exception
*/
@Test
public void testSingleSwitchPortDownReconciliation() throws Exception {
log.debug("Starting single switch port down reconciliation test");
// Load the switch map
switches = new HashMap<Long, IOFSwitch>();
switches.put(1L, sw1);
mockFloodlightProvider.setSwitches(switches);
// Reconcile flows with specified OFMatchReconcile
pdr.reconcileFlows(lofmr);
// Validate results
verify(sw1);
assertTrue(wc1.hasCaptured());
List<List<OFMessage>> msglist = wc1.getValues();
// Make sure the messages we captures correct
for (List<OFMessage> m : msglist) {
if (m instanceof OFFlowMod)
assertEquals(fmd, m);
}
}
/**
* This tests the port down reconciliation in the event that the base switch
* is connected to a chain of three switches. It discovers that is has 1
* neighbor, which recursively finds out that it has 1 neighbor until the
* final switch "sw4" is evaluated, which has no neighbors.
*
* @verify checks to see that a general clearFlowMods(Short outPort) is
* called on the base switch while specific clearFlowMods(OFMatch
* match, Short outPort) are called on the neighboring switches
* @throws Exception
*/
@Test
public void testLinearLinkPortDownReconciliation() throws Exception {
log.debug("Starting linear link port down reconciliation test");
// Load the switch map
switches = new HashMap<Long, IOFSwitch>();
switches.put(1L, sw1);
switches.put(2L, sw2);
switches.put(3L, sw3);
switches.put(4L, sw4);
mockFloodlightProvider.setSwitches(switches);
// Create the links between the switches
// (Switch 4) --> (Switch 3) --> (Switch 2) --> (Switch 1)
Map<Link, LinkInfo> links = new HashMap<Link, LinkInfo>();
Link link = new Link(2L, (short) 3, 1L, (short) 1);
Link link2 = new Link(3L, (short) 3, 2L, (short) 1);
Link link3 = new Link(4L, (short) 3, 3L, (short) 1);
LinkInfo linkinfo = null;
links.put(link, linkinfo);
links.put(link2, linkinfo);
links.put(link3, linkinfo);
// Make sure that the link discovery service provides the link we made
expect(lds.getLinks()).andReturn(links).anyTimes();
replay(lds);
// Reconcile flows with specified OFMatchReconcile
pdr.reconcileFlows(lofmr);
// Validate results
verify(sw1, sw2, sw3, sw4);
// Make sure each capture is not null
assertTrue(wc2.hasCaptured());
assertTrue(wc3.hasCaptured());
assertTrue(wc4.hasCaptured());
// Make sure each capture has captured the proper Flow Mod Delete
// message
List<List<OFMessage>> msglist = wc2.getValues();
for (List<OFMessage> m : msglist) {
if (m instanceof OFFlowMod)
assertEquals(fmd2, m);
}
msglist = wc3.getValues();
for (List<OFMessage> m : msglist) {
if (m instanceof OFFlowMod)
assertEquals(fmd2, m);
}
msglist = wc4.getValues();
for (List<OFMessage> m : msglist) {
if (m instanceof OFFlowMod)
assertEquals(fmd2, m);
}
}
/**
* This tests the port down reconciliation in the event that the base switch
* has three separate neighboring switches with invalid flows. It discovers
* that is has 3 neighbors and each of them delete flows with the specific
* OFMatch and outPort.
*
* @verify checks to see that a general clearFlowMods(Short outPort) is
* called on the base switch while specific clearFlowMods(OFMatch
* match, Short outPort) are called on the neighboring switches
* @throws Exception
*/
@Test
public void testMultipleLinkPortDownReconciliation() throws Exception {
log.debug("Starting multiple link port down reconciliation test");
// Load the switch map
switches = new HashMap<Long, IOFSwitch>();
switches.put(1L, sw1);
switches.put(2L, sw2);
switches.put(3L, sw3);
switches.put(4L, sw4);
mockFloodlightProvider.setSwitches(switches);
// Create the links between the switches
// (Switch 4 output port 3) --> (Switch 1 input port 1)
// (Switch 3 output port 3) --> (Switch 1 input port 1)
// (Switch 2 output port 3) --> (Switch 1 input port 1)
Map<Link, LinkInfo> links = new HashMap<Link, LinkInfo>();
Link link = new Link(2L, (short) 3, 1L, (short) 1);
Link link2 = new Link(3L, (short) 3, 1L, (short) 1);
Link link3 = new Link(4L, (short) 3, 1L, (short) 1);
LinkInfo linkinfo = null;
links.put(link, linkinfo);
links.put(link2, linkinfo);
links.put(link3, linkinfo);
// Make sure that the link discovery service provides the link we made
expect(lds.getLinks()).andReturn(links).anyTimes();
replay(lds);
// Reconcile flows with specified OFMatchReconcile
pdr.reconcileFlows(lofmr);
// Validate results
verify(sw1, sw2, sw3, sw4);
// Make sure each capture is not null
assertTrue(wc2.hasCaptured());
assertTrue(wc3.hasCaptured());
assertTrue(wc4.hasCaptured());
// Make sure each capture has captured the proper Flow Mod Delete
// message
List<List<OFMessage>> msglist = wc2.getValues();
for (List<OFMessage> m : msglist) {
if (m instanceof OFFlowMod)
assertEquals(fmd2, m);
}
msglist = wc3.getValues();
for (List<OFMessage> m : msglist) {
if (m instanceof OFFlowMod)
assertEquals(fmd2, m);
}
msglist = wc4.getValues();
for (List<OFMessage> m : msglist) {
if (m instanceof OFFlowMod)
assertEquals(fmd2, m);
}
}
}
\ No newline at end of file
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment