/* * 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.forwarding; import static org.easymock.EasyMock.anyBoolean; import static org.easymock.EasyMock.anyObject; import static org.easymock.EasyMock.anyShort; import static org.easymock.EasyMock.capture; import static org.easymock.EasyMock.createMock; import static org.easymock.EasyMock.createNiceMock; import static org.easymock.EasyMock.expect; import static org.easymock.EasyMock.expectLastCall; import static org.easymock.EasyMock.replay; import static org.easymock.EasyMock.verify; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertTrue; import java.util.ArrayList; import java.util.Date; import java.util.HashMap; import java.util.List; import java.util.Map; 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.OFMatch; import org.openflow.protocol.OFMessage; import org.openflow.protocol.OFPacketIn; import org.openflow.protocol.OFPacketOut; 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.sdnplatform.IBetterOFSwitch; import org.sdnplatform.addressspace.IAddressSpaceManagerService; import org.sdnplatform.core.ListenerContext; import org.sdnplatform.core.IControllerService; import org.sdnplatform.core.IOFSwitch; import org.sdnplatform.core.module.ModuleContext; import org.sdnplatform.core.test.MockControllerProvider; import org.sdnplatform.core.test.MockThreadPoolService; 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.IFlowCacheService; import org.sdnplatform.flowcache.IFlowReconcileService; import org.sdnplatform.forwarding.Forwarding; import org.sdnplatform.forwarding.IRewriteService; import org.sdnplatform.linkdiscovery.ILinkDiscovery; import org.sdnplatform.linkdiscovery.ILinkDiscoveryService; import org.sdnplatform.netvirt.core.VNS; import org.sdnplatform.netvirt.core.VNSInterface; import org.sdnplatform.netvirt.manager.INetVirtManagerService; 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.routing.ForwardingBase; import org.sdnplatform.routing.IRoutingDecision; import org.sdnplatform.routing.IRoutingService; import org.sdnplatform.routing.Route; import org.sdnplatform.routing.RouteId; import org.sdnplatform.storage.IStorageSourceService; import org.sdnplatform.storage.memory.MemoryStorageSource; import org.sdnplatform.threadpool.IThreadPoolService; import org.sdnplatform.topology.BetterTopologyManager; import org.sdnplatform.topology.ITopologyService; import org.sdnplatform.topology.NodePortTuple; import org.sdnplatform.tunnelmanager.ITunnelManagerService; public class MultipathForwardingTest { protected MockControllerProvider mockControllerProvider; protected ListenerContext cntx; protected MockThreadPoolService threadPool; protected MockDeviceManager deviceManager; protected IRoutingService routingEngine; protected BetterTopologyManager topology; protected ITunnelManagerService tunnelManager; protected Forwarding forwarding; protected IFlowReconcileService flowReconcileMgr; protected IRewriteService rewriteService; protected IRestApiService restApi; protected ILinkDiscoveryService linkDiscovery; protected IAddressSpaceManagerService addressSpaceMgr; protected IOFSwitch sw1, sw2, sw3; // swithes for use in multi-action packet out for netVirt-broadcast protected Capture<OFMessage> wc1, wc2, wc3; // Capture writes to switches protected Capture<ListenerContext> fc1, fc2, fc3; // Capture writes to switches protected IDevice srcDevice; protected IDevice mpathDstDevice1, mpathDstDevice2, mpathDstDevice3, mpathDstDevice4; protected ArrayList<IDevice> dstDevices; protected OFPacketIn mpathPacketIn1, mpathPacketIn2, mpathPacketIn3, mpathPacketIn4; protected OFPacketOut mpathPacketOut1, mpathPacketOut2, mpathPacketOut3, mpathPacketOut4; protected IPacket testMpathPacket1, testMpathPacket2, testMpathPacket3, testMpathPacket4; protected byte[] testMpathPacket1Serialized, testMpathPacket2Serialized, testMpathPacket3Serialized, testMpathPacket4Serialized; protected IRoutingDecision decision; protected int fastWildcards; protected int expected_wildcards; protected Date currentDate; protected int DIRECT_LINK = 1; protected int MULTIHOP_LINK = 2; protected int TUNNEL_LINK = 3; @Before public void setUp() throws Exception { // Mock context cntx = new ListenerContext(); mockControllerProvider = new MockControllerProvider(); forwarding = new Forwarding(); threadPool = new MockThreadPoolService(); deviceManager = new MockDeviceManager(); routingEngine = createMock(IRoutingService.class); topology = new BetterTopologyManager(); tunnelManager = createMock(ITunnelManagerService.class); flowReconcileMgr = createMock(IFlowReconcileService.class); rewriteService = createNiceMock(IRewriteService.class); restApi = createNiceMock(IRestApiService.class); addressSpaceMgr = createMock(IAddressSpaceManagerService.class); DefaultEntityClassifier entityClassifier = new DefaultEntityClassifier(); linkDiscovery = EasyMock.createMock(ILinkDiscoveryService.class); BetterFlowCache betterFlowCacheMgr = new BetterFlowCache(); betterFlowCacheMgr.setAppName("netVirt"); ModuleContext fmc = new ModuleContext(); fmc.addService(IControllerService.class, mockControllerProvider); fmc.addService(ITopologyService.class, topology); fmc.addService(IThreadPoolService.class, threadPool); fmc.addService(IRoutingService.class, routingEngine); fmc.addService(ICounterStoreService.class, new CounterStore()); fmc.addService(IDeviceService.class, deviceManager); fmc.addService(IFlowCacheService.class, betterFlowCacheMgr); fmc.addService(ITunnelManagerService.class, tunnelManager); fmc.addService(IFlowReconcileService.class, flowReconcileMgr); fmc.addService(IRewriteService.class, rewriteService); fmc.addService(IRestApiService.class, restApi); fmc.addService(IAddressSpaceManagerService.class, addressSpaceMgr); fmc.addService(IEntityClassifierService.class, entityClassifier); fmc.addService(ILinkDiscoveryService.class, linkDiscovery); fmc.addService(IStorageSourceService.class, new MemoryStorageSource()); topology.init(fmc); deviceManager.init(fmc); betterFlowCacheMgr.init(fmc); threadPool.init(fmc); forwarding.init(fmc); entityClassifier.init(fmc); threadPool.startUp(fmc); deviceManager.startUp(fmc); betterFlowCacheMgr.startUp(fmc); forwarding.startUp(fmc); entityClassifier.startUp(fmc); // Mock tunnel service expect(tunnelManager.isTunnelEndpoint(anyObject(IDevice.class))) .andReturn(true).anyTimes(); expect(tunnelManager.isTunnelEndpoint(null)).andReturn(true).anyTimes(); expect(tunnelManager.getTunnelPortNumber(EasyMock.anyLong())).andReturn(null).anyTimes(); expect(tunnelManager.getTunnelLoopbackPort(EasyMock.anyLong())).andReturn(null).anyTimes(); replay(tunnelManager); int [][] linkArray = { {1, 3, 2, 1, DIRECT_LINK}, {1, 4, 2, 2, DIRECT_LINK}, {2, 3, 3, 1, DIRECT_LINK}, {2, 4, 3, 2, DIRECT_LINK} }; expect(linkDiscovery.isTunnelPort(1L, (short)1)).andReturn(false).anyTimes(); expect(linkDiscovery.isTunnelPort(1L, (short)3)).andReturn(false).anyTimes(); expect(linkDiscovery.isTunnelPort(1L, (short)4)).andReturn(false).anyTimes(); expect(linkDiscovery.isTunnelPort(2L, (short)1)).andReturn(false).anyTimes(); expect(linkDiscovery.isTunnelPort(2L, (short)2)).andReturn(false).anyTimes(); expect(linkDiscovery.isTunnelPort(2L, (short)3)).andReturn(false).anyTimes(); expect(linkDiscovery.isTunnelPort(2L, (short)4)).andReturn(false).anyTimes(); expect(linkDiscovery.isTunnelPort(3L, (short)1)).andReturn(false).anyTimes(); expect(linkDiscovery.isTunnelPort(3L, (short)2)).andReturn(false).anyTimes(); expect(linkDiscovery.isTunnelPort(3L, (short)3)).andReturn(false).anyTimes(); expect(linkDiscovery.isTunnelPort(3L, (short)4)).andReturn(false).anyTimes(); replay(linkDiscovery); ILinkDiscovery.LinkType type = ILinkDiscovery.LinkType.DIRECT_LINK; for (int i = 0; i < linkArray.length; i++) { int [] r = linkArray[i]; if (r[4] == DIRECT_LINK) type= ILinkDiscovery.LinkType.DIRECT_LINK; else if (r[4] == MULTIHOP_LINK) type= ILinkDiscovery.LinkType.MULTIHOP_LINK; else if (r[4] == TUNNEL_LINK) type = ILinkDiscovery.LinkType.TUNNEL; topology.addOrUpdateLink(r[0], (short)r[1], r[2], (short)r[3], type); } topology.createNewInstance(); topology.updateTopology(); // Mock switches sw1 = EasyMock.createMock(IOFSwitch.class); expect(sw1.getId()).andReturn(1L).anyTimes(); expect(sw1.getStringId()).andReturn("00:00:00:00:00:00:00:01").anyTimes(); expect(sw1.attributeEquals(IBetterOFSwitch.SUPPORTS_NX_TTL_DECREMENT, true)) .andReturn(false).anyTimes(); sw2 = EasyMock.createMock(IOFSwitch.class); expect(sw2.getId()).andReturn(2L).anyTimes(); expect(sw2.getStringId()).andReturn("00:00:00:00:00:00:00:02").anyTimes(); expect(sw2.attributeEquals(IBetterOFSwitch.SUPPORTS_NX_TTL_DECREMENT, true)) .andReturn(false).anyTimes(); sw3 = EasyMock.createMock(IOFSwitch.class); expect(sw3.getId()).andReturn(3L).anyTimes(); expect(sw3.getStringId()).andReturn("00:00:00:00:00:00:00:03").anyTimes(); expect(sw3.attributeEquals(IBetterOFSwitch.SUPPORTS_NX_TTL_DECREMENT, true)) .andReturn(false).anyTimes(); wc1 = new Capture<OFMessage>(CaptureType.ALL); //capture message on switch 1. wc2 = new Capture<OFMessage>(CaptureType.ALL); wc3 = new Capture<OFMessage>(CaptureType.ALL); fc1 = new Capture<ListenerContext>(CaptureType.ALL); fc2 = new Capture<ListenerContext>(CaptureType.ALL); fc3 = new Capture<ListenerContext>(CaptureType.ALL); //fastWilcards mocked as this constant fastWildcards = OFMatch.OFPFW_IN_PORT | OFMatch.OFPFW_NW_PROTO | OFMatch.OFPFW_TP_SRC | OFMatch.OFPFW_TP_DST | OFMatch.OFPFW_NW_SRC_ALL | OFMatch.OFPFW_NW_DST_ALL | OFMatch.OFPFW_NW_TOS; // for netVirt-broadcast multi-action packet expect(sw1.getAttribute(IOFSwitch.PROP_FASTWILDCARDS)).andReturn(fastWildcards).anyTimes(); expect(sw1.hasAttribute(IOFSwitch.PROP_FASTWILDCARDS)).andReturn(true).anyTimes(); expect(sw1.hasAttribute(IOFSwitch.PROP_REQUIRES_L3_MATCH)).andReturn(true).anyTimes(); expect(sw1.hasAttribute(IOFSwitch.PROP_SUPPORTS_OFPP_TABLE)).andReturn(true).anyTimes(); expect(sw1.hasAttribute(IOFSwitch.PROP_SUPPORTS_OFPP_FLOOD)).andReturn(true).anyTimes(); expect(sw1.portEnabled(EasyMock.anyShort())).andReturn(true).anyTimes(); expect(sw2.getAttribute(IOFSwitch.PROP_FASTWILDCARDS)).andReturn(fastWildcards).anyTimes(); expect(sw2.hasAttribute(IOFSwitch.PROP_FASTWILDCARDS)).andReturn(true).anyTimes(); expect(sw2.hasAttribute(IOFSwitch.PROP_REQUIRES_L3_MATCH)).andReturn(true).anyTimes(); expect(sw2.hasAttribute(IOFSwitch.PROP_SUPPORTS_OFPP_TABLE)).andReturn(true).anyTimes(); expect(sw2.hasAttribute(IOFSwitch.PROP_SUPPORTS_OFPP_FLOOD)).andReturn(true).anyTimes(); expect(sw2.portEnabled(EasyMock.anyShort())).andReturn(true).anyTimes(); expect(sw3.getAttribute(IOFSwitch.PROP_FASTWILDCARDS)).andReturn(fastWildcards).anyTimes(); expect(sw3.hasAttribute(IOFSwitch.PROP_FASTWILDCARDS)).andReturn(true).anyTimes(); expect(sw3.hasAttribute(IOFSwitch.PROP_REQUIRES_L3_MATCH)).andReturn(true).anyTimes(); expect(sw3.hasAttribute(IOFSwitch.PROP_SUPPORTS_OFPP_TABLE)).andReturn(true).anyTimes(); expect(sw3.hasAttribute(IOFSwitch.PROP_SUPPORTS_OFPP_FLOOD)).andReturn(true).anyTimes(); expect(sw3.portEnabled(EasyMock.anyShort())).andReturn(true).anyTimes(); sw1.write(capture(wc1), capture(fc1)); expectLastCall().anyTimes(); sw2.write(capture(wc2), capture(fc2)); expectLastCall().anyTimes(); sw3.write(capture(wc3), capture(fc3)); expectLastCall().anyTimes(); replay(sw1, sw2, sw3); // 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); // Build test packets for multipath tests testMpathPacket1 = new Ethernet() .setDestinationMACAddress("00:11:22:33:44:55") .setSourceMACAddress("00:44:33:22:11:00") .setEtherType(Ethernet.TYPE_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})))); testMpathPacket1Serialized = testMpathPacket1.serialize(); testMpathPacket2 = new Ethernet() .setDestinationMACAddress("00:11:22:33:44:56") .setSourceMACAddress("00:44:33:22:11:00") .setEtherType(Ethernet.TYPE_IPv4) .setPayload( new IPv4() .setTtl((byte) 128) .setSourceAddress("192.168.1.1") .setDestinationAddress("192.168.1.3") .setPayload(new UDP() .setSourcePort((short) 5000) .setDestinationPort((short) 5001) .setPayload(new Data(new byte[] {0x01})))); testMpathPacket2Serialized = testMpathPacket2.serialize(); testMpathPacket3 = new Ethernet() .setDestinationMACAddress("00:11:22:33:44:57") .setSourceMACAddress("00:44:33:22:11:00") .setEtherType(Ethernet.TYPE_IPv4) .setPayload( new IPv4() .setTtl((byte) 128) .setSourceAddress("192.168.1.1") .setDestinationAddress("192.168.1.4") .setPayload(new UDP() .setSourcePort((short) 5000) .setDestinationPort((short) 5001) .setPayload(new Data(new byte[] {0x01})))); testMpathPacket3Serialized = testMpathPacket3.serialize(); testMpathPacket4 = new Ethernet() .setDestinationMACAddress("00:11:22:33:44:59") .setSourceMACAddress("00:44:33:22:11:00") .setEtherType(Ethernet.TYPE_IPv4) .setPayload( new IPv4() .setTtl((byte) 128) .setSourceAddress("192.168.1.1") .setDestinationAddress("192.168.1.5") .setPayload(new UDP() .setSourcePort((short) 5000) .setDestinationPort((short) 5001) .setPayload(new Data(new byte[] {0x01})))); testMpathPacket4Serialized = testMpathPacket4.serialize(); // Build multipath test src and dest devices byte[] mpathDataLayerSource = ((Ethernet)testMpathPacket1).getSourceMACAddress(); int mpathNetworkSource = ((IPv4)((Ethernet)testMpathPacket1).getPayload()).getSourceAddress(); byte[] mpathDataLayerDest1 = ((Ethernet)testMpathPacket1).getDestinationMACAddress(); int mpathNetworkDest1 = ((IPv4)((Ethernet)testMpathPacket1).getPayload()).getDestinationAddress(); byte[] mpathDataLayerDest2 = ((Ethernet)testMpathPacket2).getDestinationMACAddress(); int mpathNetworkDest2 = ((IPv4)((Ethernet)testMpathPacket2).getPayload()).getDestinationAddress(); byte[] mpathDataLayerDest3 = ((Ethernet)testMpathPacket3).getDestinationMACAddress(); int mpathNetworkDest3 = ((IPv4)((Ethernet)testMpathPacket3).getPayload()).getDestinationAddress(); byte[] mpathDataLayerDest4 = ((Ethernet)testMpathPacket4).getDestinationMACAddress(); int mpathNetworkDest4 = ((IPv4)((Ethernet)testMpathPacket4).getPayload()).getDestinationAddress(); srcDevice = deviceManager.learnEntity(Ethernet.toLong(mpathDataLayerSource), null, mpathNetworkSource, 1L, 1); mpathDstDevice1 = deviceManager.learnEntity(Ethernet.toLong(mpathDataLayerDest1), null, mpathNetworkDest1, 2L, 3); mpathDstDevice2 = deviceManager.learnEntity(Ethernet.toLong(mpathDataLayerDest2), null, mpathNetworkDest2, 2L, 4); mpathDstDevice3 = deviceManager.learnEntity(Ethernet.toLong(mpathDataLayerDest3), null, mpathNetworkDest3, 3L, 3); mpathDstDevice4 = deviceManager.learnEntity(Ethernet.toLong(mpathDataLayerDest4), null, mpathNetworkDest4, 3L, 4); // Mock multipath PacketIns mpathPacketIn1 = ((OFPacketIn) mockControllerProvider.getOFMessageFactory().getMessage(OFType.PACKET_IN)) .setBufferId(-1) .setInPort((short) 1) .setPacketData(testMpathPacket1Serialized) .setReason(OFPacketInReason.NO_MATCH) .setTotalLength((short) testMpathPacket1Serialized.length); mpathPacketIn2 = ((OFPacketIn) mockControllerProvider.getOFMessageFactory().getMessage(OFType.PACKET_IN)) .setBufferId(-1) .setInPort((short) 1) .setPacketData(testMpathPacket2Serialized) .setReason(OFPacketInReason.NO_MATCH) .setTotalLength((short) testMpathPacket2Serialized.length); mpathPacketIn3 = ((OFPacketIn) mockControllerProvider.getOFMessageFactory().getMessage(OFType.PACKET_IN)) .setBufferId(-1) .setInPort((short) 1) .setPacketData(testMpathPacket3Serialized) .setReason(OFPacketInReason.NO_MATCH) .setTotalLength((short) testMpathPacket3Serialized.length); mpathPacketIn4 = ((OFPacketIn) mockControllerProvider.getOFMessageFactory().getMessage(OFType.PACKET_IN)) .setBufferId(-1) .setInPort((short) 1) .setPacketData(testMpathPacket4Serialized) .setReason(OFPacketInReason.NO_MATCH) .setTotalLength((short) testMpathPacket4Serialized.length); // Mock multipath PacketOuts mpathPacketOut1 = (OFPacketOut) mockControllerProvider.getOFMessageFactory().getMessage(OFType.PACKET_OUT); mpathPacketOut1.setBufferId(this.mpathPacketIn1.getBufferId()) .setInPort(this.mpathPacketIn1.getInPort()); List<OFAction> poactions1 = new ArrayList<OFAction>(); poactions1.add(new OFActionOutput((short)3, (short) 0xffff)); mpathPacketOut1.setActions(poactions1) .setActionsLength((short) OFActionOutput.MINIMUM_LENGTH) .setPacketData(testMpathPacket1Serialized) .setLengthU(OFPacketOut.MINIMUM_LENGTH+mpathPacketOut1.getActionsLength()+testMpathPacket1Serialized.length); mpathPacketOut2 = (OFPacketOut) mockControllerProvider.getOFMessageFactory().getMessage(OFType.PACKET_OUT); mpathPacketOut2.setBufferId(this.mpathPacketIn2.getBufferId()) .setInPort(this.mpathPacketIn2.getInPort()); List<OFAction> poactions2 = new ArrayList<OFAction>(); poactions2.add(new OFActionOutput((short)4, (short) 0xffff)); mpathPacketOut2.setActions(poactions2) .setActionsLength((short) OFActionOutput.MINIMUM_LENGTH) .setPacketData(testMpathPacket2Serialized) .setLengthU(OFPacketOut.MINIMUM_LENGTH+mpathPacketOut2.getActionsLength()+testMpathPacket2Serialized.length); mpathPacketOut3 = (OFPacketOut) mockControllerProvider.getOFMessageFactory().getMessage(OFType.PACKET_OUT); mpathPacketOut3.setBufferId(this.mpathPacketIn3.getBufferId()) .setInPort(this.mpathPacketIn3.getInPort()); List<OFAction> poactions3 = new ArrayList<OFAction>(); poactions3.add(new OFActionOutput((short)3, (short) 0xffff)); mpathPacketOut3.setActions(poactions3) .setActionsLength((short) OFActionOutput.MINIMUM_LENGTH) .setPacketData(testMpathPacket3Serialized) .setLengthU(OFPacketOut.MINIMUM_LENGTH+mpathPacketOut3.getActionsLength()+testMpathPacket3Serialized.length); mpathPacketOut4 = (OFPacketOut) mockControllerProvider.getOFMessageFactory().getMessage(OFType.PACKET_OUT); mpathPacketOut4.setBufferId(this.mpathPacketIn4.getBufferId()) .setInPort(this.mpathPacketIn4.getInPort()); List<OFAction> poactions4 = new ArrayList<OFAction>(); poactions4.add(new OFActionOutput((short)4, (short) 0xffff)); mpathPacketOut4.setActions(poactions2) .setActionsLength((short) OFActionOutput.MINIMUM_LENGTH) .setPacketData(testMpathPacket4Serialized) .setLengthU(OFPacketOut.MINIMUM_LENGTH+mpathPacketOut4.getActionsLength()+testMpathPacket4Serialized.length); expected_wildcards = fastWildcards; expected_wildcards &= ~OFMatch.OFPFW_IN_PORT & ~OFMatch.OFPFW_DL_VLAN & ~OFMatch.OFPFW_DL_SRC & ~OFMatch.OFPFW_DL_DST; expected_wildcards &= ~OFMatch.OFPFW_DL_TYPE & ~OFMatch.OFPFW_NW_SRC_MASK & ~OFMatch.OFPFW_NW_DST_MASK; // Mock decision decision = createMock(IRoutingDecision.class); expect(decision.getSourceDevice()).andReturn(srcDevice).atLeastOnce(); expect(decision.getSourcePort()).andReturn(new SwitchPort(1L, (short)1)).atLeastOnce(); dstDevices = new ArrayList<IDevice>(); expect(decision.getDestinationDevices()).andReturn(dstDevices).atLeastOnce(); IRoutingDecision.rtStore.put(cntx, IRoutingDecision.CONTEXT_DECISION, decision); IDeviceService.fcStore. put(cntx, IDeviceService.CONTEXT_SRC_DEVICE, srcDevice); // set decision.getRoutingAction() based on test case // Set SRC_IFACCES in context List<VNSInterface> srcIfaces = new ArrayList<VNSInterface>(); VNS netVirt = new VNS("default"); srcIfaces.add(new VNSInterface("testSrcIface1", netVirt, null, null)); INetVirtManagerService.bcStore.put(cntx, INetVirtManagerService.CONTEXT_SRC_IFACES, srcIfaces); // Mock default behavior for getSwitchPortVlanMode expect(rewriteService.getSwitchPortVlanMode(anyObject(SwitchPort.class), anyObject(String.class), anyShort(), anyBoolean())) .andReturn(Ethernet.VLAN_UNTAGGED).anyTimes(); replay(rewriteService); } @After public void tearDown() { verify(tunnelManager); } @Test public void testMultipathDualLinkBetweenTwoSwitches() throws Exception { // Mock decision expect(decision.getRoutingAction()).andReturn(IRoutingDecision.RoutingAction.FORWARD).atLeastOnce(); expect(decision.getWildcards()).andReturn(null).atLeastOnce(); expect(decision.getHardTimeout()). andReturn(ForwardingBase.FLOWMOD_DEFAULT_HARD_TIMEOUT).atLeastOnce(); // Set destination and Mock route dstDevices.add(mpathDstDevice1); // Expected Flow-mods // first packet in to mpathDstDevice1 OFMatch match = new OFMatch(); match.loadFromPacket(testMpathPacket1Serialized, (short) 1); OFActionOutput action = new OFActionOutput((short)3, (short)0xffff); List<OFAction> actions = new ArrayList<OFAction>(); actions.add(action); OFFlowMod fm1a = (OFFlowMod) mockControllerProvider.getOFMessageFactory().getMessage(OFType.FLOW_MOD); fm1a.setIdleTimeout((short)5) .setPriority(forwarding.getAccessPriority()) .setMatch(match.clone() .setWildcards(expected_wildcards)) .setActions(actions) .setBufferId(OFPacketOut.BUFFER_ID_NONE) .setCookie(2L << 52) .setLengthU(OFFlowMod.MINIMUM_LENGTH+OFActionOutput.MINIMUM_LENGTH); OFFlowMod fm2a = fm1a.clone(); fm1a.setFlags((short)1); // set flow-mod-removal flag on src switch only // second packet in to mpathDstDevice2 match = new OFMatch(); match.loadFromPacket(testMpathPacket2Serialized, (short) 1); action = new OFActionOutput((short)4, (short)0xffff); actions = new ArrayList<OFAction>(); actions.add(action); OFFlowMod fm1b = (OFFlowMod) mockControllerProvider.getOFMessageFactory().getMessage(OFType.FLOW_MOD); fm1b.setIdleTimeout((short)5) .setPriority(forwarding.getAccessPriority()) .setMatch(match.clone() .setWildcards(expected_wildcards)) .setActions(actions) .setBufferId(OFPacketOut.BUFFER_ID_NONE) .setCookie(2L << 52) .setLengthU(OFFlowMod.MINIMUM_LENGTH+OFActionOutput.MINIMUM_LENGTH); OFFlowMod fm2b = fm1b.clone(); fm2b.getMatch().setInputPort((short) 2); fm1b.setFlags((short)1); // set flow-mod-removal flag on src switch only long cookie1 = forwarding.getHashByMac(mpathDstDevice1.getMACAddress()); RouteId routeId1 = new RouteId(1L, 2L, cookie1); Route route1 = new Route(routeId1, new ArrayList<NodePortTuple>()); route1.getPath().add(new NodePortTuple(1L, (short)1)); route1.getPath().add(new NodePortTuple(1L, (short)3)); route1.getPath().add(new NodePortTuple(2L, (short)1)); route1.getPath().add(new NodePortTuple(2L, (short)3)); expect(routingEngine.getRoute(1L, (short)1, 2L, (short)3, cookie1, false)).andReturn(route1).anyTimes(); long cookie2 = forwarding.getHashByMac(mpathDstDevice2.getMACAddress()); RouteId routeId2 = new RouteId(1L, 2L, cookie2); Route route2 = new Route(routeId2, new ArrayList<NodePortTuple>()); route2.getPath().add(new NodePortTuple(1L, (short)1)); route2.getPath().add(new NodePortTuple(1L, (short)4)); route2.getPath().add(new NodePortTuple(2L, (short)2)); route2.getPath().add(new NodePortTuple(2L, (short)4)); expect(routingEngine.getRoute(1L, (short)1, 2L, (short)4, cookie2, false)).andReturn(route2).anyTimes(); replay(routingEngine, decision); forwarding.receive(sw1, this.mpathPacketIn1, cntx); verify(sw1); verify(sw2); verify(routingEngine); verify(decision); verify(linkDiscovery); assertTrue(wc1.hasCaptured()); // wc1 should get packetout + flowmod. assertTrue(wc2.hasCaptured()); // wc2 should be a flowmod. List<OFMessage> msglist = wc1.getValues(); for (OFMessage m1: msglist) { if (m1 instanceof OFPacketOut) assertEquals(m1, mpathPacketOut1); else if (m1 instanceof OFFlowMod) assertEquals(m1, fm1a); } OFMessage m1 = wc2.getValue(); assert (m1 instanceof OFFlowMod); assertTrue(m1.equals(fm2a)); wc1.reset(); wc2.reset(); // Set destination and Mock route dstDevices.clear(); dstDevices.add(mpathDstDevice2); forwarding.receive(sw1, this.mpathPacketIn2, cntx); verify(sw1); verify(sw2); verify(routingEngine); verify(decision); verify(linkDiscovery); assertTrue(wc1.hasCaptured()); // wc1 should get packetout + flowmod. assertTrue(wc2.hasCaptured()); // wc2 should be a flowmod. msglist = wc1.getValues(); for (OFMessage m2: msglist) { if (m2 instanceof OFPacketOut) assertEquals(m2, mpathPacketOut2); else if (m2 instanceof OFFlowMod) assertEquals(m2, fm1b); } OFMessage m2 = wc2.getValue(); assert (m2 instanceof OFFlowMod); assertEquals(m2, fm2b); } @Test public void testMultipathDualLinkBetweenThreeSwitches() throws Exception { // Mock decision expect(decision.getRoutingAction()).andReturn(IRoutingDecision.RoutingAction.FORWARD).atLeastOnce(); expect(decision.getWildcards()).andReturn(null).atLeastOnce(); expect(decision.getHardTimeout()). andReturn(ForwardingBase.FLOWMOD_DEFAULT_HARD_TIMEOUT).atLeastOnce(); // Set destination and Mock route dstDevices.add(mpathDstDevice3); // Expected Flow-mods // first packet in to mpathDstDevice3 OFMatch match = new OFMatch(); match.loadFromPacket(testMpathPacket3Serialized, (short) 1); OFActionOutput action = new OFActionOutput((short)3, (short)0xffff); List<OFAction> actions = new ArrayList<OFAction>(); actions.add(action); OFFlowMod fm1a = (OFFlowMod) mockControllerProvider.getOFMessageFactory().getMessage(OFType.FLOW_MOD); fm1a.setIdleTimeout((short)5) .setPriority(forwarding.getAccessPriority()) .setMatch(match.clone() .setWildcards(expected_wildcards)) .setActions(actions) .setBufferId(OFPacketOut.BUFFER_ID_NONE) .setCookie(2L << 52) .setLengthU(OFFlowMod.MINIMUM_LENGTH+OFActionOutput.MINIMUM_LENGTH); OFFlowMod fm2a = fm1a.clone(); OFFlowMod fm3a = fm1a.clone(); fm1a.setFlags((short)1); // set flow-mod-removal flag on src switch only // second packet in to mpathDstDevice2 match = new OFMatch(); match.loadFromPacket(testMpathPacket4Serialized, (short) 1); action = new OFActionOutput((short)4, (short)0xffff); actions = new ArrayList<OFAction>(); actions.add(action); OFFlowMod fm1b = (OFFlowMod) mockControllerProvider.getOFMessageFactory().getMessage(OFType.FLOW_MOD); fm1b.setIdleTimeout((short)5) .setPriority(forwarding.getAccessPriority()) .setMatch(match.clone() .setWildcards(expected_wildcards)) .setActions(actions) .setBufferId(OFPacketOut.BUFFER_ID_NONE) .setCookie(2L << 52) .setLengthU(OFFlowMod.MINIMUM_LENGTH+OFActionOutput.MINIMUM_LENGTH); OFFlowMod fm2b = fm1b.clone(); fm2b.getMatch().setInputPort((short) 2); OFFlowMod fm3b = fm1b.clone(); fm3b.getMatch().setInputPort((short) 2); fm1b.setFlags((short)1); // set flow-mod-removal flag on src switch only long cookie1 = forwarding.getHashByMac(mpathDstDevice3.getMACAddress()); RouteId routeId1 = new RouteId(1L, 3L, cookie1); Route route1 = new Route(routeId1, new ArrayList<NodePortTuple>()); route1.getPath().add(new NodePortTuple(1L, (short)1)); route1.getPath().add(new NodePortTuple(1L, (short)3)); route1.getPath().add(new NodePortTuple(2L, (short)1)); route1.getPath().add(new NodePortTuple(2L, (short)3)); route1.getPath().add(new NodePortTuple(3L, (short)1)); route1.getPath().add(new NodePortTuple(3L, (short)3)); expect(routingEngine.getRoute(1L, (short)1, 3L, (short)3, cookie1, false)).andReturn(route1).anyTimes(); long cookie2 = forwarding.getHashByMac(mpathDstDevice4.getMACAddress()); RouteId routeId2 = new RouteId(1L, 3L, cookie2); Route route2 = new Route(routeId2, new ArrayList<NodePortTuple>()); route2.getPath().add(new NodePortTuple(1L, (short)1)); route2.getPath().add(new NodePortTuple(1L, (short)4)); route2.getPath().add(new NodePortTuple(2L, (short)2)); route2.getPath().add(new NodePortTuple(2L, (short)4)); route2.getPath().add(new NodePortTuple(3L, (short)2)); route2.getPath().add(new NodePortTuple(3L, (short)4)); expect(routingEngine.getRoute(1L, (short)1, 3L, (short)4, cookie2, false)).andReturn(route2).anyTimes(); replay(routingEngine, decision); forwarding.receive(sw1, this.mpathPacketIn3, cntx); verify(sw1); verify(sw2); verify(sw3); verify(routingEngine); verify(decision); verify(linkDiscovery); assertTrue(wc1.hasCaptured()); // wc1 should get packetout + flowmod. assertTrue(wc2.hasCaptured()); // wc2 should be a flowmod. assertTrue(wc3.hasCaptured()); // wc3 should be a flowmod. List<OFMessage> msglist = wc1.getValues(); for (OFMessage m1: msglist) { if (m1 instanceof OFPacketOut) assertEquals(m1, mpathPacketOut3); else if (m1 instanceof OFFlowMod) assertEquals(m1, fm1a); } OFMessage m1 = wc2.getValue(); assert (m1 instanceof OFFlowMod); assertTrue(m1.equals(fm2a)); m1 = wc3.getValue(); assert (m1 instanceof OFFlowMod); assertTrue(m1.equals(fm3a)); wc1.reset(); wc2.reset(); wc3.reset(); // Set destination and Mock route dstDevices.clear(); dstDevices.add(mpathDstDevice4); forwarding.receive(sw1, this.mpathPacketIn4, cntx); verify(sw1); verify(sw2); verify(sw3); verify(routingEngine); verify(decision); verify(linkDiscovery); assertTrue(wc1.hasCaptured()); // wc1 should get packetout + flowmod. assertTrue(wc2.hasCaptured()); // wc2 should be a flowmod. assertTrue(wc3.hasCaptured()); // wc2 should be a flowmod. msglist = wc1.getValues(); for (OFMessage m2: msglist) { if (m2 instanceof OFPacketOut) assertEquals(m2, mpathPacketOut4); else if (m2 instanceof OFFlowMod) assertEquals(m2, fm1b); } OFMessage m2 = wc2.getValue(); assert (m2 instanceof OFFlowMod); assertEquals(m2, fm2b); m2 = wc3.getValue(); assert (m2 instanceof OFFlowMod); assertEquals(m2, fm3b); } }