/*
* Copyright (c) 2013 Big Switch Networks, Inc.
*
* Licensed under the Eclipse Public License, Version 1.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.eclipse.org/legal/epl-v10.html
*
* 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 org.sdnplatform.flowcache;
import static org.easymock.EasyMock.*;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
import org.easymock.Capture;
import org.easymock.CaptureType;
import org.easymock.EasyMock;
import org.junit.After;
import org.junit.Before;
import org.junit.Test;
import org.openflow.protocol.OFFlowMod;
import org.openflow.protocol.OFFlowRemoved;
import org.openflow.protocol.OFMatch;
import org.openflow.protocol.OFMatchWithSwDpid;
import org.openflow.protocol.OFMessage;
import org.openflow.protocol.OFPacketIn;
import org.openflow.protocol.OFPacketOut;
import org.openflow.protocol.OFPort;
import org.openflow.protocol.OFStatisticsReply;
import org.openflow.protocol.OFStatisticsRequest;
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.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.sdnplatform.addressspace.IAddressSpaceManagerService;
import org.sdnplatform.core.ListenerContext;
import org.sdnplatform.core.IControllerService;
import org.sdnplatform.core.IOFMessageListener;
import org.sdnplatform.core.IOFSwitch;
import org.sdnplatform.core.module.ModuleContext;
import org.sdnplatform.core.test.MockThreadPoolService;
import org.sdnplatform.core.util.AppCookie;
import org.sdnplatform.counter.CounterStore;
import org.sdnplatform.counter.ICounterStoreService;
import org.sdnplatform.devicemanager.IDevice;
import org.sdnplatform.devicemanager.IDeviceService;
import org.sdnplatform.devicemanager.IEntityClassifierService;
import org.sdnplatform.devicemanager.SwitchPort;
import org.sdnplatform.devicemanager.internal.DefaultEntityClassifier;
import org.sdnplatform.devicemanager.test.MockDeviceManager;
import org.sdnplatform.flowcache.BetterFlowCache;
import org.sdnplatform.flowcache.BetterFlowReconcileManager;
import org.sdnplatform.flowcache.FCQueryObj;
import org.sdnplatform.flowcache.FlowCacheObj;
import org.sdnplatform.flowcache.FlowCacheQueryResp;
import org.sdnplatform.flowcache.IFlowCacheService;
import org.sdnplatform.flowcache.IFlowReconcileService;
import org.sdnplatform.flowcache.QRFlowCacheObj;
import org.sdnplatform.flowcache.BetterFlowCache.FCOper;
import org.sdnplatform.flowcache.IFlowCacheService.FCQueryEvType;
import org.sdnplatform.forwarding.Forwarding;
import org.sdnplatform.forwarding.IForwardingService;
import org.sdnplatform.forwarding.IRewriteService;
import org.sdnplatform.forwarding.RewriteServiceImpl;
import org.sdnplatform.netvirt.core.VNS;
import org.sdnplatform.netvirt.core.NetVirtExplainPacket;
import org.sdnplatform.netvirt.core.VNSInterface;
import org.sdnplatform.netvirt.manager.INetVirtManagerService;
import org.sdnplatform.netvirt.virtualrouting.IVirtualRoutingService;
import org.sdnplatform.netvirt.virtualrouting.internal.VirtualRouting;
import org.sdnplatform.packet.ARP;
import org.sdnplatform.packet.Data;
import org.sdnplatform.packet.Ethernet;
import org.sdnplatform.packet.IPacket;
import org.sdnplatform.packet.IPv4;
import org.sdnplatform.packet.UDP;
import org.sdnplatform.restserver.IRestApiService;
import org.sdnplatform.restserver.RestApiServer;
import org.sdnplatform.routing.ForwardingBase;
import org.sdnplatform.routing.IRoutingDecision;
import org.sdnplatform.routing.IRoutingService;
import org.sdnplatform.routing.Route;
import org.sdnplatform.storage.IStorageSourceService;
import org.sdnplatform.storage.memory.MemoryStorageSource;
import org.sdnplatform.test.PlatformTestCase;
import org.sdnplatform.threadpool.IThreadPoolService;
import org.sdnplatform.topology.ITopologyService;
import org.sdnplatform.topology.NodePortTuple;
import org.sdnplatform.tunnelmanager.ITunnelManagerService;
public class BetterFlowCacheTest extends PlatformTestCase {
protected ListenerContext cntx12, cntx21, cntx13, cntx31, cntx14;
protected MockDeviceManager deviceManager;
protected IRoutingService routingEngine;
protected ITopologyService topology;
protected ITunnelManagerService tunnelManager;
protected VirtualRouting virtualRouting;
protected Forwarding forwarding;
protected RestApiServer restApi;
protected BetterFlowCache betterFlowCacheMgr;
protected ICounterStoreService counterStore;
protected INetVirtManagerService mockNetVirtManager;
protected BetterFlowReconcileManager flowReconcileMgr;
protected RewriteServiceImpl rewriteService;
protected IAddressSpaceManagerService addressSpaceManager;
protected IOFSwitch sw1, sw2, sw3;
protected IDevice device1, device2, device2alt, device3, device4;
protected OFPacketIn packetIn12, packetIn21, packetIn13, packetIn31;
protected OFPacketIn packetIn14, arpPacketIn;
protected OFPacketOut packetOut12, packetOut21, packetOut13, packetOut31;
protected OFPacketOut packetOut14, arpPacketOut;
protected OFFlowRemoved flowRemoveMsg12;
protected OFFlowRemoved flowRemoveMsg21;
protected OFFlowRemoved flowRemoveMsg13;
protected OFFlowRemoved flowRemoveMsg31;
protected OFFlowRemoved flowRemoveMsg14;
protected IPacket testPacket12, testPacket21, testPacket13, testPacket31;
protected IPacket testPacket14, testARPPacket;
protected IPacket testMulticastPacket;
protected IPacket testSecondMulticastPacket;
protected byte[] testPacketSerialized12;
protected byte[] testPacketSerialized21;
protected byte[] testPacketSerialized13;
protected byte[] testPacketSerialized31;
protected byte[] testPacketSerialized14;
protected byte[] testARPPacketSerialized;
protected byte[] testSecondMulticastPacketSerialized;
protected byte[] testMulticastPacketSerialized;
protected IPacket testPacketUnknownDest;
protected byte[] testPacketUnknownDestSerialized;
protected IPacket testBroadcastPacket;
protected byte[] testBroadcastPacketSerialized;
protected IRoutingDecision decision12, decision21, decision13, decision31;
protected IRoutingDecision decision14;
protected int expected_wildcards;
protected Date currentDate;
protected OFStatisticsRequest ofStatsRequest;
private MockThreadPoolService tp;
@Before
public void setUp() throws Exception {
super.setUp();
ModuleContext fmc = new ModuleContext();
// Mock context
cntx12 = new ListenerContext();
cntx21 = new ListenerContext();
cntx13 = new ListenerContext();
cntx31 = new ListenerContext();
cntx14 = new ListenerContext();
forwarding = new Forwarding();
deviceManager = new MockDeviceManager();
flowReconcileMgr = new BetterFlowReconcileManager();
virtualRouting = new VirtualRouting();
mockControllerProvider = getMockControllerProvider();
rewriteService = new RewriteServiceImpl();
tp = new MockThreadPoolService();
DefaultEntityClassifier entityClassifier = new DefaultEntityClassifier();
addressSpaceManager = createMock(IAddressSpaceManagerService.class);
restApi = new RestApiServer();
betterFlowCacheMgr = new BetterFlowCache();
betterFlowCacheMgr.setAppName("netVirt");
betterFlowCacheMgr.periodicSwScanInitDelayMsec = 0;
betterFlowCacheMgr.periodicSwScanIntervalMsec = 100; // ms
mockNetVirtManager = createMock(INetVirtManagerService.class);
routingEngine = createMock(IRoutingService.class);
topology = createMock(ITopologyService.class);
tunnelManager = createMock(ITunnelManagerService.class);
counterStore = new CounterStore();
fmc.addService(IForwardingService.class, forwarding);
fmc.addService(IControllerService.class, mockControllerProvider);
fmc.addService(IThreadPoolService.class, tp);
fmc.addService(IDeviceService.class, deviceManager);
fmc.addService(IRoutingService.class, routingEngine);
fmc.addService(ITopologyService.class, topology);
fmc.addService(ITunnelManagerService.class, tunnelManager);
fmc.addService(IVirtualRoutingService.class, virtualRouting);
fmc.addService(INetVirtManagerService.class, mockNetVirtManager);
fmc.addService(IFlowCacheService.class, betterFlowCacheMgr);
fmc.addService(ICounterStoreService.class, counterStore);
fmc.addService(IFlowReconcileService.class, flowReconcileMgr);
fmc.addService(IEntityClassifierService.class, entityClassifier);
fmc.addService(IAddressSpaceManagerService.class, addressSpaceManager);
fmc.addService(IRewriteService.class, rewriteService);
fmc.addService(IRestApiService.class, restApi);
fmc.addService(IStorageSourceService.class, new MemoryStorageSource());
deviceManager.init(fmc);
virtualRouting.init(fmc);
betterFlowCacheMgr.init(fmc);
flowReconcileMgr.init(fmc);
forwarding.init(fmc);
rewriteService.init(fmc);
tp.init(fmc);
entityClassifier.init(fmc);
restApi.init(fmc);
topology.addListener(flowReconcileMgr);
expectLastCall().times(1);
deviceManager.startUp(fmc);
betterFlowCacheMgr.startUp(fmc);
flowReconcileMgr.startUp(fmc);
forwarding.startUp(fmc);
rewriteService.startUp(fmc);
tp.startUp(fmc);
entityClassifier.startUp(fmc);
restApi.startUp(fmc);
// Mock tunnel manager
expect(tunnelManager.isTunnelEndpoint(anyObject(IDevice.class)))
.andReturn(false).anyTimes();
expect(tunnelManager.isTunnelEndpoint(null)).andReturn(false).anyTimes();
expect(tunnelManager.getTunnelPortNumber(EasyMock.anyLong())).andReturn(null).anyTimes();
expect(tunnelManager.getTunnelLoopbackPort(EasyMock.anyLong())).andReturn(null).anyTimes();
replay(tunnelManager);
// Mock address space manager
addressSpaceManager.getSwitchPortVlanMode(anyObject(SwitchPort.class),
anyObject(String.class),
anyShort(),
anyBoolean());
expectLastCall().andReturn(Ethernet.VLAN_UNTAGGED).anyTimes();
replay(addressSpaceManager);
// Mock switches
sw1 = EasyMock.createNiceMock(IOFSwitch.class);
expect(sw1.getId()).andReturn(1L).anyTimes();
expect(sw1.isConnected()).andReturn(true).anyTimes();
expect(sw1.hasAttribute(IOFSwitch.PROP_REQUIRES_L3_MATCH)).
andReturn(false).anyTimes();
expect(sw1.getStringId()).andReturn("00:00:00:00:00:00:00:01").
anyTimes();
sw2 = EasyMock.createNiceMock(IOFSwitch.class);
expect(sw2.getId()).andReturn(2L).anyTimes();
expect(sw2.isConnected()).andReturn(true).anyTimes();
expect(sw2.hasAttribute(IOFSwitch.PROP_REQUIRES_L3_MATCH)).
andReturn(false).anyTimes();
expect(sw2.getStringId()).andReturn("00:00:00:00:00:00:00:02").
anyTimes();
sw3 = EasyMock.createNiceMock(IOFSwitch.class);
expect(sw3.getId()).andReturn(3L).anyTimes();
expect(sw3.isConnected()).andReturn(true).anyTimes();
expect(sw3.hasAttribute(IOFSwitch.PROP_REQUIRES_L3_MATCH)).
andReturn(false).anyTimes();
expect(sw3.getStringId()).andReturn("00:00:00:00:00:00:00:03").
anyTimes();
//switch 3 belongs to cluster 3. as it is on its own.
// Load the switch map
Map<Long, IOFSwitch> switches = new HashMap<Long, IOFSwitch>();
switches.put(1L, sw1);
switches.put(2L, sw2);
switches.put(3L, sw3);
mockControllerProvider.setSwitches(switches);
assertEquals(switches, mockControllerProvider.getSwitches());
// Build test packets
testPacket12 = new Ethernet()
.setDestinationMACAddress("00:00:00:00:00:02")
.setSourceMACAddress("00:00:00:00:00:01")
.setEtherType(Ethernet.TYPE_IPv4)
.setPayload(
new IPv4()
.setTtl((byte) 128)
.setDestinationAddress("192.168.1.2")
.setSourceAddress("192.168.1.1")
.setPayload(new UDP()
.setSourcePort((short) 5000)
.setDestinationPort((short) 5001)
.setPayload(new Data(new byte[] {0x01}))));
testPacketSerialized12 = testPacket12.serialize();
testPacket21 = new Ethernet()
.setDestinationMACAddress("00:00:00:00:00:01")
.setSourceMACAddress("00:00:00:00:00:02")
.setEtherType(Ethernet.TYPE_IPv4)
.setPayload(
new IPv4()
.setTtl((byte) 128)
.setDestinationAddress("192.168.1.1")
.setSourceAddress("192.168.1.2")
.setPayload(new UDP()
.setSourcePort((short) 5000)
.setDestinationPort((short) 5001)
.setPayload(new Data(new byte[] {0x01}))));
testPacketSerialized21= testPacket21.serialize();
testPacket13 = new Ethernet()
.setDestinationMACAddress("00:00:00:00:00:03")
.setSourceMACAddress("00:00:00:00:00:01")
.setEtherType(Ethernet.TYPE_IPv4)
.setPayload(
new IPv4()
.setTtl((byte) 128)
.setDestinationAddress("192.168.1.3")
.setSourceAddress("192.168.1.1")
.setPayload(new UDP()
.setSourcePort((short) 5000)
.setDestinationPort((short) 5001)
.setPayload(new Data(new byte[] {0x01}))));
testPacketSerialized13 = testPacket13.serialize();
testPacket31 = new Ethernet()
.setDestinationMACAddress("00:00:00:00:00:01")
.setSourceMACAddress("00:00:00:00:00:03")
.setEtherType(Ethernet.TYPE_IPv4)
.setPayload(
new IPv4()
.setTtl((byte) 128)
.setDestinationAddress("192.168.1.1")
.setSourceAddress("192.168.1.3")
.setPayload(new UDP()
.setSourcePort((short) 5000)
.setDestinationPort((short) 5001)
.setPayload(new Data(new byte[] {0x01}))));
testPacketSerialized31 = testPacket31.serialize();
testPacket14 = new Ethernet()
.setDestinationMACAddress("00:00:00:00:00:04")
.setSourceMACAddress("00:00:00:00:00:01")
.setEtherType(Ethernet.TYPE_IPv4)
.setPayload(
new IPv4()
.setTtl((byte) 128)
.setDestinationAddress("192.168.1.4")
.setSourceAddress("192.168.1.1")
.setPayload(new UDP()
.setSourcePort((short) 5000)
.setDestinationPort((short) 5001)
.setPayload(new Data(new byte[] {0x01}))));
testPacketSerialized14 = testPacket14.serialize();
testARPPacket = new Ethernet()
.setSourceMACAddress("00:00:00:00:00:01")
.setDestinationMACAddress("00:00:00:00:00:04")
.setEtherType(Ethernet.TYPE_ARP)
.setPayload(
new ARP()
.setHardwareType(ARP.HW_TYPE_ETHERNET)
.setProtocolType(ARP.PROTO_TYPE_IP)
.setHardwareAddressLength((byte) 6)
.setProtocolAddressLength((byte) 4)
.setOpCode(ARP.OP_REPLY)
.setSenderHardwareAddress(Ethernet.toMACAddress(
"00:00:00:00:00:01"))
.setSenderProtocolAddress(IPv4.toIPv4AddressBytes(
"192.168.1.1"))
.setTargetHardwareAddress(Ethernet.toMACAddress(
"00:00:00:00:00:04"))
.setTargetProtocolAddress(IPv4.toIPv4AddressBytes(
"192.168.1.4")));
testARPPacketSerialized = testARPPacket.serialize();
// Build src and dest devices
byte[] dataLayerDevice1 = ((Ethernet)testPacket12)
.getSourceMACAddress();
byte[] dataLayerDevice2 = ((Ethernet)testPacket21)
.getSourceMACAddress();
byte[] dataLayerDevice3 = ((Ethernet)testPacket31)
.getSourceMACAddress();
byte[] dataLayerDevice4 =
((Ethernet)testPacket14).getDestinationMACAddress();
int networkSource1 = ((IPv4)((Ethernet)testPacket12).getPayload()).
getSourceAddress();
int networkSource2 = ((IPv4)((Ethernet)testPacket21).getPayload()).
getSourceAddress();
int networkSource3 = ((IPv4)((Ethernet)testPacket31).getPayload()).
getSourceAddress();
int networkSource4 = ((IPv4)((Ethernet)testPacket14).getPayload()).
getDestinationAddress();
expect(topology.getL2DomainId(EasyMock.anyLong()))
.andReturn(1L).anyTimes();
expect(topology.isAttachmentPointPort(EasyMock.anyLong(),
EasyMock.anyShort()))
.andReturn(true).anyTimes();
replay(topology);
currentDate = new Date();
device1 = deviceManager.
learnEntity(Ethernet.toLong(dataLayerDevice1),
null,
networkSource1,
1L, 1, false);
device2 = deviceManager.
learnEntity(Ethernet.toLong(dataLayerDevice2),
null,
networkSource2,
1L, 2, false);
device3 = deviceManager.
learnEntity(Ethernet.toLong(dataLayerDevice3),
null,
networkSource3,
1L, 3, false);
device4 = deviceManager.
learnEntity(Ethernet.toLong(dataLayerDevice4),
null,
networkSource4,
3L, 1, false);
// Mock Packet-in
packetIn12 = ((OFPacketIn) mockControllerProvider.getOFMessageFactory().
getMessage(OFType.PACKET_IN))
.setBufferId(-1)
.setInPort((short) 1)
.setPacketData(testPacketSerialized12)
.setReason(OFPacketInReason.NO_MATCH)
.setTotalLength((short) testPacketSerialized12.length);
packetIn21 = ((OFPacketIn) mockControllerProvider.
getOFMessageFactory().getMessage(OFType.PACKET_IN))
.setBufferId(-1)
.setInPort((short) 2)
.setPacketData(testPacketSerialized21)
.setReason(OFPacketInReason.NO_MATCH)
.setTotalLength((short) testPacketSerialized21.length);
packetIn13 = ((OFPacketIn) mockControllerProvider.
getOFMessageFactory().getMessage(OFType.PACKET_IN))
.setBufferId(-1)
.setInPort((short) 1)
.setPacketData(testPacketSerialized13)
.setReason(OFPacketInReason.NO_MATCH)
.setTotalLength((short) testPacketSerialized13.length);
packetIn31 = ((OFPacketIn) mockControllerProvider.
getOFMessageFactory().getMessage(OFType.PACKET_IN))
.setBufferId(-1)
.setInPort((short) 3)
.setPacketData(testPacketSerialized31)
.setReason(OFPacketInReason.NO_MATCH)
.setTotalLength((short) testPacketSerialized31.length);
packetIn14 = ((OFPacketIn) mockControllerProvider.
getOFMessageFactory().getMessage(OFType.PACKET_IN))
.setBufferId(-1)
.setInPort((short) 1)
.setPacketData(testPacketSerialized14)
.setReason(OFPacketInReason.NO_MATCH)
.setTotalLength((short) testPacketSerialized14.length);
arpPacketIn = ((OFPacketIn) mockControllerProvider.
getOFMessageFactory().getMessage(OFType.PACKET_IN))
.setBufferId(-1)
.setInPort((short) 1)
.setPacketData(testARPPacketSerialized)
.setReason(OFPacketInReason.NO_MATCH)
.setTotalLength((short) testARPPacketSerialized.length);
// Mock Packet-out
packetOut12 =
(OFPacketOut) mockControllerProvider.
getOFMessageFactory().getMessage(OFType.PACKET_OUT);
packetOut12.setBufferId(this.packetIn12.getBufferId())
.setInPort(this.packetIn12.getInPort());
List<OFAction> poactions12 = new ArrayList<OFAction>();
poactions12.add(new OFActionOutput((short)2, (short) 0xffff));
packetOut12.setActions(poactions12)
.setActionsLength((short) OFActionOutput.MINIMUM_LENGTH)
.setPacketData(testPacketSerialized12)
.setLengthU(OFPacketOut.MINIMUM_LENGTH+packetOut12.
getActionsLength()+testPacketSerialized12.length);
packetOut21 =
(OFPacketOut) mockControllerProvider.
getOFMessageFactory().getMessage(OFType.PACKET_OUT);
packetOut21.setBufferId(this.packetIn21.getBufferId())
.setInPort(this.packetIn21.getInPort());
List<OFAction> poactions21 = new ArrayList<OFAction>();
poactions21.add(new OFActionOutput((short)1, (short) 0xffff));
packetOut21.setActions(poactions21)
.setActionsLength((short) OFActionOutput.MINIMUM_LENGTH)
.setPacketData(testPacketSerialized21)
.setLengthU(OFPacketOut.MINIMUM_LENGTH +
packetOut21.getActionsLength() +
testPacketSerialized21.length);
packetOut13 =
(OFPacketOut) mockControllerProvider.
getOFMessageFactory().getMessage(OFType.PACKET_OUT);
packetOut13.setBufferId(this.packetIn13.getBufferId())
.setInPort(this.packetIn13.getInPort());
List<OFAction> poactions13 = new ArrayList<OFAction>();
poactions13.add(new OFActionOutput((short)3, (short) 0xffff));
packetOut13.setActions(poactions13)
.setActionsLength((short) OFActionOutput.MINIMUM_LENGTH)
.setPacketData(testPacketSerialized13)
.setLengthU(OFPacketOut.MINIMUM_LENGTH +
packetOut13.getActionsLength( ) +
testPacketSerialized13.length);
packetOut31 =
(OFPacketOut) mockControllerProvider.getOFMessageFactory().
getMessage(OFType.PACKET_OUT);
packetOut31.setBufferId(this.packetIn31.getBufferId())
.setInPort(this.packetIn31.getInPort());
List<OFAction> poactions31 = new ArrayList<OFAction>();
poactions31.add(new OFActionOutput((short)1, (short) 0xffff));
packetOut31.setActions(poactions31)
.setActionsLength((short) OFActionOutput.MINIMUM_LENGTH)
.setPacketData(testPacketSerialized31)
.setLengthU(OFPacketOut.MINIMUM_LENGTH +
packetOut31.getActionsLength() +
testPacketSerialized31.length);
packetOut14 =
(OFPacketOut) mockControllerProvider.getOFMessageFactory().
getMessage(OFType.PACKET_OUT);
packetOut14.setBufferId(this.packetIn14.getBufferId())
.setInPort(this.packetIn14.getInPort());
List<OFAction> poactions14 = new ArrayList<OFAction>();
poactions14.add(new OFActionOutput((short)3, (short) 0xffff));
packetOut14.setActions(poactions14)
.setActionsLength((short) OFActionOutput.MINIMUM_LENGTH)
.setPacketData(testPacketSerialized14)
.setLengthU(OFPacketOut.MINIMUM_LENGTH +
packetOut14.getActionsLength( ) +
testPacketSerialized14.length);
arpPacketOut =
(OFPacketOut) mockControllerProvider.getOFMessageFactory().
getMessage(OFType.PACKET_OUT);
arpPacketOut.setBufferId(this.arpPacketOut.getBufferId())
.setInPort(this.arpPacketIn.getInPort());
List<OFAction> arppoactions = new ArrayList<OFAction>();
arppoactions.add(new OFActionOutput((short)3, (short) 0xffff));
arpPacketOut.setActions(poactions14)
.setActionsLength((short) OFActionOutput.MINIMUM_LENGTH)
.setPacketData(testARPPacketSerialized)
.setLengthU(OFPacketOut.MINIMUM_LENGTH +
arpPacketOut.getActionsLength( ) +
testARPPacketSerialized.length);
// Mock flow-mod removal messages
flowRemoveMsg12 = ((OFFlowRemoved) mockControllerProvider.
getOFMessageFactory().getMessage(OFType.FLOW_REMOVED));
flowRemoveMsg12.setCookie(2L << 52);
flowRemoveMsg21 = ((OFFlowRemoved) mockControllerProvider.
getOFMessageFactory().getMessage(OFType.FLOW_REMOVED));
flowRemoveMsg21.setCookie(2L << 52);
flowRemoveMsg13 = ((OFFlowRemoved) mockControllerProvider.
getOFMessageFactory().getMessage(OFType.FLOW_REMOVED));
flowRemoveMsg13.setCookie(2L << 52);
flowRemoveMsg31 = ((OFFlowRemoved) mockControllerProvider.
getOFMessageFactory().getMessage(OFType.FLOW_REMOVED));
flowRemoveMsg31.setCookie(2L << 52);
flowRemoveMsg14 = ((OFFlowRemoved) mockControllerProvider.
getOFMessageFactory().getMessage(OFType.FLOW_REMOVED));
flowRemoveMsg14.setCookie(2L << 52);
// Mock decision12
decision12 = createMock(IRoutingDecision.class);
expect(decision12.getSourceDevice()).andReturn(device1).atLeastOnce();
expect(decision12.getSourcePort()).andReturn(
new SwitchPort(1L, (short)1)).atLeastOnce();
ArrayList<IDevice> dstDevices12 = new ArrayList<IDevice>();
dstDevices12.add(device2);
expect(decision12.getDestinationDevices()).andReturn(dstDevices12).
atLeastOnce();
IRoutingDecision.rtStore.put(
cntx12, IRoutingDecision.CONTEXT_DECISION, decision12);
// set decision.getRoutingAction() based on test case
// Set SRC_IFACCES in context
List<VNSInterface> srcIfaces1 = new ArrayList<VNSInterface>();
VNS netVirt1 = new VNS("default");
srcIfaces1.add(new VNSInterface("testSrcIface1", netVirt1, null, null));
INetVirtManagerService.bcStore.put(
cntx12, INetVirtManagerService.CONTEXT_SRC_IFACES, srcIfaces1);
IFlowCacheService.fcStore.put(cntx12,
IFlowCacheService.FLOWCACHE_APP_NAME, "netVirt");
IFlowCacheService.fcStore.put(cntx12,
IFlowCacheService.FLOWCACHE_APP_INSTANCE_NAME, netVirt1.getName());
// Mock decision21
decision21 = createMock(IRoutingDecision.class);
expect(decision21.getSourceDevice()).andReturn(device2).atLeastOnce();
expect(decision21.getSourcePort()).andReturn(
new SwitchPort(1L, (short)2)).atLeastOnce();
ArrayList<IDevice> dstDevices21 = new ArrayList<IDevice>();
dstDevices21.add(device1);
expect(decision21.getDestinationDevices()).andReturn(dstDevices21).
atLeastOnce();
IRoutingDecision.rtStore.put(
cntx21, IRoutingDecision.CONTEXT_DECISION, decision21);
// set decision.getRoutingAction() based on test case
// Set SRC_IFACCES in context
List<VNSInterface> srcIfaces2 = new ArrayList<VNSInterface>();
VNS netVirt2 = new VNS("default");
srcIfaces2.add(new VNSInterface("testSrcIface2", netVirt2, null, null));
INetVirtManagerService.bcStore.put(
cntx21, INetVirtManagerService.CONTEXT_SRC_IFACES, srcIfaces2);
IFlowCacheService.fcStore.put(cntx21,
IFlowCacheService.FLOWCACHE_APP_NAME, "netVirt");
IFlowCacheService.fcStore.put(cntx21,
IFlowCacheService.FLOWCACHE_APP_INSTANCE_NAME, netVirt2.getName());
// Mock decision13
decision13 = createMock(IRoutingDecision.class);
expect(decision13.getSourceDevice()).andReturn(device1).atLeastOnce();
expect(decision13.getSourcePort()).andReturn(
new SwitchPort(1L, (short)1)).atLeastOnce();
ArrayList<IDevice> dstDevices13 = new ArrayList<IDevice>();
dstDevices13.add(device3);
expect(decision13.getDestinationDevices()).
andReturn(dstDevices13).atLeastOnce();
IRoutingDecision.rtStore.put(
cntx13, IRoutingDecision.CONTEXT_DECISION, decision13);
// set decision.getRoutingAction() based on test case
// Set SRC_IFACCES in context
List<VNSInterface> srcIfaces3 = new ArrayList<VNSInterface>();
VNS netVirt3 = new VNS("default");
srcIfaces3.add(new VNSInterface("testSrcIface3", netVirt3, null, null));
INetVirtManagerService.bcStore.put(
cntx13, INetVirtManagerService.CONTEXT_SRC_IFACES, srcIfaces3);
IFlowCacheService.fcStore.put(cntx14,
IFlowCacheService.FLOWCACHE_APP_NAME, "netVirt");
IFlowCacheService.fcStore.put(cntx13,
IFlowCacheService.FLOWCACHE_APP_INSTANCE_NAME, netVirt3.getName());
// Mock decision31
decision31 = createMock(IRoutingDecision.class);
expect(decision31.getSourceDevice()).andReturn(device3).atLeastOnce();
expect(decision31.getSourcePort()).andReturn(
new SwitchPort(1L, (short)3)).atLeastOnce();
ArrayList<IDevice> dstDevices31 = new ArrayList<IDevice>();
dstDevices31.add(device1);
expect(decision31.getDestinationDevices()).
andReturn(dstDevices31).atLeastOnce();
IRoutingDecision.rtStore.put(
cntx31, IRoutingDecision.CONTEXT_DECISION, decision31);
// set decision.getRoutingAction() based on test case
// Set SRC_IFACCES in context
List<VNSInterface> srcIfaces4 = new ArrayList<VNSInterface>();
VNS netVirt4 = new VNS("default");
srcIfaces4.add(new VNSInterface("testSrcIface4", netVirt4, null, null));
INetVirtManagerService.bcStore.put(
cntx31, INetVirtManagerService.CONTEXT_SRC_IFACES, srcIfaces4);
IFlowCacheService.fcStore.put(cntx14,
IFlowCacheService.FLOWCACHE_APP_NAME, "netVirt");
IFlowCacheService.fcStore.put(cntx31,
IFlowCacheService.FLOWCACHE_APP_INSTANCE_NAME, netVirt4.getName());
// Mock decision14
decision14 = createMock(IRoutingDecision.class);
expect(decision14.getSourceDevice()).andReturn(device1).atLeastOnce();
expect(decision14.getSourcePort()).andReturn(
new SwitchPort(1L, (short)1)).atLeastOnce();
ArrayList<IDevice> dstDevices14 = new ArrayList<IDevice>();
dstDevices14.add(device4);
expect(decision14.getDestinationDevices()).
andReturn(dstDevices14).atLeastOnce();
IRoutingDecision.rtStore.put(
cntx14, IRoutingDecision.CONTEXT_DECISION, decision14);
// set decision.getRoutingAction() based on test case
// Set SRC_IFACCES in context
List<VNSInterface> srcIfaces5 = new ArrayList<VNSInterface>();
VNS netVirt5 = new VNS("default");
srcIfaces5.add(new VNSInterface("testSrcIface5", netVirt5, null, null));
INetVirtManagerService.bcStore.put(
cntx14, INetVirtManagerService.CONTEXT_SRC_IFACES, srcIfaces5);
IFlowCacheService.fcStore.put(cntx14,
IFlowCacheService.FLOWCACHE_APP_NAME, "netVirt");
IFlowCacheService.fcStore.put(cntx14,
IFlowCacheService.FLOWCACHE_APP_INSTANCE_NAME, netVirt5.getName());
// Create a statsRequest
ofStatsRequest = new OFStatisticsRequest();
ofStatsRequest.setStatisticType(OFStatisticsType.FLOW);
int requestLength = ofStatsRequest.getLengthU();
OFFlowStatisticsRequest specificReq = new OFFlowStatisticsRequest();
OFMatch match = new OFMatch();
match.setWildcards(FlowCacheObj.WILD_ALL);
specificReq.setMatch(match);
specificReq.setOutPort(OFPort.OFPP_NONE.getValue());
specificReq.setTableId((byte) 0xff);
ofStatsRequest.setStatistics(Collections.singletonList(
(OFStatistics)specificReq));
requestLength += specificReq.getLength();
ofStatsRequest.setLengthU(requestLength);
}
@After
public void tearDown() {
tp.getScheduledExecutor().shutdownNow();
verify(tunnelManager);
}
@Test
public void testFlowCacheFlowAddRemoves() throws Exception {
// Mock decision
expect(decision12.getRoutingAction()).andReturn(
IRoutingDecision.RoutingAction.FORWARD).atLeastOnce();
expect(decision12.getWildcards()).andReturn(null).atLeastOnce();
expect(decision12.getHardTimeout()).
andReturn(ForwardingBase.FLOWMOD_DEFAULT_HARD_TIMEOUT).atLeastOnce();
expect(decision21.getRoutingAction()).andReturn(
IRoutingDecision.RoutingAction.FORWARD).atLeastOnce();
expect(decision21.getWildcards()).andReturn(null).atLeastOnce();
expect(decision21.getHardTimeout()).
andReturn(ForwardingBase.FLOWMOD_DEFAULT_HARD_TIMEOUT).atLeastOnce();
expect(decision13.getRoutingAction()).andReturn(
IRoutingDecision.RoutingAction.FORWARD).atLeastOnce();
expect(decision13.getWildcards()).andReturn(null).atLeastOnce();
expect(decision13.getHardTimeout()).
andReturn(ForwardingBase.FLOWMOD_DEFAULT_HARD_TIMEOUT).atLeastOnce();
expect(decision31.getRoutingAction()).andReturn(
IRoutingDecision.RoutingAction.FORWARD).atLeastOnce();
expect(decision31.getWildcards()).andReturn(null).atLeastOnce();
expect(decision31.getHardTimeout()).
andReturn(ForwardingBase.FLOWMOD_DEFAULT_HARD_TIMEOUT).atLeastOnce();
// Set destination as local and Mock route
Route route = new Route(1L, 1L);
route.getPath().add(new NodePortTuple(1L, (short)1));
route.getPath().add(new NodePortTuple(1L, (short)2));
long cookie12 = forwarding.getHashByMac(((Ethernet) testPacket12).getDestinationMAC().toLong());
expect(routingEngine.getRoute(1L, (short)1, 1L, (short)2, cookie12, true))
.andReturn(route).anyTimes();
route = new Route(1L, 1L);
route.getPath().add(new NodePortTuple(1L, (short)2));
route.getPath().add(new NodePortTuple(1L, (short)1));
long cookie21 = forwarding.getHashByMac(((Ethernet) testPacket21).getDestinationMAC().toLong());
expect(routingEngine.getRoute(1L, (short)2, 1L, (short)1, cookie21, true))
.andReturn(route).anyTimes();
route = new Route(1L, 1L);
route.getPath().add(new NodePortTuple(1L, (short)1));
route.getPath().add(new NodePortTuple(1L, (short)3));
long cookie13 = forwarding.getHashByMac(((Ethernet) testPacket13).getDestinationMAC().toLong());
expect(routingEngine.getRoute(1L, (short)1, 1L, (short)3, cookie13, true))
.andReturn(route).anyTimes();
route = new Route(1L, 1L);
route.getPath().add(new NodePortTuple(1L, (short)3));
route.getPath().add(new NodePortTuple(1L, (short)1));
long cookie31 = forwarding.getHashByMac(((Ethernet) testPacket31).getDestinationMAC().toLong());
expect(routingEngine.getRoute(1L, (short)3, 1L, (short)1, cookie31, true))
.andReturn(route).anyTimes();
// Expected Flow-mods
OFMatch match = new OFMatch();
// Packet 1 to 2 from sw1, inport 1
match.loadFromPacket(testPacketSerialized12, (short) 1);
OFActionOutput action = new OFActionOutput((short)2, (short)0xffff);
List<OFAction> actions = new ArrayList<OFAction>();
actions.add(action);
OFFlowMod fm1 = (OFFlowMod) mockControllerProvider.
getOFMessageFactory().getMessage(OFType.FLOW_MOD);
Long cookie = 2L << 52;
fm1.setIdleTimeout((short)5)
.setMatch(match.clone()
.setWildcards(0x3FFFF0))
.setActions(actions)
.setBufferId(OFPacketOut.BUFFER_ID_NONE)
.setCookie(cookie)
.setFlags((short)1)
.setLengthU(OFFlowMod.MINIMUM_LENGTH+
OFActionOutput.MINIMUM_LENGTH);
// Record expected packet-outs/flow-mods
reset(sw1);
expect(sw1.getId()).andReturn(1L).anyTimes();
expect(sw1.isConnected()).andReturn(true).anyTimes();
sw1.write(fm1, cntx12);
expectLastCall().anyTimes();
sw1.write(packetOut12, cntx12);
expectLastCall().anyTimes();
// Reset mocks, trigger the packet in, and validate results
reset(topology);
expect(topology.getL2DomainId(EasyMock.anyLong()))
.andReturn(1L).anyTimes();
expect(topology.getL2DomainId(EasyMock.anyLong(),
EasyMock.anyBoolean()))
.andReturn(1L).anyTimes();
expect(topology.getIncomingSwitchPort((long)1, (short)2,
(long)1, (short)1, true))
.andReturn(new NodePortTuple((long)1, (short)2)).anyTimes();
expect(topology.isAttachmentPointPort(1L, (short)2))
.andReturn(true).anyTimes();
expect(topology.getIncomingSwitchPort((long)1, (short)1,
(long)1, (short)2, true))
.andReturn(new NodePortTuple((long)1, (short)1)).anyTimes();
expect(topology.isAttachmentPointPort(EasyMock.anyLong(), EasyMock.anyShort()))
.andReturn(true).anyTimes();
expect(topology.isAttachmentPointPort(1L, (short)1, true))
.andReturn(true).anyTimes();
expect(topology.isAttachmentPointPort(1L, (short)2, true))
.andReturn(true).anyTimes();
expect(topology.getOutgoingSwitchPort((long)1, (short)2,
(long)1, (short)1, true))
.andReturn(new NodePortTuple((long)1, (short)1)).atLeastOnce();
expect(topology.getOutgoingSwitchPort((long)1, (short)1,
(long)1, (short)2, true))
.andReturn(new NodePortTuple((long)1, (short)2)).atLeastOnce();
expect(topology.isAllowed(EasyMock.anyLong(), EasyMock.anyShort()))
.andReturn(true).anyTimes();
replay(sw1, routingEngine, decision12, topology);
forwarding.receive(sw1, this.packetIn12, cntx12);
betterFlowCacheMgr.updateFlush();
verify(sw1, routingEngine, decision12);
// Check that the flow was added to flow-cache
assertEquals(1, betterFlowCacheMgr.getBfcCore().getActiveCnt());
assertEquals(1, betterFlowCacheMgr.getBfcCore().getAddCnt());
int preCount = flowReconcileMgr.flowQueryRespHandlerCallCount.get();
// Check that the get API works to get all flows to
// the destination device, device2
String testName = "FCTestDst";
FCQueryObj fcQueryObj = new FCQueryObj(
flowReconcileMgr,
null, // null appName
null, // null vlan
null, // null srcDevice
device2,
testName,
FCQueryEvType.GET,
null);
betterFlowCacheMgr.submitFlowCacheQuery(fcQueryObj);
Date startTime = new Date();
while (flowReconcileMgr.flowQueryRespHandlerCallCount.get() == preCount) {
Date curTime = new Date();
assertTrue((curTime.getTime() - startTime.getTime()) < 1000);
}
assertEquals(preCount+1, flowReconcileMgr.flowQueryRespHandlerCallCount.get());
FlowCacheQueryResp bfcQR = flowReconcileMgr.lastFCQueryResp;
assertNotNull(bfcQR);
assertEquals(FCQueryEvType.GET, bfcQR.queryObj.evType);
assertEquals(testName, bfcQR.queryObj.callerName);
assertEquals(bfcQR.queryObj, fcQueryObj);
assertEquals(false, bfcQR.moreFlag);
assertEquals(1, bfcQR.qrFlowCacheObjList.size());
QRFlowCacheObj qrFcObj = bfcQR.qrFlowCacheObjList.get(0);
assertEquals(1L, qrFcObj.ofmWithSwDpid.getSwitchDataPathId());
assertEquals(1, qrFcObj.ofmWithSwDpid.getOfMatch().getInputPort());
assertEquals(Ethernet.toLong(qrFcObj.ofmWithSwDpid.getOfMatch()
.getDataLayerSource()),
device1.getMACAddress());
assertEquals(Ethernet.toLong(qrFcObj.ofmWithSwDpid.getOfMatch()
.getDataLayerDestination()),
device2.getMACAddress());
assertEquals(FlowCacheObj.FCActionPERMIT, qrFcObj.action);
preCount = flowReconcileMgr.flowQueryRespHandlerCallCount.get();
// Check that the get API works to get all flows to
// the src device, device1
testName = "FCTestSrc";
fcQueryObj = new FCQueryObj(flowReconcileMgr,
null, // null appName
null, // null vlan
device1,
null, // null destDevice
testName,
FCQueryEvType.GET,
null);
betterFlowCacheMgr.submitFlowCacheQuery(fcQueryObj);
startTime = new Date();
while (flowReconcileMgr.flowQueryRespHandlerCallCount.get() == preCount) {
Date curTime = new Date();
assertTrue((curTime.getTime() - startTime.getTime()) < 1000);
}
assertEquals(preCount+1, flowReconcileMgr.flowQueryRespHandlerCallCount.get());
bfcQR = flowReconcileMgr.lastFCQueryResp;
assertEquals(FCQueryEvType.GET, bfcQR.queryObj.evType);
assertEquals(testName, bfcQR.queryObj.callerName);
assertEquals(bfcQR.queryObj, fcQueryObj);
assertEquals(false, bfcQR.moreFlag);
assertEquals(1, bfcQR.qrFlowCacheObjList.size());
qrFcObj = bfcQR.qrFlowCacheObjList.get(0);
assertEquals(1L, qrFcObj.ofmWithSwDpid.getSwitchDataPathId());
assertEquals(1, qrFcObj.ofmWithSwDpid.getOfMatch().getInputPort());
assertEquals(Ethernet.toLong(qrFcObj.ofmWithSwDpid.getOfMatch()
.getDataLayerSource()),
device1.getMACAddress());
assertEquals(Ethernet.toLong(qrFcObj.ofmWithSwDpid.getOfMatch()
.getDataLayerDestination()),
device2.getMACAddress());
assertEquals(FlowCacheObj.FCActionPERMIT, qrFcObj.action);
preCount = flowReconcileMgr.flowQueryRespHandlerCallCount.get();
// Check that the get API works to get flows to
// the dest device, device2, in the correct netVirt
testName = "FCTestDestInNetVirt";
fcQueryObj = new FCQueryObj(flowReconcileMgr,
"default",
null, // null vlan
null, // null srcDevice
device2,
testName,
FCQueryEvType.GET,
null);
betterFlowCacheMgr.submitFlowCacheQuery(fcQueryObj);
startTime = new Date();
while (flowReconcileMgr.flowQueryRespHandlerCallCount.get() == preCount) {
Date curTime = new Date();
assertTrue((curTime.getTime() - startTime.getTime()) < 1000);
}
assertEquals(preCount+1, flowReconcileMgr.flowQueryRespHandlerCallCount.get());
bfcQR = flowReconcileMgr.lastFCQueryResp;
assertEquals(FCQueryEvType.GET, bfcQR.queryObj.evType);
assertEquals(testName, bfcQR.queryObj.callerName);
assertEquals(bfcQR.queryObj, fcQueryObj);
assertEquals(false, bfcQR.moreFlag);
assertEquals(1, bfcQR.qrFlowCacheObjList.size());
qrFcObj = bfcQR.qrFlowCacheObjList.get(0);
assertEquals(1L, qrFcObj.ofmWithSwDpid.getSwitchDataPathId());
assertEquals(1, qrFcObj.ofmWithSwDpid.getOfMatch().getInputPort());
assertEquals(Ethernet.toLong(qrFcObj.ofmWithSwDpid.getOfMatch()
.getDataLayerSource()),
device1.getMACAddress());
assertEquals(Ethernet.toLong(qrFcObj.ofmWithSwDpid.getOfMatch()
.getDataLayerDestination()),
device2.getMACAddress());
assertEquals(FlowCacheObj.FCActionPERMIT, qrFcObj.action);
preCount = flowReconcileMgr.flowQueryRespHandlerCallCount.get();
// Check that the get API works to get flows to
// the dest device, device2, in a wrong netVirt.
// It is expected to get 0 flows
testName = "FCTestDestInNetVirt";
fcQueryObj = new FCQueryObj(flowReconcileMgr,
"netVirt1",
null, // null vlan
null, // null srcDevice
device2,
testName,
FCQueryEvType.GET,
null);
betterFlowCacheMgr.submitFlowCacheQuery(fcQueryObj);
startTime = new Date();
while (flowReconcileMgr.flowQueryRespHandlerCallCount.get() == preCount) {
Date curTime = new Date();
assertTrue((curTime.getTime() - startTime.getTime()) < 1000);
}
assertEquals(preCount+1, flowReconcileMgr.flowQueryRespHandlerCallCount.get());
bfcQR = flowReconcileMgr.lastFCQueryResp;
assertEquals(FCQueryEvType.GET, bfcQR.queryObj.evType);
assertEquals(testName, bfcQR.queryObj.callerName);
assertEquals(bfcQR.queryObj, fcQueryObj);
assertEquals(false, bfcQR.moreFlag);
assertEquals(0, bfcQR.qrFlowCacheObjList.size());
// Inject other packet-ins and check the flow-cache counters
replay(decision21);
forwarding.receive(sw1, this.packetIn21, cntx21);
betterFlowCacheMgr.updateFlush();
verify(decision21);
assertEquals(2, betterFlowCacheMgr.getBfcCore().getActiveCnt());
assertEquals(2, betterFlowCacheMgr.getBfcCore().getAddCnt());
reset(topology);
expect(topology.getL2DomainId(1L)).andReturn(1L).anyTimes();
expect(topology.getL2DomainId(2L)).andReturn(1L).anyTimes();
expect(topology.getL2DomainId(3L)).andReturn(1L).anyTimes();
expect(topology.getL2DomainId(1L, true)).andReturn(1L).anyTimes();
expect(topology.getL2DomainId(2L, true)).andReturn(1L).anyTimes();
expect(topology.getL2DomainId(3L, true)).andReturn(1L).anyTimes();
expect(topology.getOutgoingSwitchPort((long)1, (short)1,
(long)1,(short)3, true))
.andReturn(new NodePortTuple((long)1, (short)3)).anyTimes();
expect(topology.getIncomingSwitchPort((long)1, (short)1,
(long)1, (short)3, true))
.andReturn(new NodePortTuple((long)1, (short)1)).anyTimes();
expect(topology.isAttachmentPointPort(1L, (short)1))
.andReturn(true).anyTimes();
expect(topology.isAttachmentPointPort(1L, (short)3))
.andReturn(true).anyTimes();
expect(topology.isAttachmentPointPort(1L, (short)1, true))
.andReturn(true).anyTimes();
expect(topology.isAttachmentPointPort(1L, (short)3, true))
.andReturn(true).anyTimes();
expect(topology.isAllowed(EasyMock.anyLong(), EasyMock.anyShort()))
.andReturn(true).anyTimes();
replay(decision13, topology);
forwarding.receive(sw1, this.packetIn13, cntx13);
betterFlowCacheMgr.updateFlush();
//verify(decision13);
assertEquals(3, betterFlowCacheMgr.getBfcCore().getActiveCnt());
assertEquals(3, betterFlowCacheMgr.getBfcCore().getAddCnt());
reset(topology);
expect(topology.getL2DomainId(1L)).andReturn(1L).anyTimes();
expect(topology.getL2DomainId(2L)).andReturn(1L).anyTimes();
expect(topology.getL2DomainId(3L)).andReturn(1L).anyTimes();
expect(topology.getL2DomainId(1L, true)).andReturn(1L).anyTimes();
expect(topology.getL2DomainId(2L, true)).andReturn(1L).anyTimes();
expect(topology.getL2DomainId(3L, true)).andReturn(1L).anyTimes();
expect(topology.getOutgoingSwitchPort((long)1, (short)3,
(long)1, (short)1, true))
.andReturn(new NodePortTuple((long)1, (short)1)).anyTimes();
expect(topology.getIncomingSwitchPort((long)1, (short)3,
(long)1, (short)1, true))
.andReturn(new NodePortTuple((long)1, (short)3)).anyTimes();
expect(topology.isAttachmentPointPort(1L, (short)1))
.andReturn(true).anyTimes();
expect(topology.isAttachmentPointPort(1L, (short)3))
.andReturn(true).anyTimes();
expect(topology.isAttachmentPointPort(1L, (short)3, true))
.andReturn(true).anyTimes();
expect(topology.isAllowed(EasyMock.anyLong(), EasyMock.anyShort()))
.andReturn(true).anyTimes();
replay(decision31, topology);
forwarding.receive(sw1, this.packetIn31, cntx31);
betterFlowCacheMgr.updateFlush();
verify(decision31);
assertEquals(4, betterFlowCacheMgr.getBfcCore().getActiveCnt());
assertEquals(4, betterFlowCacheMgr.getBfcCore().getAddCnt());
// Check the public APIs
// All flows in a netVirt
testName = "FCTestDefaultNetVirt";
fcQueryObj = new FCQueryObj(flowReconcileMgr,
"default",
null, // null vlan
null, // null srcDevice
null, // null destDevice
testName,
FCQueryEvType.GET,
null);
betterFlowCacheMgr.submitFlowCacheQuery(fcQueryObj);
startTime = new Date();
FlowCacheQueryResp resp = flowReconcileMgr.lastFCQueryResp;
while (resp == null || ! resp.queryObj.callerName.equals(testName)) {
Date curTime = new Date();
assertTrue((curTime.getTime() - startTime.getTime()) < 5000);
resp = flowReconcileMgr.lastFCQueryResp;
}
assertEquals(FCQueryEvType.GET, resp.queryObj.evType);
assertEquals(false, resp.moreFlag);
assertEquals(4, resp.qrFlowCacheObjList.size());
// All flows in a netVirt in a vlan
testName = "FCTestDefaultNetVirtNoVlan";
fcQueryObj = new FCQueryObj(flowReconcileMgr,
"default",
(short)-1,
null, // null srcDevice
null, // null destDevice
testName,
FCQueryEvType.GET,
null);
betterFlowCacheMgr.submitFlowCacheQuery(fcQueryObj);
startTime = new Date();
resp = flowReconcileMgr.lastFCQueryResp;
while (resp == null || ! resp.queryObj.callerName.equals(testName)) {
Date curTime = new Date();
assertTrue((curTime.getTime() - startTime.getTime()) < 5000);
resp = flowReconcileMgr.lastFCQueryResp;
}
assertEquals(FCQueryEvType.GET, resp.queryObj.evType);
assertEquals(testName, resp.queryObj.callerName);
assertEquals(false, resp.moreFlag);
assertEquals(4, resp.qrFlowCacheObjList.size());
// All flows destined to a device
testName = "FCTestAllFlowsToDestinationDevice";
fcQueryObj = new FCQueryObj(flowReconcileMgr,
null, // null appName
null, // null vlan
device1,
null, // null destDevice
testName,
FCQueryEvType.GET,
null);
betterFlowCacheMgr.submitFlowCacheQuery(fcQueryObj);
startTime = new Date();
resp = flowReconcileMgr.lastFCQueryResp;
while (resp == null || ! resp.queryObj.callerName.equals(testName)) {
Date curTime = new Date();
assertTrue((curTime.getTime() - startTime.getTime()) < 5000);
resp = flowReconcileMgr.lastFCQueryResp;
}
assertEquals(FCQueryEvType.GET, resp.queryObj.evType);
assertEquals(testName, resp.queryObj.callerName);
assertEquals(false, resp.moreFlag);
// Two flows: 2--> 1 and 3 --> 1
assertEquals(2, resp.qrFlowCacheObjList.size());
// All flows destined to a device by the correct netVirt
testName = "FCTestAllFlowsToDestinationDeviceInNetVirt";
fcQueryObj = new FCQueryObj(flowReconcileMgr,
"default",
null, // null vlan
device1,
null, // null destDevice
testName,
FCQueryEvType.GET,
null);
betterFlowCacheMgr.submitFlowCacheQuery(fcQueryObj);
startTime = new Date();
resp = flowReconcileMgr.lastFCQueryResp;
while (resp == null || ! resp.queryObj.callerName.equals(testName)) {
Date curTime = new Date();
assertTrue((curTime.getTime() - startTime.getTime()) < 5000);
resp = flowReconcileMgr.lastFCQueryResp;
}
assertEquals(FCQueryEvType.GET, resp.queryObj.evType);
assertEquals(testName, resp.queryObj.callerName);
assertEquals(false, resp.moreFlag);
// Two flows: 2--> 1 and 3 --> 1
assertEquals(2, resp.qrFlowCacheObjList.size());
// All flows destined to a device by wrong netVirt
testName = "FCTestAllFlowsToDestinationDeviceInWrongNetVirt";
fcQueryObj = new FCQueryObj(flowReconcileMgr,
"netVirt10",
null, // null vlan
device1,
null, // null destDevice
testName,
FCQueryEvType.GET,
null);
betterFlowCacheMgr.submitFlowCacheQuery(fcQueryObj);
startTime = new Date();
resp = flowReconcileMgr.lastFCQueryResp;
while (resp == null || ! resp.queryObj.callerName.equals(testName)) {
Date curTime = new Date();
assertTrue((curTime.getTime() - startTime.getTime()) < 5000);
resp = flowReconcileMgr.lastFCQueryResp;
}
assertEquals(FCQueryEvType.GET, resp.queryObj.evType);
assertEquals(testName, resp.queryObj.callerName);
assertEquals(false, resp.moreFlag);
assertEquals(0, resp.qrFlowCacheObjList.size());
// All flows from a source device
testName = "FCTestAllFlowsFromSourceDevice";
fcQueryObj = new FCQueryObj(flowReconcileMgr,
null, // null appName
null, // null vlan
device1,
null, // null destDevice
testName,
FCQueryEvType.GET,
null);
betterFlowCacheMgr.submitFlowCacheQuery(fcQueryObj);
startTime = new Date();
resp = flowReconcileMgr.lastFCQueryResp;
while (resp == null || ! resp.queryObj.callerName.equals(testName)) {
Date curTime = new Date();
assertTrue((curTime.getTime() - startTime.getTime()) < 5000);
resp = flowReconcileMgr.lastFCQueryResp;
}
assertEquals(FCQueryEvType.GET, resp.queryObj.evType);
assertEquals(testName, resp.queryObj.callerName);
assertEquals(false, resp.moreFlag);
assertEquals(2, resp.qrFlowCacheObjList.size());
// All flows to a device from a source
testName = "FCTestAllFlowBetweenSourceDestination";
fcQueryObj = new FCQueryObj(flowReconcileMgr,
null, // null appName
null, // null vlan
device1,
device2,
testName,
FCQueryEvType.GET,
null);
betterFlowCacheMgr.submitFlowCacheQuery(fcQueryObj);
startTime = new Date();
resp = flowReconcileMgr.lastFCQueryResp;
while (resp == null || ! resp.queryObj.callerName.equals(testName)) {
Date curTime = new Date();
assertTrue((curTime.getTime() - startTime.getTime()) < 5000);
resp = flowReconcileMgr.lastFCQueryResp;
}
assertEquals(FCQueryEvType.GET, resp.queryObj.evType);
assertEquals(testName, resp.queryObj.callerName);
assertEquals(false, resp.moreFlag);
assertEquals(1, resp.qrFlowCacheObjList.size());
OFMatch match12 = new OFMatch();
match12.loadFromPacket(testPacketSerialized12, (short) 1);
flowRemoveMsg12.setMatch(match12);
flowRemoveMsg12.getMatch().setWildcards(VirtualRouting.DEFAULT_HINT);
flowRemoveMsg12.setPriority(forwarding.getAccessPriority());
OFMatch match13 = new OFMatch();
match13.loadFromPacket(testPacketSerialized13, (short) 1);
flowRemoveMsg13.setMatch(match13);
flowRemoveMsg13.getMatch().setWildcards(VirtualRouting.DEFAULT_HINT);
flowRemoveMsg13.setPriority(forwarding.getAccessPriority());
OFMatch match21 = new OFMatch();
match21.loadFromPacket(testPacketSerialized21, (short) 2);
flowRemoveMsg21.setMatch(match21);
flowRemoveMsg21.getMatch().setWildcards(VirtualRouting.DEFAULT_HINT);
flowRemoveMsg21.setPriority(forwarding.getAccessPriority());
OFMatch match31 = new OFMatch();
match31.loadFromPacket(testPacketSerialized31, (short) 3);
flowRemoveMsg31.setMatch(match31);
flowRemoveMsg31.getMatch().setWildcards(VirtualRouting.DEFAULT_HINT);
flowRemoveMsg31.setPriority(forwarding.getAccessPriority());
// Inject flow removal message from device 1 to 2
betterFlowCacheMgr.receive(sw1, flowRemoveMsg12, cntx12);
betterFlowCacheMgr.updateFlush();
// Check that the message was removed
assertEquals(3, betterFlowCacheMgr.getBfcCore().getActiveCnt());
assertEquals(1, betterFlowCacheMgr.getBfcCore().getDeactivatedCnt());
assertEquals(1, betterFlowCacheMgr.getBfcCore().getInactiveCnt());
assertEquals(1, betterFlowCacheMgr.getBfcCore().getCacheHitCnt());
// Inject flow removal message from device 1 to 3
betterFlowCacheMgr.receive(sw1, flowRemoveMsg13, cntx13);
betterFlowCacheMgr.updateFlush();
// Check that the message was removed
assertEquals(2, betterFlowCacheMgr.getBfcCore().getActiveCnt());
assertEquals(2, betterFlowCacheMgr.getBfcCore().getDeactivatedCnt());
assertEquals(2, betterFlowCacheMgr.getBfcCore().getInactiveCnt());
assertEquals(2, betterFlowCacheMgr.getBfcCore().getCacheHitCnt());
// Inject flow removal message from device 2 to 1
betterFlowCacheMgr.receive(sw1, flowRemoveMsg21, cntx21);
betterFlowCacheMgr.updateFlush();
// Check that the message was removed
assertEquals(1, betterFlowCacheMgr.getBfcCore().getActiveCnt());
assertEquals(3, betterFlowCacheMgr.getBfcCore().getDeactivatedCnt());
assertEquals(3, betterFlowCacheMgr.getBfcCore().getInactiveCnt());
assertEquals(3, betterFlowCacheMgr.getBfcCore().getCacheHitCnt());
// Inject the same flow removal message from device 2 to 1
// and check that the counters doesn't change
betterFlowCacheMgr.receive(sw1, flowRemoveMsg21, cntx21);
betterFlowCacheMgr.updateFlush();
// Check that the message was removed
assertEquals(1, betterFlowCacheMgr.getBfcCore().getActiveCnt());
assertEquals(3, betterFlowCacheMgr.getBfcCore().getDeactivatedCnt());
assertEquals(3, betterFlowCacheMgr.getBfcCore().getInactiveCnt());
assertEquals(3, betterFlowCacheMgr.getBfcCore().getCacheHitCnt());
// Inject flow removal message from device 3 to 1
betterFlowCacheMgr.receive(sw1, flowRemoveMsg31, cntx31);
betterFlowCacheMgr.updateFlush();
// Check that the message was removed
assertEquals(0, betterFlowCacheMgr.getBfcCore().getActiveCnt());
assertEquals(4, betterFlowCacheMgr.getBfcCore().getDeactivatedCnt());
assertEquals(4, betterFlowCacheMgr.getBfcCore().getInactiveCnt());
assertEquals(4, betterFlowCacheMgr.getBfcCore().getCacheHitCnt());
// Inject a packet-in and check that a deactivated flow was activated
reset(topology);
expect(topology.getL2DomainId(1L)).andReturn(1L).anyTimes();
expect(topology.getL2DomainId(2L)).andReturn(1L).anyTimes();
expect(topology.getL2DomainId(3L)).andReturn(1L).anyTimes();
expect(topology.getL2DomainId(1L, true)).andReturn(1L).anyTimes();
expect(topology.getL2DomainId(2L, true)).andReturn(1L).anyTimes();
expect(topology.getL2DomainId(3L, true)).andReturn(1L).anyTimes();
expect(topology.getOutgoingSwitchPort((long)1, (short)1,
(long)1, (short)3, true))
.andReturn(new NodePortTuple((long)1, (short)3)).anyTimes();
expect(topology.getIncomingSwitchPort((long)1, (short)1,
(long)1, (short)3, true))
.andReturn(new NodePortTuple((long)1, (short)1)).anyTimes();
expect(topology.isAttachmentPointPort(1L, (short)1))
.andReturn(true).anyTimes();
expect(topology.isAttachmentPointPort(1L, (short)3))
.andReturn(true).anyTimes();
expect(topology.isAttachmentPointPort(1L, (short)1, true))
.andReturn(true).anyTimes();
expect(topology.isAllowed(EasyMock.anyLong(), EasyMock.anyShort()))
.andReturn(true).anyTimes();
replay(topology);
forwarding.receive(sw1, this.packetIn13, cntx13);
betterFlowCacheMgr.updateFlush();
verify(decision13);
assertEquals(1, betterFlowCacheMgr.getBfcCore().getActiveCnt());
assertEquals(4, betterFlowCacheMgr.getBfcCore().getDeactivatedCnt());
assertEquals(3, betterFlowCacheMgr.getBfcCore().getInactiveCnt());
assertEquals(1, betterFlowCacheMgr.getBfcCore().getActivatedCnt());
assertEquals(5, betterFlowCacheMgr.getBfcCore().getCacheHitCnt());
}
/**
* Test ARP flowmod is skipped by the flow Cache
*/
@Test
public void testSkipARPFlowAdd() throws Exception {
reset(sw1, sw3);
expect(sw1.getId()).andReturn(1L).anyTimes();
expect(sw1.isConnected()).andReturn(true).anyTimes();
expect(sw3.getId()).andReturn(3L).anyTimes();
expect(sw3.isConnected()).andReturn(true).anyTimes();
// Mock decision
expect(decision14.getRoutingAction()).andReturn(
IRoutingDecision.RoutingAction.FORWARD).atLeastOnce();
expect(decision14.getWildcards()).andReturn(null).atLeastOnce();
expect(decision14.getHardTimeout()).
andReturn(ForwardingBase.FLOWMOD_DEFAULT_HARD_TIMEOUT).atLeastOnce();
// Set destination as local and Mock route
Route route = new Route(1L, 3L);
route.getPath().add(new NodePortTuple(1L, (short)1));
route.getPath().add(new NodePortTuple(1L, (short)2));
route.getPath().add(new NodePortTuple(3L, (short)2));
route.getPath().add(new NodePortTuple(3L, (short)1));
long cookie14 = forwarding.getHashByMac(((Ethernet) testPacket14).getDestinationMAC().toLong());
expect(routingEngine.getRoute(1L, (short)1, 3L, (short)1, cookie14, true))
.andReturn(route).anyTimes();
// Record expected packet-outs/flow-mods
sw1.write((OFMessage)EasyMock.anyObject(),
(ListenerContext)EasyMock.anyObject());
expectLastCall().times(2);
sw3.write((OFMessage)EasyMock.anyObject(),
(ListenerContext)EasyMock.anyObject());
expectLastCall().times(1);
// Reset mocks, trigger the packet in, and validate results
reset(topology);
expect(topology.getL2DomainId(EasyMock.anyLong()))
.andReturn(1L).anyTimes();
expect(topology.getL2DomainId(EasyMock.anyLong(),
EasyMock.anyBoolean()))
.andReturn(1L).anyTimes();
expect(topology.getIncomingSwitchPort(1L, (short)1,
3L, (short)1, true))
.andReturn(new NodePortTuple(1L, (short)1)).anyTimes();
expect(topology.isAttachmentPointPort(1L, (short)1))
.andReturn(true).anyTimes();
expect(topology.isAttachmentPointPort(3L, (short)1))
.andReturn(true).anyTimes();
expect(topology.isAttachmentPointPort(1L, (short)1, true))
.andReturn(true).anyTimes();
expect(topology.getOutgoingSwitchPort(1L, (short)1,
3L, (short)1, true))
.andReturn(new NodePortTuple(3L, (short)1)).atLeastOnce();
expect(topology.isAllowed(EasyMock.anyLong(), EasyMock.anyShort()))
.andReturn(true).anyTimes();
replay(sw1, sw3, routingEngine, decision14, topology);
forwarding.receive(sw1, this.arpPacketIn, cntx14);
verify(sw1, sw3, routingEngine, decision14, topology);
// Check that the flow was added to flow-cache
assertEquals(0, betterFlowCacheMgr.getBfcCore().getActiveCnt());
assertEquals(0, betterFlowCacheMgr.getBfcCore().getAddCnt());
}
/**
* Test ARP flows are skipped when handling switch's statsReply
*/
@Test
public void testSkipARPStatsReply() throws Exception{
// Mock decision
expect(decision12.getRoutingAction()).andReturn(
IRoutingDecision.RoutingAction.FORWARD).atLeastOnce();
expect(decision12.getWildcards()).andReturn(null).atLeastOnce();
expect(decision12.getHardTimeout()).
andReturn(ForwardingBase.FLOWMOD_DEFAULT_HARD_TIMEOUT).atLeastOnce();
expect(decision21.getRoutingAction()).andReturn(
IRoutingDecision.RoutingAction.FORWARD).atLeastOnce();
expect(decision21.getWildcards()).andReturn(null).atLeastOnce();
expect(decision21.getHardTimeout()).
andReturn(ForwardingBase.FLOWMOD_DEFAULT_HARD_TIMEOUT).atLeastOnce();
expect(decision13.getRoutingAction()).andReturn(
IRoutingDecision.RoutingAction.FORWARD).atLeastOnce();
expect(decision13.getWildcards()).andReturn(null).atLeastOnce();
expect(decision13.getHardTimeout()).
andReturn(ForwardingBase.FLOWMOD_DEFAULT_HARD_TIMEOUT).atLeastOnce();
expect(decision31.getRoutingAction()).andReturn(
IRoutingDecision.RoutingAction.FORWARD).atLeastOnce();
expect(decision31.getWildcards()).andReturn(null).atLeastOnce();
expect(decision31.getHardTimeout()).
andReturn(ForwardingBase.FLOWMOD_DEFAULT_HARD_TIMEOUT).atLeastOnce();
// Set destination as local and Mock route
Route route = new Route(1L, 1L);
route.getPath().add(new NodePortTuple(1L, (short)1));
route.getPath().add(new NodePortTuple(1L, (short)2));
long cookie12 = forwarding.getHashByMac(((Ethernet) testPacket12).getDestinationMAC().toLong());
expect(routingEngine.getRoute(1L, (short)1, 1L, (short)2, cookie12, true))
.andReturn(route).anyTimes();
route = new Route(1L, 1L);
route.getPath().add(new NodePortTuple(1L, (short)2));
route.getPath().add(new NodePortTuple(1L, (short)1));
long cookie21 = forwarding.getHashByMac(((Ethernet) testPacket21).getDestinationMAC().toLong());
expect(routingEngine.getRoute(1L, (short)2, 1L, (short)1, cookie21, true))
.andReturn(route).anyTimes();
route = new Route(1L, 1L);
route.getPath().add(new NodePortTuple(1L, (short)1));
route.getPath().add(new NodePortTuple(1L, (short)3));
long cookie13 = forwarding.getHashByMac(((Ethernet) testPacket13).getDestinationMAC().toLong());
expect(routingEngine.getRoute(1L, (short)1, 1L, (short)3, cookie13, true))
.andReturn(route).anyTimes();
route = new Route(1L, 1L);
route.getPath().add(new NodePortTuple(1L, (short)3));
route.getPath().add(new NodePortTuple(1L, (short)1));
long cookie31 = forwarding.getHashByMac(((Ethernet) testPacket31).getDestinationMAC().toLong());
expect(routingEngine.getRoute(1L, (short)3, 1L, (short)1, cookie31, true))
.andReturn(route).anyTimes();
// Expected Flow-mods
OFMatch match = new OFMatch();
// Packet 1 to 2 from sw1, inport 1
match.loadFromPacket(testPacketSerialized12, (short) 1);
OFActionOutput action = new OFActionOutput((short)2, (short)0xffff);
List<OFAction> actions = new ArrayList<OFAction>();
actions.add(action);
OFFlowMod fm1 = (OFFlowMod) mockControllerProvider.
getOFMessageFactory().getMessage(OFType.FLOW_MOD);
Long cookie = 2L << 52;
fm1.setIdleTimeout((short)5)
.setMatch(match.clone()
.setWildcards(0x3FFFF0))
.setActions(actions)
.setBufferId(OFPacketOut.BUFFER_ID_NONE)
.setCookie(cookie)
.setFlags((short)1)
.setLengthU(OFFlowMod.MINIMUM_LENGTH+
OFActionOutput.MINIMUM_LENGTH);
// Record expected packet-outs/flow-mods
reset(sw1);
expect(sw1.getId()).andReturn(1L).anyTimes();
expect(sw1.isConnected()).andReturn(true).anyTimes();
sw1.write((OFMessage)EasyMock.anyObject(),
(ListenerContext)EasyMock.anyObject());
expectLastCall().times(2);
// Reset mocks, trigger the packet in, and validate results
reset(topology);
expect(topology.getL2DomainId(EasyMock.anyLong()))
.andReturn(1L).anyTimes();
expect(topology.getL2DomainId(EasyMock.anyLong(),
EasyMock.anyBoolean()))
.andReturn(1L).anyTimes();
expect(topology.getIncomingSwitchPort((long)1, (short)2,
(long)1, (short)1, true))
.andReturn(new NodePortTuple((long)1, (short)2)).anyTimes();
expect(topology.isAttachmentPointPort(1L, (short)2))
.andReturn(true).anyTimes();
expect(topology.getIncomingSwitchPort((long)1, (short)1,
(long)1, (short)2, true))
.andReturn(new NodePortTuple((long)1, (short)1)).anyTimes();
expect(topology.isAttachmentPointPort(1L, (short)1))
.andReturn(true).anyTimes();
expect(topology.isAttachmentPointPort(1L, (short)1, true))
.andReturn(true).anyTimes();
expect(topology.getOutgoingSwitchPort((long)1, (short)2,
(long)1, (short)1, true))
.andReturn(new NodePortTuple((long)1, (short)1)).atLeastOnce();
expect(topology.getOutgoingSwitchPort((long)1, (short)1,
(long)1, (short)2, true))
.andReturn(new NodePortTuple((long)1, (short)2)).atLeastOnce();
expect(topology.isAllowed(EasyMock.anyLong(), EasyMock.anyShort()))
.andReturn(true).anyTimes();
replay(sw1, routingEngine, decision12, topology);
forwarding.receive(sw1, this.packetIn12, cntx12);
betterFlowCacheMgr.updateFlush();
verify(sw1, routingEngine, decision12);
// Check that the flow was added to flow-cache
assertEquals(1, betterFlowCacheMgr.getBfcCore().getActiveCnt());
assertEquals(1, betterFlowCacheMgr.getBfcCore().getAddCnt());
OFStatisticsReply msg = new OFStatisticsReply();
msg.setType(OFType.STATS_REPLY);
List<OFStatistics> statsList = new ArrayList<OFStatistics>();
msg.setStatistics(statsList);
msg.setXid(0);
// First Non ARP flow
OFFlowStatisticsReply oneStats = new OFFlowStatisticsReply();
OFMatch matchResp = new OFMatch();
matchResp.setDataLayerSource("00:00:00:00:00:01");
matchResp.setDataLayerDestination("00:00:00:00:00:02");
matchResp.setWildcards(FlowCacheObj.WILD_MATCH_INP_VLAN_DLADRS);
oneStats.setCookie(
AppCookie.makeCookie(Forwarding.FORWARDING_APP_ID, 0));
oneStats.setMatch(matchResp);
oneStats.setActions(actions);
statsList.add(oneStats);
// Second, ARP flow mod
oneStats = new OFFlowStatisticsReply();
matchResp = new OFMatch();
matchResp.setDataLayerSource("00:00:00:00:00:01");
matchResp.setDataLayerDestination("00:00:00:00:00:02");
matchResp.setWildcards(FlowCacheObj.WILD_MATCH_INP_VLAN_DLADRS);
matchResp.setDataLayerType(Ethernet.TYPE_ARP);
oneStats.setCookie(
AppCookie.makeCookie(Forwarding.FORWARDING_APP_ID, 0));
oneStats.setMatch(matchResp);
oneStats.setActions(actions);
statsList.add(oneStats);
reset(sw1);
replay(sw1);
betterFlowCacheMgr.receive(sw1, msg, null);
betterFlowCacheMgr.updateFlush();
verify(sw1);
// Check that the flow was added to flow-cache
assertEquals(2, betterFlowCacheMgr.getBfcCore().getActiveCnt());
assertEquals(2, betterFlowCacheMgr.getBfcCore().getAddCnt());
}
/**
* Test that explain packet is not stored in flow cache
* @throws Exception
*/
@Test
public void testExplainPktNotInFlowCache() throws Exception {
deviceManager.startUp(null);
// Set destination as sw2 and Mock route
IDevice device3alt = deviceManager.
learnEntity(Ethernet.toLong(((Ethernet)testPacket31)
.getSourceMACAddress()),
null,
((IPv4)((Ethernet)testPacket31).getPayload()).
getSourceAddress(),
2L, 3, false);
Route route = new Route(1L, 2L);
route.setPath(new ArrayList<NodePortTuple>());
route.getPath().add(new NodePortTuple(1L, (short)1));
route.getPath().add(new NodePortTuple(1L, (short)2));
route.getPath().add(new NodePortTuple(2L, (short)1));
route.getPath().add(new NodePortTuple(2L, (short)3));
long cookie13 = forwarding.getHashByMac(((Ethernet) testPacket31).getSourceMAC().toLong());
expect(routingEngine.getRoute(1L, (short)1, 2L, (short)3, cookie13, true))
.andReturn(route).atLeastOnce();
// Set up the context to indicate that it is an explain packet
NetVirtExplainPacket.ExplainStore.put(cntx13,
NetVirtExplainPacket.KEY_EXPLAIN_PKT,
NetVirtExplainPacket.VAL_EXPLAIN_PKT);
NetVirtExplainPacket.ExplainPktRoute epr =
new NetVirtExplainPacket.ExplainPktRoute();
NetVirtExplainPacket.ExplainRouteStore.put(cntx13,
NetVirtExplainPacket.KEY_EXPLAIN_PKT_ROUTE, epr);
// Set up Mock decision
decision13 = createMock(IRoutingDecision.class);
expect(decision13.getSourceDevice()).andReturn(device1).atLeastOnce();
expect(decision13.getSourcePort()).andReturn(
new SwitchPort(1L, (short)1)).atLeastOnce();
ArrayList<IDevice> dstDevices = new ArrayList<IDevice>();
dstDevices.add(device3alt);
expect(decision13.getDestinationDevices()).
andReturn(dstDevices).atLeastOnce();
IRoutingDecision.rtStore.put(
cntx13, IRoutingDecision.CONTEXT_DECISION, decision13);
expect(decision13.getRoutingAction()).andReturn(
IRoutingDecision.RoutingAction.FORWARD).atLeastOnce();
// Start the replay
reset(topology);
expect(topology.getL2DomainId(EasyMock.anyLong()))
.andReturn(1L).anyTimes();
expect(topology.getL2DomainId(EasyMock.anyLong(),
EasyMock.anyBoolean()))
.andReturn(1L).anyTimes();
expect(topology.getOutgoingSwitchPort((long)1, (short)1,
(long)2, (short)3, true))
.andReturn(new NodePortTuple((long)2, (short)3)).anyTimes();
expect(topology.getIncomingSwitchPort((long)1, (short)1,
(long)2, (short)3, true))
.andReturn(new NodePortTuple((long)1, (short)1)).anyTimes();
expect(topology.isAttachmentPointPort(1L, (short)1))
.andReturn(true).anyTimes();
expect(topology.isAttachmentPointPort(1L, (short)1, true))
.andReturn(true).anyTimes();
expect(topology.isAttachmentPointPort(2L, (short)3))
.andReturn(true).anyTimes();
expect(topology.isAllowed(EasyMock.anyLong(), EasyMock.anyShort()))
.andReturn(true).anyTimes();
reset(sw1, sw2, sw3);
expect(sw1.getId()).andReturn(1L).anyTimes();
expect(sw1.isConnected()).andReturn(true).anyTimes();
expect(sw2.getId()).andReturn(3L).anyTimes();
expect(sw2.isConnected()).andReturn(true).anyTimes();
expect(sw3.getId()).andReturn(3L).anyTimes();
expect(sw3.isConnected()).andReturn(true).anyTimes();
replay(sw1, sw2, sw3, routingEngine, decision13, topology);
// Call the action function
forwarding.receive(sw1, this.packetIn13, cntx13);
// Verify that all the replays that were setup did happen
verify(sw1, sw2, sw3, routingEngine, decision13, topology);
// Check that flow cache is empty, i.e. the test packet-in was not
// added to flow-cache
assertEquals(0, betterFlowCacheMgr.getBfcCore().getAddCnt());
}
/* Test periodic scanning of switch flow tables:
*
*/
@SuppressWarnings("deprecation")
@Test
public void testFlowCachePeriodicSwitchFlowTableScan() throws Exception {
betterFlowCacheMgr.fqTask.setEnableFlowQueryTask(true);
/* Periodic scan interval has already been set to low value
* in the setup() */
/* Add a flow to flow cache */
OFMatch ofm = new OFMatch();
ofm.setDataLayerSource(Ethernet.toByteArray(device1.getMACAddress()));
ofm.setDataLayerDestination(Ethernet.
toByteArray(device2.getMACAddress()));
ofm.setDataLayerVirtualLan((short)-1);
OFMatchWithSwDpid ofmWithSwDpid = new OFMatchWithSwDpid(ofm, 1L);
betterFlowCacheMgr.addFlow("testNetVirt1", ofmWithSwDpid, 2L, 1L, (short)1,
(short)0, FlowCacheObj.FCActionPERMIT);
/* Check that its scan count is zero */
FlowCacheObj fco =
betterFlowCacheMgr.getAllFlowsByApplInstVlanSrcDestDevicesInternal(
"testNetVirt1", (short)-1, device1.getMACAddress(),
device2.getMACAddress());
assertTrue(fco != null);
assertEquals(0, fco.fce.scanCnt);
Capture<OFStatisticsRequest> request =
new Capture<OFStatisticsRequest>(CaptureType.ALL);
Capture<Integer> xid = new Capture<Integer>(CaptureType.ALL);
Capture<IOFMessageListener> iofml =
new Capture<IOFMessageListener>(CaptureType.ALL);
OFStatisticsRequest req = new OFStatisticsRequest();
req.setStatisticType(OFStatisticsType.FLOW);
int requestLength = req.getLengthU();
OFFlowStatisticsRequest specificReq = new OFFlowStatisticsRequest();
OFMatch match = new OFMatch();
match.setWildcards(FlowCacheObj.WILD_ALL);
specificReq.setMatch(match);
specificReq.setOutPort(OFPort.OFPP_NONE.getValue());
specificReq.setTableId((byte) 0xff);
req.setStatistics(Collections.singletonList((OFStatistics)specificReq));
requestLength += specificReq.getLength();
req.setLengthU(requestLength);
sw1.sendStatsQuery(capture(request), capture(xid), capture(iofml));
expectLastCall().atLeastOnce();
sw2.sendStatsQuery(capture(request), capture(xid), capture(iofml));
expectLastCall().atLeastOnce();
sw3.sendStatsQuery(capture(request), capture(xid), capture(iofml));
expectLastCall().atLeastOnce();
replay(sw1, sw2, sw3);
/* Sleep for to allow for the switch flow table scans to kick in */
Thread.sleep((long)(betterFlowCacheMgr.periodicSwScanIntervalMsec*2.5));
verify(sw1, sw2, sw3);
assertTrue(iofml.getValues().size() >= 3);
assertEquals(betterFlowCacheMgr, iofml.getValues().get(1));
assertEquals(betterFlowCacheMgr, iofml.getValues().get(2));
assertEquals(betterFlowCacheMgr, iofml.getValues().get(3));
assertTrue(request.getValues().size() >= 3);
assertEquals(req, request.getValues().get(1));
assertEquals(req, request.getValues().get(2));
assertEquals(req, request.getValues().get(3));
/* Confirm that the scan count of the entry in flow cache was
* incremented as we didn't inject any response from the switches.
*/
assertTrue(2 <= fco.fce.scanCnt);
}
/* When a switch disconnects from the controller all the flows in the
* flow cache with the disconnected switch as the source switch should
* be removed.
*/
@Test
public void testFlowCacheSwitchDisconnect() throws Exception {
betterFlowCacheMgr.fqTask.setEnableFlowQueryTask(false);
// Mock decision
expect(decision14.getRoutingAction()).andReturn(
IRoutingDecision.RoutingAction.FORWARD).atLeastOnce();
expect(decision14.getWildcards()).andReturn(null).atLeastOnce();
expect(decision14.getHardTimeout()).
andReturn(ForwardingBase.FLOWMOD_DEFAULT_HARD_TIMEOUT).atLeastOnce();
// Set destination as on sw3 and Mock route
Route route = new Route(1L, 3L);
route.setPath(new ArrayList<NodePortTuple>());
/* Route: device1--[P1SW1P5]--[P5SW2P7]--[P7SW3P1]--device4 */
route.getPath().add(new NodePortTuple(1L, (short)1));
route.getPath().add(new NodePortTuple(1L, (short)7));
route.getPath().add(new NodePortTuple(2L, (short)7));
route.getPath().add(new NodePortTuple(2L, (short)5));
route.getPath().add(new NodePortTuple(3L, (short)5));
route.getPath().add(new NodePortTuple(3L, (short)1));
long cookie14 = forwarding.getHashByMac(((Ethernet) testPacket14).getDestinationMAC().toLong());
expect(routingEngine.getRoute(1L, (short)1, 3L, (short)1, cookie14, true))
.andReturn(route).atLeastOnce();
// Expected Flow-mods
OFMatch match = new OFMatch();
// Packet 1 to 4 from sw1, input port 1
match.loadFromPacket(testPacketSerialized14, (short) 1);
OFActionOutput action = new OFActionOutput((short)7, (short)0);
List<OFAction> actions = new ArrayList<OFAction>();
actions.add(action);
OFFlowMod fm1 = (OFFlowMod) mockControllerProvider.
getOFMessageFactory().getMessage(OFType.FLOW_MOD);
Long cookie = 2L << 52;
fm1.setIdleTimeout((short)5)
.setMatch(match.clone()
.setWildcards(0x3FFFF0))
.setActions(actions)
.setBufferId(OFPacketOut.BUFFER_ID_NONE)
.setCookie(cookie)
.setFlags((short)1)
.setLengthU(OFFlowMod.MINIMUM_LENGTH+
OFActionOutput.MINIMUM_LENGTH);
// Record expected packet-outs/flow-mods
sw1.write(fm1, cntx14);
sw1.write(packetOut14, cntx14);
// Reset mocks, trigger the packet in, and validate results
reset(topology);
expect(topology.getL2DomainId(EasyMock.anyLong()))
.andReturn(1L).anyTimes();
expect(topology.getL2DomainId(EasyMock.anyLong(),
EasyMock.anyBoolean()))
.andReturn(1L).anyTimes();
expect(topology.getOutgoingSwitchPort((long)1, (short)1,
(long)3, (short)1, true))
.andReturn(new NodePortTuple((long)3, (short)1)).anyTimes();
expect(topology.getIncomingSwitchPort((long)1, (short)1,
(long)3, (short)1, true))
.andReturn(new NodePortTuple((long)1, (short)1)).anyTimes();
expect(topology.isAttachmentPointPort(1L, (short)1))
.andReturn(true).anyTimes();
expect(topology.isAttachmentPointPort(3L, (short)1))
.andReturn(true).anyTimes();
expect(topology.isAttachmentPointPort(1L, (short)1, true))
.andReturn(true).anyTimes();
expect(topology.isAllowed(EasyMock.anyLong(), EasyMock.anyShort()))
.andReturn(true).anyTimes();
replay(sw1, sw2, sw3, routingEngine, decision14, topology);
forwarding.receive(sw1, this.packetIn14, cntx14);
betterFlowCacheMgr.updateFlush();
//verify(decision12);
// Check that the flow was added to flow-cache
assertEquals(1, betterFlowCacheMgr.getBfcCore().getActiveCnt());
assertEquals(0, betterFlowCacheMgr.getBfcCore().getInactiveCnt());
assertEquals(0, betterFlowCacheMgr.getBfcCore().getDelCnt());
assertEquals(1, betterFlowCacheMgr.getBfcCore().getAddCnt());
assertEquals(0, betterFlowCacheMgr.getBfcCore().getCacheHitCnt());
assertEquals(0, betterFlowCacheMgr.getBfcCore().getNotDampenedCnt());
/* Inject a switch removed event */
betterFlowCacheMgr.removedSwitch(sw1);
betterFlowCacheMgr.updateFlush();
// Check that the flow was removed from the cache
assertEquals(0, betterFlowCacheMgr.getBfcCore().getActiveCnt()); // 1 to 0
assertEquals(0, betterFlowCacheMgr.getBfcCore().getInactiveCnt());
assertEquals(1, betterFlowCacheMgr.getBfcCore().getDelCnt()); // 0 to 1
assertEquals(1, betterFlowCacheMgr.getBfcCore().getAddCnt());
assertEquals(0, betterFlowCacheMgr.getBfcCore().getCacheHitCnt());// 0 to 1
assertEquals(0, betterFlowCacheMgr.getBfcCore().getNotDampenedCnt());
/* Inject a switch removed event - this switch has no flow sourced
* on it */
betterFlowCacheMgr.removedSwitch(sw2);
// Check that the counters are unchanged
assertEquals(0, betterFlowCacheMgr.getBfcCore().getActiveCnt());
assertEquals(0, betterFlowCacheMgr.getBfcCore().getInactiveCnt());
assertEquals(1, betterFlowCacheMgr.getBfcCore().getDelCnt());
assertEquals(1, betterFlowCacheMgr.getBfcCore().getAddCnt());
assertEquals(0, betterFlowCacheMgr.getBfcCore().getCacheHitCnt());
assertEquals(0, betterFlowCacheMgr.getBfcCore().getNotDampenedCnt());
}
@SuppressWarnings("deprecation")
@Test
public void testSwitchAdded() throws Exception {
reset(sw1);
expect(sw1.getId()).andReturn(1L).anyTimes();
expect(sw1.isConnected()).andReturn(true).anyTimes();
betterFlowCacheMgr.clearFlowCache();
assertEquals(0, betterFlowCacheMgr.getBfcCore().getActiveCnt());
assertEquals(0, betterFlowCacheMgr.getBfcCore().getInactiveCnt());
Capture<OFStatisticsRequest> statsRequest =
new Capture<OFStatisticsRequest>(CaptureType.ALL);
Capture<Integer> xid =
new Capture<Integer>(CaptureType.ALL);
Capture<IOFMessageListener> callback =
new Capture<IOFMessageListener>(CaptureType.ALL);
sw1.sendStatsQuery(capture(statsRequest), capture(xid),
capture(callback));
expectLastCall().times(1);
replay(sw1);
// Simulate switch added
betterFlowCacheMgr.addedSwitch(sw1);
verify(sw1);
assertTrue(statsRequest.hasCaptured());
assertTrue(statsRequest.getValues().size() > 0);
OFStatisticsRequest thisRequest = statsRequest.getValues().get(0);
assertEquals(ofStatsRequest, thisRequest);
}
private class FlowWorker implements Runnable {
private String appName;
private long minSrcMac = 0;
private long srcMacRange = 0;
private long minDstMac = 0;
private long dstMacRange = 0;
private FCOper operation;
private int id;
public FlowWorker(int id,
long minSrcMac, long srcMacRange,
long minDstMac, long dstMacRange,
FCOper oper,
String appName) {
this.appName = appName;
this.id = id;
this.minSrcMac = minSrcMac;
this.srcMacRange = srcMacRange;
this.minDstMac = minDstMac;
this.dstMacRange = dstMacRange;
this.operation = oper;
}
private OFMatchWithSwDpid initOfMatchWithSWDpid(long srcMac,
long dstMac,
long dpid) {
OFMatchWithSwDpid fm = new OFMatchWithSwDpid();
OFMatch match = new OFMatch();
match.loadFromPacket(testPacketSerialized13, (short)1);
match.setDataLayerSource(Ethernet.toByteArray(srcMac));
match.setDataLayerDestination(Ethernet.toByteArray(dstMac));
fm.setOfMatch(match);
fm.setSwitchDataPathId(dpid);
return fm;
}
@Override
public void run() {
long srcMac = minSrcMac;
long swDpid = 1000L;
short inport = 10;
short priority = 0;
boolean verbose = false;
StringBuilder sb = new StringBuilder();
while (srcMac < minSrcMac + srcMacRange) {
long dstMac = minDstMac;
while (dstMac < minDstMac + dstMacRange) {
OFMatchWithSwDpid fm =
initOfMatchWithSWDpid(srcMac, dstMac, swDpid);
OFMatch ofmatch = fm.getOfMatch();
ofmatch.setWildcards(0x100000);
ofmatch.setInputPort(inport);
boolean status = false;
while (!status) {
switch (this.operation) {
case NEW_ENTRY:
status = betterFlowCacheMgr.addFlow(
appName,
fm,
100L, swDpid,
inport,
priority,
FlowCacheObj.FCActionPERMIT);
break;
case DELETED_ACTIVE:
status = betterFlowCacheMgr.deleteFlow(appName,
fm, priority);
break;
case DEACTIVATED:
status = betterFlowCacheMgr.deactivateFlow(appName,
fm, priority);
break;
default:
break;
}
/* Enable the printout to debug test failures.
if (!status) {
verbose = true;
}
if (verbose) {
sb.append(new Date() + "Thread id: " + id + " "
+ this.operation + " flow from " +
Long.toHexString(srcMac) + " to " +
Long.toHexString(dstMac) +
" activeFlowCnt: " +
betterFlowCacheMgr.getBfcCore().getActiveCnt() +
" deactiveFlowCnt: " +
betterFlowCacheMgr.getBfcCore().getInactiveCnt() +
" deletedFlowCnt: " +
betterFlowCacheMgr.getBfcCore().getDelCnt() +
" status: " + status + "\n");
}*/
}
dstMac++;
// Slow down the add to create race with either delete or
// de-activate threads
if (this.operation == BetterFlowCache.FCOper.NEW_ENTRY) {
try {
Thread.sleep(2);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
srcMac++;
betterFlowCacheMgr.updateFlush();
}
if (verbose) {
System.out.println(sb.toString());
System.out.println("Thread " + id + " Done.");
}
}
}
/**
* Test flowAdd and flowDelete in multi-threaded environment
* @throws InterruptedException
*/
@Test
public void testFlowAddDeletes() throws InterruptedException {
betterFlowCacheMgr.fqTask.setEnableFlowQueryTask(false);
// Simulate flow
int NUM_THREADS = 1;
int macRange = 5;
String appName = "app1";
// Add-flow threads
for (int i = 0; i < NUM_THREADS; i++) {
Runnable worker = this.new FlowWorker(i,
i * macRange,
macRange,
i * macRange,
macRange,
BetterFlowCache.FCOper.NEW_ENTRY,
appName);
Thread t = new Thread(worker);
t.start();
}
// Delete-flow threads
int idOffset = 2 * NUM_THREADS;
/**
* Make sure add-thread runs first and have enough time to
* create all the destMaps. Otherwise, delete thread can't delete
* flows whose destMap hasn't been created.
*/
while (betterFlowCacheMgr.getBfcCore().getActiveCnt() <
macRange*NUM_THREADS) {
Thread.sleep(1);
}
for (int i = 0; i < NUM_THREADS; i++) {
Runnable worker = this.new FlowWorker(idOffset + i,
i * macRange,
macRange,
i * macRange,
macRange,
BetterFlowCache.FCOper.DELETED_ACTIVE,
appName);
Thread t = new Thread(worker);
t.start();
}
Date startTime = new Date();
long totalFlows = NUM_THREADS * macRange * macRange;
if (totalFlows >= BetterFlowCache.MAX_FLOW_CACHE_SIZE_AS_FLOW_COUNT) {
totalFlows = BetterFlowCache.MAX_FLOW_CACHE_SIZE_AS_FLOW_COUNT;
}
while (betterFlowCacheMgr.getBfcCore().getActiveCnt() != 0 ||
betterFlowCacheMgr.getBfcCore().getDelCnt() != totalFlows) {
Date currTime = new Date();
if (currTime.getTime() - startTime.getTime() > 400) {
ConcurrentHashMap<Short, ConcurrentHashMap<Long,
ConcurrentHashMap<Long, FlowCacheObj>>> fms =
betterFlowCacheMgr.getAllFlowsByApplInstInternal(appName);
if (fms == null || fms.size() == 0) break;
int count = 0;
for (Short vlan : fms.keySet()) {
ConcurrentHashMap<Long,
ConcurrentHashMap<Long, FlowCacheObj>> fms_dst =
fms.get(vlan);
if (fms_dst == null || fms_dst.size() == 0) continue;
for (Long dstMac : fms_dst.keySet()) {
ConcurrentHashMap<Long, FlowCacheObj> fms_src =
fms_dst.get(dstMac);
if (fms_src == null || fms_src.size() == 0) continue;
for (long srcMac : fms_src.keySet()) {
FlowCacheObj fco = fms_src.get(srcMac);
if (fco.fce.state == FlowCacheObj.FCStateACTIVE) {
System.out.println(
"Count: " + ++count +
" vlan: " + vlan.shortValue() +
" src: " +
HexString.toHexString(srcMac, 6) +
" dst: " +
HexString.toHexString(dstMac.longValue(), 6) +
" fm: " +
fms_src.get(srcMac).fce.toString());
}
}
}
}
// break out of while loop
break;
}
}
assertEquals(0, betterFlowCacheMgr.getBfcCore().getActiveCnt());
assertEquals(totalFlows, betterFlowCacheMgr.getBfcCore().getDelCnt());
// Free all flows
betterFlowCacheMgr.clearFlowCache();
}
/**
* Test flowAdd and flowDeactivate in multi-threaded environment
* @throws InterruptedException
*/
@Test
public void testFlowAddDeactivate() throws InterruptedException {
betterFlowCacheMgr.fqTask.setEnableFlowQueryTask(false);
// Simulate flow
int NUM_THREADS = 1;
int macRange = 10;
String appName = "app1";
// Add-flow threads
for (int i = 0; i < NUM_THREADS; i++) {
Runnable worker = this.new FlowWorker(i,
i * macRange,
macRange,
i * macRange,
macRange,
BetterFlowCache.FCOper.NEW_ENTRY,
appName);
Thread t = new Thread(worker);
t.start();
}
// Deactive-flow threads
/**
* Make sure add-thread runs first and have enough time to
* create all the destMaps. Otherwise, delete thread can't delete
* flows whose destMap hasn't been created.
*/
while (betterFlowCacheMgr.getBfcCore().getActiveCnt() <
macRange*NUM_THREADS) {
Thread.sleep(1);
}
int idOffset = NUM_THREADS;
for (int i = 0; i < NUM_THREADS; i++) {
Runnable worker = this.new FlowWorker(idOffset + i,
i * macRange,
macRange,
i * macRange,
macRange,
BetterFlowCache.FCOper.DEACTIVATED,
appName);
Thread t = new Thread(worker);
t.start();
}
Thread.sleep(1000);
Date startTime = new Date();
long totalFlows = NUM_THREADS * macRange * macRange;
if (totalFlows >= BetterFlowCache.MAX_FLOW_CACHE_SIZE_AS_FLOW_COUNT) {
totalFlows = BetterFlowCache.MAX_FLOW_CACHE_SIZE_AS_FLOW_COUNT;
}
while (betterFlowCacheMgr.getBfcCore().getActiveCnt() != 0 ||
betterFlowCacheMgr.getBfcCore().getDeactivatedCnt() != totalFlows) {
Date currTime = new Date();
assertTrue((currTime.getTime() - startTime.getTime()) < 10000);
}
}
}