Skip to content
Snippets Groups Projects
Commit 99e84863 authored by Gregor Maier's avatar Gregor Maier
Browse files

Add FlowMod Dampening to Forwarding. Fix broken ForwardingTest.

parent 3620e5d1
No related branches found
No related tags found
No related merge requests found
......@@ -180,7 +180,7 @@
<batchtest todir="${test-output}">
<fileset dir="${source-test}">
<exclude name="**/storage/tests/StorageTest.java"/>
<exclude name="**/test/Mock*"/>
<include name="**/*Test*.java"/>
<exclude name="**/core/test/**"/>
<exclude name="**/core/module/**"/>
</fileset>
......
......@@ -152,7 +152,7 @@ public class Forwarding extends ForwardingBase implements IFloodlightModule {
log.debug("write drop flow-mod sw={} match={} flow-mod={}",
new Object[] { sw, match, fm });
}
sw.write(fm, cntx);
messageDamper.write(sw, fm, cntx);
} catch (IOException e) {
log.error("Failure writing drop flow mod", e);
}
......@@ -309,9 +309,11 @@ public class Forwarding extends ForwardingBase implements IFloodlightModule {
(OFPacketOut) floodlightProvider.getOFMessageFactory().getMessage(OFType.PACKET_OUT);
List<OFAction> actions = new ArrayList<OFAction>();
if (sw.hasAttribute(IOFSwitch.PROP_SUPPORTS_OFPP_FLOOD)) {
actions.add(new OFActionOutput(OFPort.OFPP_FLOOD.getValue(), (short)0));
actions.add(new OFActionOutput(OFPort.OFPP_FLOOD.getValue(),
(short)0xFFFF));
} else {
actions.add(new OFActionOutput(OFPort.OFPP_ALL.getValue(), (short)0));
actions.add(new OFActionOutput(OFPort.OFPP_ALL.getValue(),
(short)0xFFFF));
}
po.setActions(actions);
po.setActionsLength((short) OFActionOutput.MINIMUM_LENGTH);
......@@ -332,7 +334,7 @@ public class Forwarding extends ForwardingBase implements IFloodlightModule {
log.trace("Writing flood PacketOut switch={} packet-in={} packet-out={}",
new Object[] {sw, pi, po});
}
sw.write(po, cntx);
messageDamper.write(sw, po, cntx);
} catch (IOException e) {
log.error("Failure writing PacketOut switch={} packet-in={} packet-out={}",
new Object[] {sw, pi, po}, e);
......@@ -396,6 +398,7 @@ public class Forwarding extends ForwardingBase implements IFloodlightModule {
"properties file."),
})
public void init(FloodlightModuleContext context) throws FloodlightModuleException {
super.init();
this.floodlightProvider = context.getServiceImpl(IFloodlightProviderService.class);
this.deviceManager = context.getServiceImpl(IDeviceService.class);
this.routingEngine = context.getServiceImpl(IRoutingService.class);
......
......@@ -18,6 +18,7 @@
package net.floodlightcontroller.routing;
import java.io.IOException;
import java.util.EnumSet;
import java.util.ArrayList;
import java.util.Comparator;
import java.util.Iterator;
......@@ -44,6 +45,7 @@ import net.floodlightcontroller.routing.IRoutingDecision;
import net.floodlightcontroller.routing.Route;
import net.floodlightcontroller.topology.ITopologyService;
import net.floodlightcontroller.topology.NodePortTuple;
import net.floodlightcontroller.util.OFMessageDamper;
import net.floodlightcontroller.util.TimedCache;
import org.openflow.protocol.OFFlowMod;
......@@ -68,7 +70,10 @@ public abstract class ForwardingBase
protected static Logger log =
LoggerFactory.getLogger(ForwardingBase.class);
protected static int OFMESSAGE_DAMPER_CAPACITY = 50000; // TODO: find sweet spot
protected static int OFMESSAGE_DAMPER_TIMEOUT = 250; // ms
public static short FLOWMOD_DEFAULT_IDLE_TIMEOUT = 5; // in seconds
public static short FLOWMOD_DEFAULT_HARD_TIMEOUT = 0; // infinite
......@@ -78,6 +83,8 @@ public abstract class ForwardingBase
protected ITopologyService topology;
protected ICounterStoreService counterStore;
protected OFMessageDamper messageDamper;
// for broadcast loop suppression
protected boolean broadcastCacheFeature = true;
public final int prime1 = 2633; // for hash calculation
......@@ -102,6 +109,16 @@ public abstract class ForwardingBase
return d1ClusterId.compareTo(d2ClusterId);
}
};
/**
* init data structures
*
*/
protected void init() {
messageDamper = new OFMessageDamper(OFMESSAGE_DAMPER_CAPACITY,
EnumSet.of(OFType.FLOW_MOD),
OFMESSAGE_DAMPER_TIMEOUT);
}
/**
* Adds a listener for devicemanager and registers for PacketIns.
......@@ -257,7 +274,7 @@ public abstract class ForwardingBase
fm.getMatch().getInputPort(),
outPort });
}
sw.write(fm, cntx);
messageDamper.write(sw, fm, cntx);
if (doFlush) {
sw.flush();
}
......@@ -365,7 +382,7 @@ public abstract class ForwardingBase
try {
counterStore.updatePktOutFMCounterStore(sw, po);
sw.write(po, cntx);
messageDamper.write(sw, po, cntx);
} catch (IOException e) {
log.error("Failure writing packet out", e);
}
......@@ -448,7 +465,7 @@ public abstract class ForwardingBase
try {
counterStore.updatePktOutFMCounterStore(sw, po);
sw.write(po, cntx);
messageDamper.write(sw, po, cntx);
} catch (IOException e) {
log.error("Failure writing packet out", e);
}
......@@ -505,7 +522,7 @@ public abstract class ForwardingBase
"interfaces={} packet-out={}",
new Object[] {sw.getId(), outPorts, po});
}
sw.write(po, cntx);
messageDamper.write(sw, po, cntx);
} catch (IOException e) {
log.error("Failure writing packet out", e);
......@@ -624,6 +641,7 @@ public abstract class ForwardingBase
try {
log.debug("write drop flow-mod sw={} match={} flow-mod={}",
new Object[] { sw, match, fm });
// TODO: can't use the message damper sine this method is static
sw.write(fm, null);
} catch (IOException e) {
log.error("Failure writing deny flow mod", e);
......
......@@ -80,4 +80,12 @@ public class MockDevice extends Device {
}
return vals.toArray(new SwitchPort[vals.size()]);
}
@Override
public String toString() {
String rv = "MockDevice[entities=+";
rv += entities.toString();
rv += "]";
return rv;
}
}
......@@ -17,15 +17,7 @@
package net.floodlightcontroller.forwarding;
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.reset;
import static org.easymock.EasyMock.verify;
import static org.easymock.EasyMock.capture;
import static org.easymock.EasyMock.anyLong;
import static org.easymock.EasyMock.anyShort;
import static org.easymock.EasyMock.*;
import java.util.ArrayList;
import java.util.Date;
......@@ -55,6 +47,7 @@ import net.floodlightcontroller.routing.IRoutingService;
import net.floodlightcontroller.routing.Route;
import net.floodlightcontroller.test.FloodlightTestCase;
import net.floodlightcontroller.threadpool.IThreadPoolService;
import net.floodlightcontroller.topology.ITopologyListener;
import net.floodlightcontroller.topology.ITopologyService;
import net.floodlightcontroller.topology.NodePortTuple;
import net.floodlightcontroller.flowcache.FlowReconcileManager;
......@@ -71,10 +64,12 @@ import org.openflow.protocol.OFMatch;
import org.openflow.protocol.OFMessage;
import org.openflow.protocol.OFPacketIn;
import org.openflow.protocol.OFPacketOut;
import org.openflow.protocol.OFPort;
import org.openflow.protocol.OFType;
import org.openflow.protocol.OFPacketIn.OFPacketInReason;
import org.openflow.protocol.action.OFAction;
import org.openflow.protocol.action.OFActionOutput;
import org.openflow.util.HexString;
public class ForwardingTest extends FloodlightTestCase {
protected MockFloodlightProvider mockFloodlightProvider;
......@@ -90,6 +85,7 @@ public class ForwardingTest extends FloodlightTestCase {
protected IDevice srcDevice, dstDevice1, dstDevice2;
protected OFPacketIn packetIn;
protected OFPacketOut packetOut;
protected OFPacketOut packetOutFlooded;
protected IPacket testPacket;
protected byte[] testPacketSerialized;
protected int expected_wildcards;
......@@ -142,6 +138,9 @@ public class ForwardingTest extends FloodlightTestCase {
fmc.addService(IFlowReconcileService.class, flowReconcileMgr);
fmc.addService(IEntityClassifierService.class, entityClassifier);
topology.addListener(anyObject(ITopologyListener.class));
expectLastCall().anyTimes();
replay(topology);
threadPool.init(fmc);
forwarding.init(fmc);
deviceManager.init(fmc);
......@@ -152,19 +151,22 @@ public class ForwardingTest extends FloodlightTestCase {
forwarding.startUp(fmc);
flowReconcileMgr.startUp(fmc);
entityClassifier.startUp(fmc);
verify(topology);
swFeatures = new OFFeaturesReply();
swFeatures.setBuffers(1000);
// Mock switches
sw1 = EasyMock.createNiceMock(IOFSwitch.class);
sw1 = EasyMock.createMock(IOFSwitch.class);
expect(sw1.getId()).andReturn(1L).anyTimes();
expect(sw1.getFeaturesReply()).andReturn(swFeatures).anyTimes();
expect(topology.getL2DomainId(1L)).andReturn(1L).anyTimes();
expect(sw1.getStringId())
.andReturn(HexString.toHexString(1L)).anyTimes();
sw2 = EasyMock.createNiceMock(IOFSwitch.class);
sw2 = EasyMock.createMock(IOFSwitch.class);
expect(sw2.getId()).andReturn(2L).anyTimes();
expect(sw2.getFeaturesReply()).andReturn(swFeatures).anyTimes();
expect(topology.getL2DomainId(2L)).andReturn(1L).anyTimes();
expect(sw2.getStringId())
.andReturn(HexString.toHexString(2L)).anyTimes();
//fastWilcards mocked as this constant
int fastWildcards =
......@@ -203,34 +205,9 @@ public class ForwardingTest extends FloodlightTestCase {
.setDestinationPort((short) 5001)
.setPayload(new Data(new byte[] {0x01}))));
// Build src and dest devices
byte[] dataLayerSource = ((Ethernet)testPacket).getSourceMACAddress();
byte[] dataLayerDest =
((Ethernet)testPacket).getDestinationMACAddress();
int networkSource =
((IPv4)((Ethernet)testPacket).getPayload()).
getSourceAddress();
int networkDest =
((IPv4)((Ethernet)testPacket).getPayload()).
getDestinationAddress();
currentDate = new Date();
expect(topology.isAttachmentPointPort(1L, (short)1))
.andReturn(true)
.anyTimes();
expect(topology.isAttachmentPointPort(2L, (short)3))
.andReturn(true)
.anyTimes();
replay(topology);
srcDevice =
deviceManager.learnEntity(Ethernet.toLong(dataLayerSource),
null, networkSource,
1L, 1);
dstDevice1 =
deviceManager.learnEntity(Ethernet.toLong(dataLayerDest),
null, networkDest,
2L, 3);
currentDate = new Date();
// Mock Packet-in
testPacketSerialized = testPacket.serialize();
......@@ -257,6 +234,22 @@ public class ForwardingTest extends FloodlightTestCase {
.setLengthU(OFPacketOut.MINIMUM_LENGTH+
packetOut.getActionsLength()+
testPacketSerialized.length);
// Mock Packet-out with OFPP_FLOOD action
packetOutFlooded =
(OFPacketOut) mockFloodlightProvider.getOFMessageFactory().
getMessage(OFType.PACKET_OUT);
packetOutFlooded.setBufferId(this.packetIn.getBufferId())
.setInPort(this.packetIn.getInPort());
poactions = new ArrayList<OFAction>();
poactions.add(new OFActionOutput(OFPort.OFPP_FLOOD.getValue(),
(short) 0xffff));
packetOutFlooded.setActions(poactions)
.setActionsLength((short) OFActionOutput.MINIMUM_LENGTH)
.setPacketData(testPacketSerialized)
.setLengthU(OFPacketOut.MINIMUM_LENGTH+
packetOutFlooded.getActionsLength()+
testPacketSerialized.length);
expected_wildcards = fastWildcards;
expected_wildcards &= ~OFMatch.OFPFW_IN_PORT &
......@@ -266,19 +259,68 @@ public class ForwardingTest extends FloodlightTestCase {
expected_wildcards &= ~OFMatch.OFPFW_NW_SRC_MASK &
~OFMatch.OFPFW_NW_DST_MASK;
// Add the packet to the context store
IFloodlightProviderService.bcStore.
put(cntx,
IFloodlightProviderService.CONTEXT_PI_PAYLOAD,
(Ethernet)testPacket);
IDeviceService.fcStore.
put(cntx,
IDeviceService.CONTEXT_SRC_DEVICE,
srcDevice);
}
enum DestDeviceToLearn { NONE, DEVICE1 ,DEVICE2 };
public void learnDevices(DestDeviceToLearn destDeviceToLearn) {
// Build src and dest devices
byte[] dataLayerSource = ((Ethernet)testPacket).getSourceMACAddress();
byte[] dataLayerDest =
((Ethernet)testPacket).getDestinationMACAddress();
int networkSource =
((IPv4)((Ethernet)testPacket).getPayload()).
getSourceAddress();
int networkDest =
((IPv4)((Ethernet)testPacket).getPayload()).
getDestinationAddress();
reset(topology);
expect(topology.isAttachmentPointPort(1L, (short)1))
.andReturn(true)
.anyTimes();
expect(topology.isAttachmentPointPort(2L, (short)3))
.andReturn(true)
.anyTimes();
expect(topology.isAttachmentPointPort(1L, (short)3))
.andReturn(true)
.anyTimes();
replay(topology);
srcDevice =
deviceManager.learnEntity(Ethernet.toLong(dataLayerSource),
null, networkSource,
1L, 1);
IDeviceService.fcStore. put(cntx,
IDeviceService.CONTEXT_SRC_DEVICE,
srcDevice);
if (destDeviceToLearn == DestDeviceToLearn.DEVICE1) {
dstDevice1 =
deviceManager.learnEntity(Ethernet.toLong(dataLayerDest),
null, networkDest,
2L, 3);
IDeviceService.fcStore.put(cntx,
IDeviceService.CONTEXT_DST_DEVICE,
dstDevice1);
}
if (destDeviceToLearn == DestDeviceToLearn.DEVICE2) {
dstDevice2 =
deviceManager.learnEntity(Ethernet.toLong(dataLayerDest),
null, networkDest,
1L, 3);
IDeviceService.fcStore.put(cntx,
IDeviceService.CONTEXT_DST_DEVICE,
dstDevice2);
}
verify(topology);
}
@Test
public void testForwardMultiSwitchPath() throws Exception {
learnDevices(DestDeviceToLearn.DEVICE1);
Capture<OFMessage> wc1 = new Capture<OFMessage>(CaptureType.ALL);
Capture<OFMessage> wc2 = new Capture<OFMessage>(CaptureType.ALL);
......@@ -287,11 +329,6 @@ public class ForwardingTest extends FloodlightTestCase {
Capture<FloodlightContext> bc2 =
new Capture<FloodlightContext>(CaptureType.ALL);
// Set destination as sw2 and Mock route
IDeviceService.fcStore.
put(cntx,
IDeviceService.CONTEXT_DST_DEVICE,
dstDevice1);
Route route = new Route(1L, 2L);
List<NodePortTuple> nptList = new ArrayList<NodePortTuple>();
......@@ -358,38 +395,8 @@ public class ForwardingTest extends FloodlightTestCase {
@Test
public void testForwardSingleSwitchPath() throws Exception {
// Set destination as local and Mock route
byte[] dataLayerSource = ((Ethernet)testPacket).getSourceMACAddress();
byte[] dataLayerDest =
((Ethernet)testPacket).getDestinationMACAddress();
int networkSource =
((IPv4)((Ethernet)testPacket).getPayload()).
getSourceAddress();
int networkDest =
((IPv4)((Ethernet)testPacket).getPayload()).
getDestinationAddress();
deviceManager.startUp(null);
reset(topology);
expect(topology.isAttachmentPointPort(EasyMock.anyLong(), EasyMock.anyShort()))
.andReturn(true).anyTimes();
expect(topology.getL2DomainId(1L)).andReturn(1L).anyTimes();
replay(topology);
srcDevice =
deviceManager.learnEntity(Ethernet.toLong(dataLayerSource),
null, networkSource,
1L, 1);
dstDevice2 =
deviceManager.learnEntity(Ethernet.toLong(dataLayerDest),
null, networkDest,
1L, 3);
learnDevices(DestDeviceToLearn.DEVICE2);
IDeviceService.fcStore.
put(cntx,
IDeviceService.CONTEXT_DST_DEVICE,
dstDevice2);
Route route = new Route(1L, 1L);
route.getPath().add(new NodePortTuple(1L, (short)1));
route.getPath().add(new NodePortTuple(1L, (short)3));
......@@ -430,11 +437,67 @@ public class ForwardingTest extends FloodlightTestCase {
verify(sw1, sw2, routingEngine);
}
@Test
public void testFlowModDampening() throws Exception {
learnDevices(DestDeviceToLearn.DEVICE2);
reset(topology);
expect(topology.isAttachmentPointPort(EasyMock.anyLong(), EasyMock.anyShort()))
.andReturn(true).anyTimes();
expect(topology.getL2DomainId(1L)).andReturn(1L).anyTimes();
replay(topology);
Route route = new Route(1L, 1L);
route.getPath().add(new NodePortTuple(1L, (short)1));
route.getPath().add(new NodePortTuple(1L, (short)3));
expect(routingEngine.getRoute(1L, (short)1, 1L, (short)3)).andReturn(route).atLeastOnce();
// Expected Flow-mods
OFMatch match = new OFMatch();
match.loadFromPacket(testPacketSerialized, (short) 1);
OFActionOutput action = new OFActionOutput((short)3, (short)0xffff);
List<OFAction> actions = new ArrayList<OFAction>();
actions.add(action);
OFFlowMod fm1 =
(OFFlowMod) mockFloodlightProvider.getOFMessageFactory().
getMessage(OFType.FLOW_MOD);
fm1.setIdleTimeout((short)5)
.setMatch(match.clone()
.setWildcards(expected_wildcards))
.setActions(actions)
.setBufferId(OFPacketOut.BUFFER_ID_NONE)
.setCookie(2L << 52)
.setLengthU(OFFlowMod.MINIMUM_LENGTH +
OFActionOutput.MINIMUM_LENGTH);
// Record expected packet-outs/flow-mods
sw1.write(fm1, cntx);
expectLastCall().once();
sw1.write(packetOut, cntx);
expectLastCall().times(3);
reset(topology);
expect(topology.isIncomingBroadcastAllowed(anyLong(), anyShort())).andReturn(true).anyTimes();
expect(topology.getL2DomainId(1L)).andReturn(1L).anyTimes();
expect(topology.isAttachmentPointPort(1L, (short)1)).andReturn(true).anyTimes();
expect(topology.isAttachmentPointPort(1L, (short)3)).andReturn(true).anyTimes();
// Reset mocks, trigger the packet in, and validate results
replay(sw1, routingEngine, topology);
forwarding.receive(sw1, this.packetIn, cntx);
forwarding.receive(sw1, this.packetIn, cntx);
forwarding.receive(sw1, this.packetIn, cntx);
verify(sw1, routingEngine);
}
@Test
public void testForwardNoPath() throws Exception {
learnDevices(DestDeviceToLearn.NONE);
// Set no destination attachment point or route
// expect no Flow-mod or packet out
// expect no Flow-mod but expect the packet to be flooded
// Reset mocks, trigger the packet in, and validate results
reset(topology);
......@@ -443,6 +506,10 @@ public class ForwardingTest extends FloodlightTestCase {
EasyMock.anyShort()))
.andReturn(true)
.anyTimes();
expect(sw1.hasAttribute(IOFSwitch.PROP_SUPPORTS_OFPP_FLOOD))
.andReturn(true).anyTimes();
sw1.write(packetOutFlooded, cntx);
expectLastCall().once();
replay(sw1, sw2, routingEngine, topology);
forwarding.receive(sw1, this.packetIn, cntx);
verify(sw1, sw2, routingEngine);
......
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