/**
* Copyright 2011, Big Switch Networks, Inc.
* Originally created by David Erickson, Stanford University
*
* Licensed under the Apache License, Version 2.0 (the "License"); you may
* not use this file except in compliance with the License. You may obtain
* a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
* License for the specific language governing permissions and limitations
* under the License.
**/
package net.floodlightcontroller.forwarding;
import static org.easymock.EasyMock.*;
import static org.junit.Assert.*;
import java.util.ArrayList;
import java.util.Date;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Set;
import net.floodlightcontroller.core.FloodlightContext;
import net.floodlightcontroller.core.IFloodlightProviderService;
import net.floodlightcontroller.core.IOFSwitch;
import net.floodlightcontroller.core.SwitchDescription;
import net.floodlightcontroller.core.internal.IOFSwitchService;
import net.floodlightcontroller.core.module.FloodlightModuleContext;
import net.floodlightcontroller.core.test.MockThreadPoolService;
import net.floodlightcontroller.core.types.NodePortTuple;
import net.floodlightcontroller.core.util.AppCookie;
import net.floodlightcontroller.debugcounter.IDebugCounterService;
import net.floodlightcontroller.debugcounter.MockDebugCounterService;
import net.floodlightcontroller.devicemanager.internal.DefaultEntityClassifier;
import net.floodlightcontroller.devicemanager.test.MockDeviceManager;
import net.floodlightcontroller.devicemanager.IDevice;
import net.floodlightcontroller.devicemanager.IDeviceService;
import net.floodlightcontroller.devicemanager.IEntityClassifierService;
import net.floodlightcontroller.linkdiscovery.ILinkDiscoveryService;
import net.floodlightcontroller.linkdiscovery.internal.LinkDiscoveryManager;
import net.floodlightcontroller.packet.Data;
import net.floodlightcontroller.packet.Ethernet;
import net.floodlightcontroller.packet.IPacket;
import net.floodlightcontroller.packet.IPv4;
import net.floodlightcontroller.packet.IPv6;
import net.floodlightcontroller.packet.UDP;
import net.floodlightcontroller.routing.IRoutingDecision.RoutingAction;
import net.floodlightcontroller.routing.IRoutingService;
import net.floodlightcontroller.routing.Path;
import net.floodlightcontroller.routing.RoutingDecision;
import net.floodlightcontroller.test.FloodlightTestCase;
import net.floodlightcontroller.threadpool.IThreadPoolService;
import net.floodlightcontroller.topology.ITopologyListener;
import net.floodlightcontroller.topology.ITopologyService;
import net.floodlightcontroller.util.OFMessageUtils;
import net.floodlightcontroller.forwarding.Forwarding;
import org.easymock.Capture;
import org.easymock.CaptureType;
import org.easymock.EasyMock;
import org.junit.Test;
import org.projectfloodlight.openflow.protocol.OFFeaturesReply;
import org.projectfloodlight.openflow.protocol.OFFlowMod;
import org.projectfloodlight.openflow.protocol.match.Match;
import org.projectfloodlight.openflow.protocol.match.MatchField;
import org.projectfloodlight.openflow.protocol.OFDescStatsReply;
import org.projectfloodlight.openflow.protocol.OFFactories;
import org.projectfloodlight.openflow.protocol.OFFactory;
import org.projectfloodlight.openflow.protocol.OFMessage;
import org.projectfloodlight.openflow.protocol.OFPacketIn;
import org.projectfloodlight.openflow.protocol.OFPacketOut;
import org.projectfloodlight.openflow.protocol.OFVersion;
import org.projectfloodlight.openflow.types.DatapathId;
import org.projectfloodlight.openflow.types.EthType;
import org.projectfloodlight.openflow.types.IPv4Address;
import org.projectfloodlight.openflow.types.IPv6Address;
import org.projectfloodlight.openflow.types.IpProtocol;
import org.projectfloodlight.openflow.types.MacAddress;
import org.projectfloodlight.openflow.types.Masked;
import org.projectfloodlight.openflow.types.OFBufferId;
import org.projectfloodlight.openflow.types.OFPort;
import org.projectfloodlight.openflow.types.TransportPort;
import org.projectfloodlight.openflow.types.U64;
import org.projectfloodlight.openflow.types.VlanVid;
import org.projectfloodlight.openflow.protocol.OFPacketInReason;
import org.projectfloodlight.openflow.protocol.action.OFAction;
import org.projectfloodlight.openflow.protocol.action.OFActionOutput;
import org.sdnplatform.sync.ISyncService;
import org.sdnplatform.sync.test.MockSyncService;
import com.google.common.collect.ImmutableList;
public class ForwardingTest extends FloodlightTestCase {
protected FloodlightContext cntx;
protected MockDeviceManager deviceManager;
protected IRoutingService routingEngine;
protected Forwarding forwarding;
protected ITopologyService topology;
protected LinkDiscoveryManager linkService;
protected MockThreadPoolService threadPool;
protected IOFSwitch sw1, sw2;
protected OFFeaturesReply swFeatures;
protected OFDescStatsReply swDescription;
protected IDevice srcDevice, dstDevice1, dstDevice2; /* reuse for IPv4 and IPv6 */
protected OFPacketIn packetIn;
protected OFPacketIn packetInIPv6;
protected OFPacketOut packetOut;
protected OFPacketOut packetOutIPv6;
protected OFPacketOut packetOutFlooded;
protected OFPacketOut packetOutFloodedIPv6;
protected IPacket testPacket;
protected IPacket testPacketIPv6;
protected byte[] testPacketSerialized;
protected byte[] testPacketSerializedIPv6;
protected int expected_wildcards;
protected Date currentDate;
private MockSyncService mockSyncService;
private OFFactory factory = OFFactories.getFactory(OFVersion.OF_13);
@Override
public void setUp() throws Exception {
super.setUp();
cntx = new FloodlightContext();
// Module loader setup
mockFloodlightProvider = getMockFloodlightProvider();
forwarding = new Forwarding();
threadPool = new MockThreadPoolService();
deviceManager = new MockDeviceManager();
routingEngine = createMock(IRoutingService.class);
topology = createMock(ITopologyService.class);
mockSyncService = new MockSyncService();
linkService = new LinkDiscoveryManager();
DefaultEntityClassifier entityClassifier = new DefaultEntityClassifier();
FloodlightModuleContext fmc = new FloodlightModuleContext();
fmc.addService(IFloodlightProviderService.class,
mockFloodlightProvider);
fmc.addService(IThreadPoolService.class, threadPool);
fmc.addService(ITopologyService.class, topology);
fmc.addService(IRoutingService.class, routingEngine);
fmc.addService(IDeviceService.class, deviceManager);
fmc.addService(IEntityClassifierService.class, entityClassifier);
fmc.addService(ISyncService.class, mockSyncService);
fmc.addService(IDebugCounterService.class, new MockDebugCounterService());
fmc.addService(IOFSwitchService.class, getMockSwitchService());
fmc.addService(ILinkDiscoveryService.class, linkService);
topology.addListener(anyObject(ITopologyListener.class));
expectLastCall().anyTimes();
expect(topology.isBroadcastAllowed(anyObject(DatapathId.class), anyObject(OFPort.class))).andReturn(true).anyTimes();
replay(topology);
threadPool.init(fmc);
mockSyncService.init(fmc);
linkService.init(fmc);
deviceManager.init(fmc);
forwarding.init(fmc);
entityClassifier.init(fmc);
threadPool.startUp(fmc);
mockSyncService.startUp(fmc);
linkService.startUp(fmc);
deviceManager.startUp(fmc);
forwarding.startUp(fmc);
Forwarding.flowSetIdRegistry.seedFlowSetIdForUnitTest(3);
entityClassifier.startUp(fmc);
verify(topology);
swDescription = factory.buildDescStatsReply().build();
swFeatures = factory.buildFeaturesReply().setNBuffers(1000).build();
// Mock switches
sw1 = EasyMock.createMock(IOFSwitch.class);
expect(sw1.getId()).andReturn(DatapathId.of(1L)).anyTimes();
expect(sw1.getOFFactory()).andReturn(factory).anyTimes();
expect(sw1.getBuffers()).andReturn(swFeatures.getNBuffers()).anyTimes();
sw2 = EasyMock.createMock(IOFSwitch.class);
expect(sw2.getId()).andReturn(DatapathId.of(2L)).anyTimes();
expect(sw2.getOFFactory()).andReturn(factory).anyTimes();
expect(sw2.getBuffers()).andReturn(swFeatures.getNBuffers()).anyTimes();
expect(sw1.hasAttribute(IOFSwitch.PROP_SUPPORTS_OFPP_TABLE)).andReturn(true).anyTimes();
expect(sw2.hasAttribute(IOFSwitch.PROP_SUPPORTS_OFPP_TABLE)).andReturn(true).anyTimes();
expect(sw1.getSwitchDescription()).andReturn(new SwitchDescription(swDescription)).anyTimes();
expect(sw2.getSwitchDescription()).andReturn(new SwitchDescription(swDescription)).anyTimes();
expect(sw1.isActive()).andReturn(true).anyTimes();
expect(sw2.isActive()).andReturn(true).anyTimes();
// Load the switch map
Map<DatapathId, IOFSwitch> switches = new HashMap<DatapathId, IOFSwitch>();
switches.put(DatapathId.of(1L), sw1);
switches.put(DatapathId.of(2L), sw2);
getMockSwitchService().setSwitches(switches);
// Build test packet
testPacket = new Ethernet()
.setDestinationMACAddress("00:11:22:33:44:55")
.setSourceMACAddress("00:44:33:22:11:00")
.setEtherType(EthType.IPv4)
.setPayload(
new IPv4()
.setTtl((byte) 128)
.setSourceAddress("192.168.1.1")
.setDestinationAddress("192.168.1.2")
.setPayload(new UDP()
.setSourcePort((short) 5000)
.setDestinationPort((short) 5001)
.setPayload(new Data(new byte[] {0x01}))));
testPacketIPv6 = new Ethernet()
.setDestinationMACAddress("00:11:22:33:44:55")
.setSourceMACAddress("00:44:33:22:11:00")
.setEtherType(EthType.IPv6)
.setPayload(
new IPv6()
.setHopLimit((byte) 128)
.setSourceAddress(IPv6Address.of(1, 1))
.setDestinationAddress(IPv6Address.of(2, 2))
.setNextHeader(IpProtocol.UDP)
.setPayload(new UDP()
.setSourcePort((short) 5000)
.setDestinationPort((short) 5001)
.setPayload(new Data(new byte[] {0x01}))));
currentDate = new Date();
// Mock Packet-in
testPacketSerialized = testPacket.serialize();
testPacketSerializedIPv6 = testPacketIPv6.serialize();
packetIn = factory.buildPacketIn()
.setMatch(factory.buildMatch()
.setExact(MatchField.IN_PORT, OFPort.of(1))
.setExact(MatchField.ETH_SRC, MacAddress.of("00:44:33:22:11:00"))
.setExact(MatchField.ETH_DST, MacAddress.of("00:11:22:33:44:55"))
.setExact(MatchField.ETH_TYPE, EthType.IPv4)
.setExact(MatchField.IPV4_SRC, IPv4Address.of("192.168.1.1"))
.setExact(MatchField.IPV4_DST, IPv4Address.of("192.168.1.2"))
.setExact(MatchField.IP_PROTO, IpProtocol.UDP)
.setExact(MatchField.UDP_SRC, TransportPort.of(5000))
.setExact(MatchField.UDP_DST, TransportPort.of(5001))
.build())
.setBufferId(OFBufferId.NO_BUFFER)
.setData(testPacketSerialized)
.setReason(OFPacketInReason.NO_MATCH)
.build();
packetInIPv6 = factory.buildPacketIn()
.setMatch(factory.buildMatch()
.setExact(MatchField.IN_PORT, OFPort.of(1))
.setExact(MatchField.ETH_SRC, MacAddress.of("00:44:33:22:11:00"))
.setExact(MatchField.ETH_DST, MacAddress.of("00:11:22:33:44:55"))
.setExact(MatchField.ETH_TYPE, EthType.IPv6)
.setExact(MatchField.IPV6_SRC, IPv6Address.of(1, 1))
.setExact(MatchField.IPV6_DST, IPv6Address.of(2, 2))
.setExact(MatchField.IP_PROTO, IpProtocol.UDP)
.setExact(MatchField.UDP_SRC, TransportPort.of(5000))
.setExact(MatchField.UDP_DST, TransportPort.of(5001))
.build())
.setBufferId(OFBufferId.NO_BUFFER)
.setData(testPacketSerializedIPv6)
.setReason(OFPacketInReason.NO_MATCH)
.build();
// Mock Packet-out
List<OFAction> poactions = new ArrayList<OFAction>();
poactions.add(factory.actions().output(OFPort.of(3), Integer.MAX_VALUE));
packetOut = factory.buildPacketOut()
.setBufferId(this.packetIn.getBufferId())
.setActions(poactions)
.setInPort(OFPort.of(1))
.setData(testPacketSerialized)
.setXid(15)
.build();
packetOutIPv6 = factory.buildPacketOut()
.setBufferId(this.packetInIPv6.getBufferId())
.setActions(poactions)
.setInPort(OFPort.of(1))
.setData(testPacketSerializedIPv6)
.setXid(15)
.build();
// Mock Packet-out with OFPP_FLOOD action (list of ports to flood)
poactions = new ArrayList<OFAction>();
poactions.add(factory.actions().output(OFPort.of(10), Integer.MAX_VALUE));
packetOutFlooded = factory.buildPacketOut()
.setBufferId(this.packetIn.getBufferId())
.setInPort(packetIn.getMatch().get(MatchField.IN_PORT))
.setXid(17)
.setActions(poactions)
.setData(testPacketSerialized)
.build();
packetOutFloodedIPv6 = factory.buildPacketOut()
.setBufferId(this.packetInIPv6.getBufferId())
.setInPort(packetInIPv6.getMatch().get(MatchField.IN_PORT))
.setXid(17)
.setActions(poactions)
.setData(testPacketSerializedIPv6)
.build();
}
void removeDeviceFromContext() {
IFloodlightProviderService.bcStore.
remove(cntx,
IFloodlightProviderService.CONTEXT_PI_PAYLOAD);
IFloodlightProviderService.bcStore.
remove(cntx,
IDeviceService.CONTEXT_SRC_DEVICE);
IFloodlightProviderService.bcStore.
remove(cntx,
IDeviceService.CONTEXT_DST_DEVICE);
}
static boolean messageListsEqualIgnoreXid(List<OFMessage> c1, List<OFMessage> c2) {
if (c1 == c2) {
return true;
}
if (c1 == null || c2 == null) {
return false;
}
if (c1.size() != c2.size()) {
return false;
}
Iterator<OFMessage> it1 = c1.iterator();
Iterator<OFMessage> it2 = c2.iterator();
while (it1.hasNext()) {
OFMessage m1 = it1.next();
OFMessage m2 = it2.next();
if (m1 == m2) {
continue;
}
if (m1 == null || m2 == null || !m1.equalsIgnoreXid(m2)) {
return false;
}
}
return true;
}
enum DestDeviceToLearn { NONE, DEVICE1 ,DEVICE2 };
public void learnDevices(DestDeviceToLearn destDeviceToLearn) {
// Build src and dest devices
MacAddress dataLayerSource = ((Ethernet)testPacket).getSourceMACAddress();
MacAddress dataLayerDest =
((Ethernet)testPacket).getDestinationMACAddress();
IPv4Address networkSource =
((IPv4)((Ethernet)testPacket).getPayload()).
getSourceAddress();
IPv4Address networkDest =
((IPv4)((Ethernet)testPacket).getPayload()).
getDestinationAddress();
reset(topology);
expect(topology.isAttachmentPointPort(DatapathId.of(1L), OFPort.of(1)))
.andReturn(true)
.anyTimes();
expect(topology.isAttachmentPointPort(DatapathId.of(2L), OFPort.of(3)))
.andReturn(true)
.anyTimes();
expect(topology.isAttachmentPointPort(DatapathId.of(1L), OFPort.of(3)))
.andReturn(true)
.anyTimes();
replay(topology);
srcDevice =
deviceManager.learnEntity(dataLayerSource, VlanVid.ZERO,
networkSource, IPv6Address.NONE,
DatapathId.of(1), OFPort.of(1));
IDeviceService.fcStore. put(cntx,
IDeviceService.CONTEXT_SRC_DEVICE,
srcDevice);
if (destDeviceToLearn == DestDeviceToLearn.DEVICE1) {
dstDevice1 =
deviceManager.learnEntity(dataLayerDest, VlanVid.ZERO,
networkDest, IPv6Address.NONE,
DatapathId.of(2), OFPort.of(3));
IDeviceService.fcStore.put(cntx,
IDeviceService.CONTEXT_DST_DEVICE,
dstDevice1);
}
if (destDeviceToLearn == DestDeviceToLearn.DEVICE2) {
dstDevice2 =
deviceManager.learnEntity(dataLayerDest, VlanVid.ZERO,
networkDest, IPv6Address.NONE,
DatapathId.of(1), OFPort.of(3));
IDeviceService.fcStore.put(cntx,
IDeviceService.CONTEXT_DST_DEVICE,
dstDevice2);
}
verify(topology);
IFloodlightProviderService.bcStore.
put(cntx,
IFloodlightProviderService.CONTEXT_PI_PAYLOAD,
(Ethernet)testPacket);
}
public void learnDevicesIPv6(DestDeviceToLearn destDeviceToLearn) {
// Build src and dest devices
MacAddress dataLayerSource = ((Ethernet)testPacketIPv6).getSourceMACAddress();
MacAddress dataLayerDest =
((Ethernet)testPacketIPv6).getDestinationMACAddress();
IPv6Address networkSource =
((IPv6)((Ethernet)testPacketIPv6).getPayload()).
getSourceAddress();
IPv6Address networkDest =
((IPv6)((Ethernet)testPacketIPv6).getPayload()).
getDestinationAddress();
reset(topology);
expect(topology.isAttachmentPointPort(DatapathId.of(1L), OFPort.of(1)))
.andReturn(true)
.anyTimes();
expect(topology.isAttachmentPointPort(DatapathId.of(2L), OFPort.of(3)))
.andReturn(true)
.anyTimes();
expect(topology.isAttachmentPointPort(DatapathId.of(1L), OFPort.of(3)))
.andReturn(true)
.anyTimes();
replay(topology);
srcDevice =
deviceManager.learnEntity(dataLayerSource, VlanVid.ZERO,
IPv4Address.NONE, networkSource,
DatapathId.of(1), OFPort.of(1));
IDeviceService.fcStore.put(cntx,
IDeviceService.CONTEXT_SRC_DEVICE,
srcDevice);
if (destDeviceToLearn == DestDeviceToLearn.DEVICE1) {
dstDevice1 =
deviceManager.learnEntity(dataLayerDest, VlanVid.ZERO,
IPv4Address.NONE, networkDest,
DatapathId.of(2), OFPort.of(3));
IDeviceService.fcStore.put(cntx,
IDeviceService.CONTEXT_DST_DEVICE,
dstDevice1);
}
if (destDeviceToLearn == DestDeviceToLearn.DEVICE2) {
dstDevice2 =
deviceManager.learnEntity(dataLayerDest, VlanVid.ZERO,
IPv4Address.NONE, networkDest,
DatapathId.of(1), OFPort.of(3));
IDeviceService.fcStore.put(cntx,
IDeviceService.CONTEXT_DST_DEVICE,
dstDevice2);
}
verify(topology);
IFloodlightProviderService.bcStore.
put(cntx,
IFloodlightProviderService.CONTEXT_PI_PAYLOAD,
(Ethernet)testPacketIPv6);
}
@Test
public void testForwardMultiSwitchPath() throws Exception {
learnDevices(DestDeviceToLearn.DEVICE1);
Capture<OFMessage> wc1 = EasyMock.newCapture(CaptureType.ALL);
Capture<OFMessage> wc2 = EasyMock.newCapture(CaptureType.ALL);
Path path = new Path(DatapathId.of(1L), DatapathId.of(2L));
List<NodePortTuple> nptList = new ArrayList<NodePortTuple>();
nptList.add(new NodePortTuple(DatapathId.of(1L), OFPort.of(1)));
nptList.add(new NodePortTuple(DatapathId.of(1L), OFPort.of(3)));
nptList.add(new NodePortTuple(DatapathId.of(2L), OFPort.of(1)));
nptList.add(new NodePortTuple(DatapathId.of(2L), OFPort.of(3)));
path.setPath(nptList);
reset(routingEngine);
expect(routingEngine.getPath(DatapathId.of(1L), OFPort.of(1), DatapathId.of(2L), OFPort.of(3))).andReturn(path).atLeastOnce();
// Expected Flow-mods
Match match = packetIn.getMatch();
OFActionOutput action = factory.actions().output(OFPort.of(3), Integer.MAX_VALUE);
List<OFAction> actions = new ArrayList<OFAction>();
actions.add(action);
OFFlowMod fm1 = factory.buildFlowAdd()
.setIdleTimeout((short)5)
.setMatch(match)
.setActions(actions)
.setOutPort(action.getPort())
.setBufferId(OFBufferId.NO_BUFFER)
.setCookie(U64.of(2L << 52).or(U64.of(4 << Forwarding.FLOWSET_SHIFT)))
.setPriority(1)
.build();
OFFlowMod fm2 = fm1.createBuilder().build();
expect(sw1.write(capture(wc1))).andReturn(true).anyTimes();
expect(sw2.write(capture(wc2))).andReturn(true).anyTimes();
reset(topology);
expect(topology.getClusterId(DatapathId.of(1L))).andReturn(DatapathId.of(1L)).anyTimes();
expect(topology.getClusterId(DatapathId.of(2L))).andReturn(DatapathId.of(1L)).anyTimes();
expect(topology.isAttachmentPointPort(DatapathId.of(1L), OFPort.of(1))).andReturn(true).anyTimes();
expect(topology.isAttachmentPointPort(DatapathId.of(2L), OFPort.of(3))).andReturn(true).anyTimes();
expect(topology.isBroadcastAllowed(DatapathId.of(anyLong()), OFPort.of(anyShort()))).andReturn(true).anyTimes();
expect(topology.isEdge(DatapathId.of(1L), OFPort.of(1))).andReturn(true).anyTimes();
expect(topology.isEdge(DatapathId.of(2L), OFPort.of(3))).andReturn(true).anyTimes();
// Reset mocks, trigger the packet in, and validate results
replay(sw1, sw2, routingEngine, topology);
forwarding.receive(sw1, this.packetIn, cntx);
verify(sw1, sw2, routingEngine);
assertTrue(wc1.hasCaptured()); // wc1 should get packetout + flowmod.
assertTrue(wc2.hasCaptured()); // wc2 should be a flowmod.
List<OFMessage> msglist = wc1.getValues();
for (OFMessage m: msglist) {
if (m instanceof OFFlowMod)
assertEquals(OFMessageUtils.OFMessageIgnoreXid.of(fm1), OFMessageUtils.OFMessageIgnoreXid.of(m));
else if (m instanceof OFPacketOut) {
assertEquals(OFMessageUtils.OFMessageIgnoreXid.of(packetOut), OFMessageUtils.OFMessageIgnoreXid.of(m));
}
}
OFMessage m = wc2.getValue();
assert (m instanceof OFFlowMod);
assertEquals(OFMessageUtils.OFMessageIgnoreXid.of(m), OFMessageUtils.OFMessageIgnoreXid.of(fm2));
removeDeviceFromContext();
}
@Test
public void testForwardMultiSwitchPathIPv6() throws Exception {
learnDevicesIPv6(DestDeviceToLearn.DEVICE1);
Capture<OFMessage> wc1 = EasyMock.newCapture(CaptureType.ALL);
Capture<OFMessage> wc2 = EasyMock.newCapture(CaptureType.ALL);
Path route = new Path(DatapathId.of(1L), DatapathId.of(2L));
List<NodePortTuple> nptList = new ArrayList<NodePortTuple>();
nptList.add(new NodePortTuple(DatapathId.of(1L), OFPort.of(1)));
nptList.add(new NodePortTuple(DatapathId.of(1L), OFPort.of(3)));
nptList.add(new NodePortTuple(DatapathId.of(2L), OFPort.of(1)));
nptList.add(new NodePortTuple(DatapathId.of(2L), OFPort.of(3)));
route.setPath(nptList);
reset(routingEngine);
expect(routingEngine.getPath(DatapathId.of(1L), OFPort.of(1), DatapathId.of(2L), OFPort.of(3))).andReturn(route).atLeastOnce();
// Expected Flow-mods
Match match = packetInIPv6.getMatch();
OFActionOutput action = factory.actions().output(OFPort.of(3), Integer.MAX_VALUE);
List<OFAction> actions = new ArrayList<OFAction>();
actions.add(action);
OFFlowMod fm1 = factory.buildFlowAdd()
.setIdleTimeout((short)5)
.setMatch(match)
.setActions(actions)
.setOutPort(action.getPort())
.setBufferId(OFBufferId.NO_BUFFER)
.setCookie(U64.of(2L << 52).or(U64.of(4 << Forwarding.FLOWSET_SHIFT)))
.setPriority(1)
.build();
OFFlowMod fm2 = fm1.createBuilder().build();
expect(sw1.write(capture(wc1))).andReturn(true).anyTimes();
expect(sw2.write(capture(wc2))).andReturn(true).anyTimes();
reset(topology);
expect(topology.getClusterId(DatapathId.of(1L))).andReturn(DatapathId.of(1L)).anyTimes();
expect(topology.getClusterId(DatapathId.of(2L))).andReturn(DatapathId.of(1L)).anyTimes();
expect(topology.isAttachmentPointPort(DatapathId.of(1L), OFPort.of(1))).andReturn(true).anyTimes();
expect(topology.isAttachmentPointPort(DatapathId.of(2L), OFPort.of(3))).andReturn(true).anyTimes();
expect(topology.isBroadcastAllowed(DatapathId.of(anyLong()), OFPort.of(anyShort()))).andReturn(true).anyTimes();
expect(topology.isEdge(DatapathId.of(1L), OFPort.of(1))).andReturn(true).anyTimes();
expect(topology.isEdge(DatapathId.of(2L), OFPort.of(3))).andReturn(true).anyTimes();
// Reset mocks, trigger the packet in, and validate results
replay(sw1, sw2, routingEngine, topology);
forwarding.receive(sw1, this.packetInIPv6, cntx);
verify(sw1, sw2, routingEngine);
assertTrue(wc1.hasCaptured()); // wc1 should get packetout + flowmod.
assertTrue(wc2.hasCaptured()); // wc2 should be a flowmod.
List<OFMessage> msglist = wc1.getValues();
for (OFMessage m: msglist) {
if (m instanceof OFFlowMod)
assertEquals(OFMessageUtils.OFMessageIgnoreXid.of(fm1), OFMessageUtils.OFMessageIgnoreXid.of(m));
else if (m instanceof OFPacketOut) {
assertEquals(OFMessageUtils.OFMessageIgnoreXid.of(packetOutIPv6), OFMessageUtils.OFMessageIgnoreXid.of(m));
}
}
OFMessage m = wc2.getValue();
assert (m instanceof OFFlowMod);
assertEquals(OFMessageUtils.OFMessageIgnoreXid.of(m), OFMessageUtils.OFMessageIgnoreXid.of(fm2));
removeDeviceFromContext();
}
@Test
public void testForwardSingleSwitchPath() throws Exception {
learnDevices(DestDeviceToLearn.DEVICE2);
Capture<OFMessage> wc1 = EasyMock.newCapture(CaptureType.ALL);
Capture<OFMessage> wc2 = EasyMock.newCapture(CaptureType.ALL);
Path route = new Path(DatapathId.of(1L), DatapathId.of(1L));
route.getPath().add(new NodePortTuple(DatapathId.of(1L), OFPort.of(1)));
route.getPath().add(new NodePortTuple(DatapathId.of(1L), OFPort.of(3)));
expect(routingEngine.getPath(DatapathId.of(1L), OFPort.of(1), DatapathId.of(1L), OFPort.of(3))).andReturn(route).atLeastOnce();
// Expected Flow-mods
Match match = packetIn.getMatch();
OFActionOutput action = factory.actions().output(OFPort.of(3), Integer.MAX_VALUE);
List<OFAction> actions = new ArrayList<OFAction>();
actions.add(action);
//routingEngine.addRoutingDecisionChangedListener(anyObject(IRoutingDecisionChangedListener.class));
OFFlowMod fm1 = factory.buildFlowAdd()
.setIdleTimeout((short)5)
.setMatch(match)
.setActions(actions)
.setOutPort(OFPort.of(3))
.setBufferId(OFBufferId.NO_BUFFER)
.setCookie(U64.of(2L << 52).or(U64.of(4 << Forwarding.FLOWSET_SHIFT)))
.setPriority(1)
.build();
// Record expected packet-outs/flow-mods
expect(sw1.write(capture(wc1))).andReturn(true).once();
expect(sw1.write(capture(wc2))).andReturn(true).once();
reset(topology);
expect(topology.isBroadcastAllowed(DatapathId.of(anyLong()), OFPort.of(anyShort()))).andReturn(true).anyTimes();
expect(topology.getClusterId(DatapathId.of(1L))).andReturn(DatapathId.of(1L)).anyTimes();
expect(topology.isAttachmentPointPort(DatapathId.of(1L), OFPort.of(1))).andReturn(true).anyTimes();
expect(topology.isAttachmentPointPort(DatapathId.of(1L), OFPort.of(3))).andReturn(true).anyTimes();
expect(topology.isEdge(DatapathId.of(1L), OFPort.of(1))).andReturn(true).anyTimes();
expect(topology.isEdge(DatapathId.of(1L), OFPort.of(3))).andReturn(true).anyTimes();
// Reset mocks, trigger the packet in, and validate results
reset(routingEngine);
expect(routingEngine.getPath(DatapathId.of(1L), OFPort.of(1), DatapathId.of(1L), OFPort.of(3))).andReturn(route).atLeastOnce();
replay(sw1, sw2, routingEngine, topology);
forwarding.receive(sw1, this.packetIn, cntx);
verify(sw1, sw2, routingEngine);
assertTrue(wc1.hasCaptured());
assertTrue(wc2.hasCaptured());
assertEquals(OFMessageUtils.OFMessageIgnoreXid.of(wc1.getValue()), OFMessageUtils.OFMessageIgnoreXid.of(fm1));
assertEquals(OFMessageUtils.OFMessageIgnoreXid.of(wc2.getValue()), OFMessageUtils.OFMessageIgnoreXid.of(packetOut));
removeDeviceFromContext();
}
@Test
public void testForwardSingleSwitchPathIPv6() throws Exception {
learnDevicesIPv6(DestDeviceToLearn.DEVICE2);
Capture<OFMessage> wc1 = EasyMock.newCapture(CaptureType.ALL);
Capture<OFMessage> wc2 = EasyMock.newCapture(CaptureType.ALL);
Path route = new Path(DatapathId.of(1L), DatapathId.of(1L));
route.getPath().add(new NodePortTuple(DatapathId.of(1L), OFPort.of(1)));
route.getPath().add(new NodePortTuple(DatapathId.of(1L), OFPort.of(3)));
reset(routingEngine);
expect(routingEngine.getPath(DatapathId.of(1L), OFPort.of(1), DatapathId.of(1L), OFPort.of(3))).andReturn(route).atLeastOnce();
// Expected Flow-mods
Match match = packetInIPv6.getMatch();
OFActionOutput action = factory.actions().output(OFPort.of(3), Integer.MAX_VALUE);
List<OFAction> actions = new ArrayList<OFAction>();
actions.add(action);
OFFlowMod fm1 = factory.buildFlowAdd()
.setIdleTimeout((short)5)
.setMatch(match)
.setActions(actions)
.setOutPort(OFPort.of(3))
.setBufferId(OFBufferId.NO_BUFFER)
.setCookie(U64.of(2L << 52).or(U64.of(4 << Forwarding.FLOWSET_SHIFT)))
.setPriority(1)
.build();
// Record expected packet-outs/flow-mods
expect(sw1.write(capture(wc1))).andReturn(true).once();
expect(sw1.write(capture(wc2))).andReturn(true).once();
reset(topology);
expect(topology.isBroadcastAllowed(DatapathId.of(anyLong()), OFPort.of(anyShort()))).andReturn(true).anyTimes();
expect(topology.getClusterId(DatapathId.of(1L))).andReturn(DatapathId.of(1L)).anyTimes();
expect(topology.isAttachmentPointPort(DatapathId.of(1L), OFPort.of(1))).andReturn(true).anyTimes();
expect(topology.isAttachmentPointPort(DatapathId.of(1L), OFPort.of(3))).andReturn(true).anyTimes();
expect(topology.isEdge(DatapathId.of(1L), OFPort.of(1))).andReturn(true).anyTimes();
expect(topology.isEdge(DatapathId.of(1L), OFPort.of(3))).andReturn(true).anyTimes();
// Reset mocks, trigger the packet in, and validate results
replay(sw1, sw2, routingEngine, topology);
forwarding.receive(sw1, this.packetInIPv6, cntx);
verify(sw1, sw2, routingEngine);
assertTrue(wc1.hasCaptured());
assertTrue(wc2.hasCaptured());
assertEquals(OFMessageUtils.OFMessageIgnoreXid.of(wc1.getValue()), OFMessageUtils.OFMessageIgnoreXid.of(fm1));
assertEquals(OFMessageUtils.OFMessageIgnoreXid.of(wc2.getValue()), OFMessageUtils.OFMessageIgnoreXid.of(packetOutIPv6));
removeDeviceFromContext();
}
/*TODO OFMessageDamper broken due to XID variability in OFMessages... need to fix @Test */
/*TODO make an IPv6 test for this once OFMessageDamper fixed */
public void testFlowModDampening() throws Exception {
learnDevices(DestDeviceToLearn.DEVICE2);
reset(topology);
expect(topology.isAttachmentPointPort(DatapathId.of(anyLong()), OFPort.of(anyShort())))
.andReturn(true).anyTimes();
expect(topology.getClusterId(DatapathId.of(1L))).andReturn(DatapathId.of(1L)).anyTimes();
replay(topology);
Path route = new Path(DatapathId.of(1L), DatapathId.of(1L));
route.getPath().add(new NodePortTuple(DatapathId.of(1L), OFPort.of(1)));
route.getPath().add(new NodePortTuple(DatapathId.of(1L), OFPort.of(3)));
expect(routingEngine.getPath(DatapathId.of(1L), OFPort.of(1), DatapathId.of(1L), OFPort.of(3))).andReturn(route).atLeastOnce();
// Expected Flow-mods
Match match = packetIn.getMatch();
OFActionOutput action = factory.actions().output(OFPort.of(3), Integer.MAX_VALUE);
List<OFAction> actions = new ArrayList<OFAction>();
actions.add(action);
OFFlowMod fm1 = factory.buildFlowAdd()
.setIdleTimeout((short)5)
.setMatch(match)
.setActions(actions)
.setOutPort(OFPort.of(3))
.setBufferId(OFBufferId.NO_BUFFER)
.setCookie(U64.of(2L << 52).or(U64.of(6 << Forwarding.FLOWSET_SHIFT)))
.setXid(anyLong())
.build();
// Record expected packet-outs/flow-mods
// We will inject the packet_in 3 times and expect 1 flow mod and
// 3 packet outs due to flow mod dampening
expect(sw1.write(fm1)).andReturn(true).once();
// Update new expected XID
expect(sw1.write(packetOut.createBuilder().setXid(anyLong()).build())).andReturn(true).times(3);
reset(topology);
expect(topology.isBroadcastAllowed(DatapathId.of(anyLong()), OFPort.of(anyInt()))).andReturn(true).anyTimes();
expect(topology.isEdge(DatapathId.of(anyLong()), OFPort.of(anyInt()))).andReturn(true).anyTimes();
expect(topology.getClusterId(DatapathId.of(1L))).andReturn(DatapathId.of(1L)).anyTimes();
expect(topology.isAttachmentPointPort(DatapathId.of(1L), OFPort.of(1))).andReturn(true).anyTimes();
expect(topology.isAttachmentPointPort(DatapathId.of(1L), OFPort.of(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);
removeDeviceFromContext();
}
@Test
public void testForwardNoPath() throws Exception {
learnDevices(DestDeviceToLearn.NONE);
// Set no destination attachment point or route
// expect no Flow-mod but expect the packet to be flooded
reset(routingEngine);
Capture<OFMessage> wc1 = EasyMock.newCapture(CaptureType.ALL);
Set<OFPort> bcastPorts = new HashSet<OFPort>();
bcastPorts.add(OFPort.of(10));
// Reset mocks, trigger the packet in, and validate results
reset(topology);
expect(topology.getSwitchBroadcastPorts(DatapathId.of(1L))).andReturn(bcastPorts).once();
expect(topology.isAttachmentPointPort(DatapathId.of(anyLong()),
OFPort.of(anyShort())))
.andReturn(true)
.anyTimes();
expect(sw1.hasAttribute(IOFSwitch.PROP_SUPPORTS_OFPP_FLOOD)).andReturn(true).anyTimes();
expect(sw1.write(capture(wc1))).andReturn(true).once();
replay(sw1, sw2, routingEngine, topology);
forwarding.receive(sw1, this.packetIn, cntx);
verify(sw1, sw2, routingEngine);
assertTrue(wc1.hasCaptured());
assertEquals(OFMessageUtils.OFMessageIgnoreXid.of(wc1.getValue()), OFMessageUtils.OFMessageIgnoreXid.of(packetOutFlooded));
removeDeviceFromContext();
}
@Test
public void testForwardNoPathIPv6() throws Exception {
learnDevicesIPv6(DestDeviceToLearn.NONE);
reset(routingEngine);
// Set no destination attachment point or route
// expect no Flow-mod but expect the packet to be flooded
Capture<OFMessage> wc1 = EasyMock.newCapture(CaptureType.ALL);
Set<OFPort> bcastPorts = new HashSet<OFPort>();
bcastPorts.add(OFPort.of(10));
// Reset mocks, trigger the packet in, and validate results
reset(topology);
expect(topology.getSwitchBroadcastPorts(DatapathId.of(1L))).andReturn(bcastPorts).once();
expect(topology.isAttachmentPointPort(DatapathId.of(anyLong()),
OFPort.of(anyShort())))
.andReturn(true)
.anyTimes();
expect(sw1.hasAttribute(IOFSwitch.PROP_SUPPORTS_OFPP_FLOOD))
.andReturn(true).anyTimes();
// Reset XID to expected (dependent on prior unit tests)
expect(sw1.write(capture(wc1))).andReturn(true).once();
replay(sw1, sw2, routingEngine, topology);
forwarding.receive(sw1, this.packetInIPv6, cntx);
verify(sw1, sw2, routingEngine);
assertTrue(wc1.hasCaptured());
assertEquals(OFMessageUtils.OFMessageIgnoreXid.of(wc1.getValue()), OFMessageUtils.OFMessageIgnoreXid.of(packetOutFloodedIPv6));
removeDeviceFromContext();
}
/*
* TODO Consider adding test cases for other Decision != null paths (I only added FORWARD and none of the paths had test cases)
*/
@Test
public void testForwardDecisionForwardingCookieZero() throws Exception {
learnDevices(DestDeviceToLearn.DEVICE2);
Capture<OFMessage> wc1 = EasyMock.newCapture(CaptureType.ALL);
Capture<OFMessage> wc2 = EasyMock.newCapture(CaptureType.ALL);
Path path = new Path(DatapathId.of(1L), DatapathId.of(1L));
path.getPath().add(new NodePortTuple(DatapathId.of(1L), OFPort.of(1)));
path.getPath().add(new NodePortTuple(DatapathId.of(1L), OFPort.of(3)));
reset(routingEngine);
expect(routingEngine.getPath(DatapathId.of(1L), OFPort.of(1), DatapathId.of(1L), OFPort.of(3))).andReturn(path).atLeastOnce();
// Expected Flow-mods
Match match = packetIn.getMatch();
OFActionOutput action = factory.actions().output(OFPort.of(3), Integer.MAX_VALUE);
List<OFAction> actions = new ArrayList<OFAction>();
actions.add(action);
RoutingDecision decision = new RoutingDecision(DatapathId.of(1L), OFPort.of(1), dstDevice1, RoutingAction.FORWARD);
decision.setDescriptor(U64.ZERO);
decision.addToContext(cntx);
OFFlowMod fm1 = factory.buildFlowAdd()
.setIdleTimeout((short)5)
.setMatch(match)
.setActions(actions)
.setOutPort(OFPort.of(3))
.setBufferId(OFBufferId.NO_BUFFER)
.setCookie(U64.of(2L << 52).or(U64.of(4 << Forwarding.FLOWSET_SHIFT)))
.setPriority(1)
.build();
// Record expected packet-outs/flow-mods
expect(sw1.write(capture(wc1))).andReturn(true).once();
expect(sw1.write(capture(wc2))).andReturn(true).once();
reset(topology);
expect(topology.isBroadcastAllowed(DatapathId.of(anyLong()), OFPort.of(anyShort()))).andReturn(true).anyTimes();
expect(topology.getClusterId(DatapathId.of(1L))).andReturn(DatapathId.of(1L)).anyTimes();
expect(topology.isAttachmentPointPort(DatapathId.of(1L), OFPort.of(1))).andReturn(true).anyTimes();
expect(topology.isAttachmentPointPort(DatapathId.of(1L), OFPort.of(3))).andReturn(true).anyTimes();
expect(topology.isEdge(DatapathId.of(1L), OFPort.of(1))).andReturn(true).anyTimes();
expect(topology.isEdge(DatapathId.of(1L), OFPort.of(3))).andReturn(true).anyTimes();
// Reset mocks, trigger the packet in, and validate results
replay(sw1, sw2, routingEngine, topology);
forwarding.receive(sw1, this.packetIn, cntx);
verify(sw1, sw2, routingEngine);
assertTrue(wc1.hasCaptured());
assertTrue(wc2.hasCaptured());
assertTrue(wc1.getValue().equalsIgnoreXid(fm1));
assertTrue(wc2.getValue().equalsIgnoreXid(packetOut));
}
@Test
public void testForwardDecisionForwardingCookieNotZero() throws Exception {
learnDevices(DestDeviceToLearn.DEVICE2);
Capture<OFMessage> wc1 = EasyMock.newCapture(CaptureType.ALL);
Capture<OFMessage> wc2 = EasyMock.newCapture(CaptureType.ALL);
Path path = new Path(DatapathId.of(1L), DatapathId.of(1L));
path.getPath().add(new NodePortTuple(DatapathId.of(1L), OFPort.of(1)));
path.getPath().add(new NodePortTuple(DatapathId.of(1L), OFPort.of(3)));
reset(routingEngine);
expect(routingEngine.getPath(DatapathId.of(1L), OFPort.of(1), DatapathId.of(1L), OFPort.of(3))).andReturn(path).atLeastOnce();
// Expected Flow-mods
Match match = packetIn.getMatch();
OFActionOutput action = factory.actions().output(OFPort.of(3), Integer.MAX_VALUE);
List<OFAction> actions = new ArrayList<OFAction>();
actions.add(action);
RoutingDecision decision = new RoutingDecision(DatapathId.of(1L), OFPort.of(1), dstDevice1, RoutingAction.FORWARD);
decision.setDescriptor(U64.of(0x00000000ffffffffL));
decision.addToContext(cntx);
//RoutingDecision de2 = (RoutingDecision) RoutingDecision.rtStore.get(cntx, IRoutingDecision.CONTEXT_DECISION); // Same as decision
//(DatapathId swDipd, OFPort inPort, IDevice srcDevice, RoutingAction action);
OFFlowMod fm1 = factory.buildFlowAdd()
.setIdleTimeout((short)5)
.setMatch(match)
.setActions(actions)
.setOutPort(OFPort.of(3))
.setBufferId(OFBufferId.NO_BUFFER)
.setCookie(U64.of(2L << 52).or(U64.of(4 << Forwarding.FLOWSET_SHIFT).or(U64.of(0xFFffFFL))))
.setPriority(1)
.build();
// Record expected packet-outs/flow-mods
expect(sw1.write(capture(wc1))).andReturn(true).once();
expect(sw1.write(capture(wc2))).andReturn(true).once();
reset(topology);
expect(topology.isBroadcastAllowed(DatapathId.of(anyLong()), OFPort.of(anyShort()))).andReturn(true).anyTimes();
expect(topology.getClusterId(DatapathId.of(1L))).andReturn(DatapathId.of(1L)).anyTimes();
expect(topology.isAttachmentPointPort(DatapathId.of(1L), OFPort.of(1))).andReturn(true).anyTimes();
expect(topology.isAttachmentPointPort(DatapathId.of(1L), OFPort.of(3))).andReturn(true).anyTimes();
expect(topology.isEdge(DatapathId.of(1L), OFPort.of(1))).andReturn(true).anyTimes();
expect(topology.isEdge(DatapathId.of(1L), OFPort.of(3))).andReturn(true).anyTimes();
// Reset mocks, trigger the packet in, and validate results
replay(sw1, sw2, routingEngine, topology);
forwarding.receive(sw1, this.packetIn, cntx);
verify(sw1, sw2, routingEngine);
assertTrue(wc1.hasCaptured());
assertTrue(wc2.hasCaptured());
assertTrue(wc1.getValue().equalsIgnoreXid(fm1));
assertTrue(wc2.getValue().equalsIgnoreXid(packetOut));
}
@Test
public void testForwardDeleteFlowsByDescriptorSingle() throws Exception {
reset(routingEngine);
Capture<List<OFMessage>> wc1 = EasyMock.newCapture(CaptureType.ALL);
Capture<List<OFMessage>> wc2 = EasyMock.newCapture(CaptureType.ALL);
List<Masked<U64>> descriptors = new ArrayList<Masked<U64>>();
descriptors.add(Masked.of(
U64.of(0x00000000FFffFFffL),
U64.of(0x00200000FFffFFffL))); // User mask = 0xffFFffFFL which is forwarding.DECISION_MASK/AppCookie.USER_MASK//descriptors.add(Masked.of(U64.of(0x00000000FFffFFffL),U64.of(0x0020000000000000L)));//descriptors.add(Masked.of(U64.of(0xffFFffFFffFFffFFL),U64.of(0x00200000FFffFFffL))); // Mask = 0xffFFffFFffFFffFFL which is the value returned by forwarding.AppCookie.getAppFieldMask()//descriptors.add(Masked.of(U64.of(0xffFFffFFffFFffFFL),U64.of(0x0020000000000000L)));
expect(sw1.getStatus()).andReturn(IOFSwitch.SwitchStatus.MASTER).anyTimes();
expect(sw2.getStatus()).andReturn(IOFSwitch.SwitchStatus.MASTER).anyTimes();
expect(sw1.write(capture(wc1))).andReturn(ImmutableList.of()).once();
expect(sw2.write(capture(wc2))).andReturn(ImmutableList.of()).once();
replay(sw1, sw2, routingEngine);
forwarding.deleteFlowsByDescriptor(descriptors);
verify(sw1, sw2, routingEngine);
assertTrue(wc1.hasCaptured());
assertTrue(wc2.hasCaptured());
Masked<U64> masked_cookie = Masked.of(
AppCookie.makeCookie(Forwarding.FORWARDING_APP_ID, (int)4294967295L),
AppCookie.getAppFieldMask().or(U64.of(0xffffffL)));
List<OFMessage> msgs_test = new ArrayList<>();
msgs_test.add( factory.buildFlowDelete()
.setCookie(masked_cookie.getValue())
.setCookieMask(masked_cookie.getMask())
.build());
assertTrue(messageListsEqualIgnoreXid(wc1.getValue(), msgs_test));
assertTrue(messageListsEqualIgnoreXid(wc2.getValue(), msgs_test));
}
@Test
public void testForwardDeleteFlowsByDescriptorMultiple() throws Exception {
reset(routingEngine);
Capture<List<OFMessage>> wc1 = EasyMock.newCapture(CaptureType.ALL);
Capture<List<OFMessage>> wc2 = EasyMock.newCapture(CaptureType.ALL);
List<Masked<U64>> descriptors = new ArrayList<Masked<U64>>();
descriptors.add(Masked.of(
U64.of(0x0000000000ffFFffL),
U64.of(0x0020000000ffFFffL))); // User mask = 0xffFFffFFL which is forwarding.DECISION_MASK/AppCookie.USER_MASK
descriptors.add(Masked.of(
U64.of(0x0000000000ffFFffL),
U64.of(0x0020000000000000L)));
expect(sw1.getStatus()).andReturn(IOFSwitch.SwitchStatus.MASTER).anyTimes();
expect(sw2.getStatus()).andReturn(IOFSwitch.SwitchStatus.MASTER).anyTimes();
expect(sw1.write(capture(wc1))).andReturn(ImmutableList.of()).once();
expect(sw2.write(capture(wc2))).andReturn(ImmutableList.of()).once();
replay(sw1, sw2, routingEngine);
forwarding.deleteFlowsByDescriptor(descriptors);
verify(sw1, sw2, routingEngine);
assertTrue(wc1.hasCaptured());
assertTrue(wc2.hasCaptured());
// Cookies
Masked<U64> masked_cookie = Masked.of( AppCookie.makeCookie(Forwarding.FORWARDING_APP_ID, (int)4294967295L),
AppCookie.getAppFieldMask().or(U64.of(0xffffffL)));
Masked<U64> masked_cookie2 = Masked.of( AppCookie.makeCookie(Forwarding.FORWARDING_APP_ID, 0),
AppCookie.getAppFieldMask().or(U64.of(0x0L)));
// Add cookies to a msg set
List<OFMessage> msgs_test = new ArrayList<OFMessage>();
msgs_test.add( factory.buildFlowDelete()
.setCookie(masked_cookie.getValue())
.setCookieMask(masked_cookie.getMask())
.build());
msgs_test.add( factory.buildFlowDelete()
.setCookie(masked_cookie2.getValue())
.setCookieMask(masked_cookie2.getMask())
.build());
assertTrue(messageListsEqualIgnoreXid(wc1.getValue(), msgs_test));
assertTrue(messageListsEqualIgnoreXid(wc2.getValue(), msgs_test));
}
@Test
public void testForwardDeleteFlowsByDescriptorNoCookies() throws Exception {
reset(routingEngine);
List<Masked<U64>> descriptors = new ArrayList<Masked<U64>>();
replay(routingEngine);
forwarding.deleteFlowsByDescriptor(descriptors);
verify(routingEngine);
}
@Test
public void testForwardDeleteFlowsByDescriptorNoCookiesContainer() throws Exception {
reset(routingEngine);
List<Masked<U64>> descriptors = null;
replay(routingEngine);
forwarding.deleteFlowsByDescriptor(descriptors);
verify(routingEngine);
}
}