From 0fbf8e92713c856df2558a087d63903689c80750 Mon Sep 17 00:00:00 2001 From: kwanggithub <kwang@clemson.edu> Date: Fri, 4 Jan 2013 18:40:37 -0800 Subject: [PATCH] Add junit test for LoadBalancer Minor cleanup in LBVip Bug fix for removal actions in LoadBalancer --- .../loadbalancer/LBVip.java | 4 +- .../loadbalancer/LoadBalancer.java | 45 +- .../loadbalancer/LoadBalancerTest.java | 677 ++++++++++++++++++ 3 files changed, 710 insertions(+), 16 deletions(-) create mode 100644 src/test/java/net/floodlightcontroller/loadbalancer/LoadBalancerTest.java diff --git a/src/main/java/net/floodlightcontroller/loadbalancer/LBVip.java b/src/main/java/net/floodlightcontroller/loadbalancer/LBVip.java index fd8c0bd45..7872175d4 100644 --- a/src/main/java/net/floodlightcontroller/loadbalancer/LBVip.java +++ b/src/main/java/net/floodlightcontroller/loadbalancer/LBVip.java @@ -32,6 +32,8 @@ public class LBVip { protected MACAddress proxyMac; + public static String LB_PROXY_MAC= "12:34:56:78:90:12"; + public LBVip() { this.id = String.valueOf((int) (Math.random()*10000)); this.name = null; @@ -47,7 +49,7 @@ public class LBVip { this.address = 0; this.status = 0; - this.proxyMac = MACAddress.valueOf("12:34:56:78:90:12"); + this.proxyMac = MACAddress.valueOf(LB_PROXY_MAC); } public String pickPool(IPClient client) { diff --git a/src/main/java/net/floodlightcontroller/loadbalancer/LoadBalancer.java b/src/main/java/net/floodlightcontroller/loadbalancer/LoadBalancer.java index 3893ed570..25303373c 100644 --- a/src/main/java/net/floodlightcontroller/loadbalancer/LoadBalancer.java +++ b/src/main/java/net/floodlightcontroller/loadbalancer/LoadBalancer.java @@ -133,7 +133,8 @@ public class LoadBalancer implements IFloodlightModule, public boolean isCallbackOrderingPrereq(OFType type, String name) { return (type.equals(OFType.PACKET_IN) && (name.equals("topology") || - name.equals("devicemanager"))); + name.equals("devicemanager") || + name.equals("virtualizer"))); } @Override @@ -504,8 +505,8 @@ public class LoadBalancer implements IFloodlightModule, fm.setPriority(Short.MAX_VALUE); if (inBound) { - entryName = "inbound-vip-"+ member.vipId+"client-"+client.ipAddress+"-port-"+client.targetPort - +"srcswitch-"+path.get(0).getNodeId()+"sw-"+sw; + entryName = "inbound-vip-"+ member.vipId+"-client-"+client.ipAddress+"-port-"+client.targetPort + +"-srcswitch-"+path.get(0).getNodeId()+"-sw-"+sw; matchString = "nw_src="+IPv4.fromIPv4Address(client.ipAddress)+"," + "nw_proto="+String.valueOf(client.nw_proto)+"," + "tp_src="+String.valueOf(client.srcPort & 0xffff)+"," @@ -521,8 +522,8 @@ public class LoadBalancer implements IFloodlightModule, "output="+path.get(i+1).getPortId(); } } else { - entryName = "outbound-vip-"+ member.vipId+"client-"+client.ipAddress+"-port-"+client.targetPort - +"srcswitch-"+path.get(0).getNodeId()+"sw-"+sw; + entryName = "outbound-vip-"+ member.vipId+"-client-"+client.ipAddress+"-port-"+client.targetPort + +"-srcswitch-"+path.get(0).getNodeId()+"-sw-"+sw; matchString = "nw_dst="+IPv4.fromIPv4Address(client.ipAddress)+"," + "nw_proto="+String.valueOf(client.nw_proto)+"," + "tp_dst="+String.valueOf(client.srcPort & 0xffff)+"," @@ -619,11 +620,13 @@ public class LoadBalancer implements IFloodlightModule, pool = new LBPool(); pools.put(pool.id, pool); - if (pool.vipId != null) + if (pool.vipId != null && vips.containsKey(pool.vipId)) vips.get(pool.vipId).pools.add(pool.id); - else - log.error("pool must be specified with non-null vip-id"); - + else { + log.error("specified vip-id must exist"); + pool.vipId = null; + pools.put(pool.id, pool); + } return pool; } @@ -635,7 +638,12 @@ public class LoadBalancer implements IFloodlightModule, @Override public int removePool(String poolId) { - if(pools.containsKey(poolId)){ + LBPool pool; + pool = pools.get(poolId); + + if(pools!=null){ + if (pool.vipId != null) + vips.get(pool.vipId).pools.remove(poolId); pools.remove(poolId); return 0; } else { @@ -671,12 +679,14 @@ public class LoadBalancer implements IFloodlightModule, public LBMember createMember(LBMember member) { if (member == null) member = new LBMember(); - + + members.put(member.id, member); + memberIpToId.put(member.address, member.id); + if (member.poolId != null && pools.get(member.poolId) != null) { member.vipId = pools.get(member.poolId).vipId; - members.put(member.id, member); - pools.get(member.poolId).members.add(member.id); - memberIpToId.put(member.address, member.id); + if (!pools.get(member.poolId).members.contains(member.id)) + pools.get(member.poolId).members.add(member.id); } else log.error("member must be specified with non-null pool_id"); @@ -691,7 +701,12 @@ public class LoadBalancer implements IFloodlightModule, @Override public int removeMember(String memberId) { - if(members.containsKey(memberId)){ + LBMember member; + member = members.get(memberId); + + if(member != null){ + if (member.poolId != null) + pools.get(member.poolId).members.remove(memberId); members.remove(memberId); return 0; } else { diff --git a/src/test/java/net/floodlightcontroller/loadbalancer/LoadBalancerTest.java b/src/test/java/net/floodlightcontroller/loadbalancer/LoadBalancerTest.java new file mode 100644 index 000000000..fba973437 --- /dev/null +++ b/src/test/java/net/floodlightcontroller/loadbalancer/LoadBalancerTest.java @@ -0,0 +1,677 @@ +package net.floodlightcontroller.loadbalancer; + +import static org.easymock.EasyMock.anyLong; +import static org.easymock.EasyMock.anyShort; +import static org.easymock.EasyMock.capture; +import static org.easymock.EasyMock.createMock; +import static org.easymock.EasyMock.expect; +import static org.easymock.EasyMock.expectLastCall; +import static org.easymock.EasyMock.replay; +import static org.easymock.EasyMock.reset; +import static org.easymock.EasyMock.verify; + +import java.io.IOException; +import java.util.ArrayList; +import java.util.List; +import java.util.Map; + +import org.easymock.Capture; +import org.easymock.CaptureType; +import org.easymock.EasyMock; +import org.junit.Before; +import org.junit.Test; +import org.openflow.protocol.OFFlowMod; +import org.openflow.protocol.OFMatch; +import org.openflow.protocol.OFMessage; +import org.openflow.protocol.OFPacketIn; +import org.openflow.protocol.OFPacketOut; +import org.openflow.protocol.OFPort; +import org.openflow.protocol.OFType; +import org.openflow.protocol.OFPacketIn.OFPacketInReason; +import org.openflow.protocol.action.OFAction; +import org.openflow.protocol.action.OFActionOutput; +import org.openflow.util.HexString; + +import net.floodlightcontroller.core.FloodlightContext; +import net.floodlightcontroller.core.IFloodlightProviderService; +import net.floodlightcontroller.core.IOFSwitch; +import net.floodlightcontroller.core.module.FloodlightModuleContext; +import net.floodlightcontroller.core.test.MockFloodlightProvider; +import net.floodlightcontroller.core.test.MockThreadPoolService; +import net.floodlightcontroller.counter.CounterStore; +import net.floodlightcontroller.counter.ICounterStoreService; +import net.floodlightcontroller.devicemanager.IDeviceService; +import net.floodlightcontroller.devicemanager.IEntityClassifierService; +import net.floodlightcontroller.devicemanager.internal.DefaultEntityClassifier; +import net.floodlightcontroller.devicemanager.test.MockDeviceManager; +import net.floodlightcontroller.flowcache.FlowReconcileManager; +import net.floodlightcontroller.flowcache.IFlowReconcileService; +import net.floodlightcontroller.packet.ARP; +import net.floodlightcontroller.packet.Ethernet; +import net.floodlightcontroller.packet.ICMP; +import net.floodlightcontroller.packet.IPacket; +import net.floodlightcontroller.packet.IPv4; +import net.floodlightcontroller.restserver.IRestApiService; +import net.floodlightcontroller.restserver.RestApiServer; +import net.floodlightcontroller.routing.IRoutingService; +import net.floodlightcontroller.routing.Route; +import net.floodlightcontroller.staticflowentry.IStaticFlowEntryPusherService; +import net.floodlightcontroller.staticflowentry.StaticFlowEntryPusher; +import net.floodlightcontroller.storage.IStorageSourceService; +import net.floodlightcontroller.storage.memory.MemoryStorageSource; +import net.floodlightcontroller.test.FloodlightTestCase; +import net.floodlightcontroller.threadpool.IThreadPoolService; +import net.floodlightcontroller.topology.ITopologyService; +import net.floodlightcontroller.topology.NodePortTuple; + +public class LoadBalancerTest extends FloodlightTestCase { + protected LoadBalancer lb; + + protected FloodlightContext cntx; + protected FloodlightModuleContext fmc; + protected MockFloodlightProvider mockFloodlightProvider; + protected MockDeviceManager deviceManager; + protected MockThreadPoolService tps; + protected FlowReconcileManager frm; + protected DefaultEntityClassifier entityClassifier; + protected IRoutingService routingEngine; + protected ITopologyService topology; + protected StaticFlowEntryPusher sfp; + protected MemoryStorageSource storage; + protected RestApiServer restApi; + protected VipsResource vipsResource; + protected PoolsResource poolsResource; + protected MembersResource membersResource; + + protected LBVip vip1, vip2; + protected LBPool pool1, pool2, pool3; + protected LBMember member1, member2, member3, member4; + + @Before + public void setUp() throws Exception { + super.setUp(); + + lb = new LoadBalancer(); + + cntx = new FloodlightContext(); + fmc = new FloodlightModuleContext(); + entityClassifier = new DefaultEntityClassifier(); // dependency for device manager + frm = new FlowReconcileManager(); //dependency for device manager + tps = new MockThreadPoolService(); //dependency for device manager + deviceManager = new MockDeviceManager(); + topology = createMock(ITopologyService.class); + routingEngine = createMock(IRoutingService.class); + restApi = new RestApiServer(); + sfp = new StaticFlowEntryPusher(); + storage = new MemoryStorageSource(); //dependency for sfp + + fmc.addService(IRestApiService.class, restApi); + fmc.addService(IFloodlightProviderService.class, getMockFloodlightProvider()); + fmc.addService(IEntityClassifierService.class, entityClassifier); + fmc.addService(IFlowReconcileService.class, frm); + fmc.addService(IThreadPoolService.class, tps); + fmc.addService(IDeviceService.class, deviceManager); + fmc.addService(ITopologyService.class, topology); + fmc.addService(IRoutingService.class, routingEngine); + fmc.addService(ICounterStoreService.class, new CounterStore()); + fmc.addService(IStaticFlowEntryPusherService.class, sfp); + fmc.addService(ILoadBalancerService.class, lb); + fmc.addService(IStorageSourceService.class, storage); + + lb.init(fmc); + getMockFloodlightProvider().init(fmc); + entityClassifier.init(fmc); + frm.init(fmc); + tps.init(fmc); + deviceManager.init(fmc); + restApi.init(fmc); + sfp.init(fmc); + storage.init(fmc); + + topology.addListener(deviceManager); + expectLastCall().times(1); + replay(topology); + + lb.startUp(fmc); + getMockFloodlightProvider().startUp(fmc); + entityClassifier.startUp(fmc); + frm.startUp(fmc); + tps.startUp(fmc); + deviceManager.startUp(fmc); + restApi.startUp(fmc); + sfp.startUp(fmc); + storage.startUp(fmc); + + verify(topology); + + vipsResource = new VipsResource(); + poolsResource = new PoolsResource(); + membersResource = new MembersResource(); + + vip1=null; + vip2=null; + + pool1=null; + pool2=null; + pool3=null; + + member1=null; + member2=null; + member3=null; + member4=null; + } + + @Test + public void testCreateVip() { + String postData1, postData2; + IOException error = null; + + postData1 = "{\"id\":\"1\",\"name\":\"vip1\",\"protocol\":\"icmp\",\"address\":\"10.0.0.100\",\"port\":\"8\"}"; + postData2 = "{\"id\":\"2\",\"name\":\"vip2\",\"protocol\":\"tcp\",\"address\":\"10.0.0.200\",\"port\":\"100\"}"; + + try { + vip1 = vipsResource.jsonToVip(postData1); + } catch (IOException e) { + error = e; + } + try { + vip2 = vipsResource.jsonToVip(postData2); + } catch (IOException e) { + error = e; + } + + // verify correct parsing + assertFalse(vip1==null); + assertFalse(vip2==null); + assertTrue(error==null); + + lb.createVip(vip1); + lb.createVip(vip2); + + // verify correct creation + assertTrue(lb.vips.containsKey(vip1.id)); + assertTrue(lb.vips.containsKey(vip2.id)); + } + + @Test + public void testRemoveVip() { + + testCreateVip(); + + // verify correct initial condition + assertFalse(vip1==null); + assertFalse(vip2==null); + + lb.removeVip(vip1.id); + lb.removeVip(vip2.id); + + // verify correct removal + assertFalse(lb.vips.containsKey(vip1.id)); + assertFalse(lb.vips.containsKey(vip2.id)); + + } + + @Test + public void testCreatePool() { + String postData1, postData2, postData3; + IOException error = null; + + testCreateVip(); + + postData1 = "{\"id\":\"1\",\"name\":\"pool1\",\"protocol\":\"icmp\",\"vip_id\":\"1\"}"; + postData2 = "{\"id\":\"2\",\"name\":\"pool2\",\"protocol\":\"tcp\",\"vip_id\":\"2\"}"; + postData3 = "{\"id\":\"3\",\"name\":\"pool3\",\"protocol\":\"udp\",\"vip_id\":\"3\"}"; + + try { + pool1 = poolsResource.jsonToPool(postData1); + } catch (IOException e) { + error = e; + } + try { + pool2 = poolsResource.jsonToPool(postData2); + } catch (IOException e) { + error = e; + } + try { + pool3 = poolsResource.jsonToPool(postData3); + } catch (IOException e) { + error = e; + } + + // verify correct parsing + assertFalse(pool1==null); + assertFalse(pool2==null); + assertFalse(pool3==null); + assertTrue(error==null); + + lb.createPool(pool1); + lb.createPool(pool2); + lb.createPool(pool3); + + // verify successful creates; two registered with vips and one not + assertTrue(lb.pools.containsKey(pool1.id)); + assertTrue(lb.vips.get(pool1.vipId).pools.contains(pool1.id)); + assertTrue(lb.pools.containsKey(pool2.id)); + assertTrue(lb.vips.get(pool2.vipId).pools.contains(pool2.id)); + assertTrue(lb.pools.containsKey(pool3.id)); + assertFalse(lb.vips.containsKey(pool3.vipId)); + + } + + @Test + public void testRemovePool() { + testCreateVip(); + testCreatePool(); + + // verify correct initial condition + assertFalse(vip1==null); + assertFalse(vip2==null); + assertFalse(pool1==null); + assertFalse(pool2==null); + assertFalse(pool3==null); + + lb.removePool(pool1.id); + lb.removePool(pool2.id); + lb.removePool(pool3.id); + + // verify correct removal + assertFalse(lb.pools.containsKey(pool1.id)); + assertFalse(lb.pools.containsKey(pool2.id)); + assertFalse(lb.pools.containsKey(pool3.id)); + + //verify pool cleanup from vip + assertFalse(lb.vips.get(pool1.vipId).pools.contains(pool1.id)); + assertFalse(lb.vips.get(pool2.vipId).pools.contains(pool2.id)); + } + + @Test + public void testCreateMember() { + String postData1, postData2, postData3, postData4; + IOException error = null; + + testCreateVip(); + testCreatePool(); + + postData1 = "{\"id\":\"1\",\"address\":\"10.0.0.3\",\"port\":\"8\",\"pool_id\":\"1\"}"; + postData2 = "{\"id\":\"2\",\"address\":\"10.0.0.4\",\"port\":\"8\",\"pool_id\":\"1\"}"; + postData3 = "{\"id\":\"3\",\"address\":\"10.0.0.5\",\"port\":\"100\",\"pool_id\":\"2\"}"; + postData4 = "{\"id\":\"4\",\"address\":\"10.0.0.6\",\"port\":\"100\",\"pool_id\":\"2\"}"; + + try { + member1 = membersResource.jsonToMember(postData1); + } catch (IOException e) { + error = e; + } + try { + member2 = membersResource.jsonToMember(postData2); + } catch (IOException e) { + error = e; + } + try { + member3 = membersResource.jsonToMember(postData3); + } catch (IOException e) { + error = e; + } + try { + member4 = membersResource.jsonToMember(postData4); + } catch (IOException e) { + error = e; + } + + // verify correct parsing + assertFalse(member1==null); + assertFalse(member2==null); + assertFalse(member3==null); + assertFalse(member4==null); + assertTrue(error==null); + + lb.createMember(member1); + lb.createMember(member2); + lb.createMember(member3); + lb.createMember(member4); + + // add the same server a second time + lb.createMember(member1); + + // verify successful creates + assertTrue(lb.members.containsKey(member1.id)); + assertTrue(lb.members.containsKey(member2.id)); + assertTrue(lb.members.containsKey(member3.id)); + assertTrue(lb.members.containsKey(member4.id)); + + assertTrue(lb.pools.get(member1.poolId).members.size()==2); + assertTrue(lb.pools.get(member3.poolId).members.size()==2); + + // member1 should inherit valid vipId from pool + assertTrue(lb.vips.get(member1.vipId)!=null); + } + + @Test + public void testRemoveMember() { + testCreateVip(); + testCreatePool(); + testCreateMember(); + + // verify correct initial condition + assertFalse(vip1==null); + assertFalse(vip2==null); + assertFalse(pool1==null); + assertFalse(pool2==null); + assertFalse(pool3==null); + assertFalse(member1==null); + assertFalse(member2==null); + assertFalse(member3==null); + assertFalse(member4==null); + + lb.removeMember(member1.id); + lb.removeMember(member2.id); + lb.removeMember(member3.id); + lb.removeMember(member4.id); + + // verify correct removal + assertFalse(lb.members.containsKey(member1.id)); + assertFalse(lb.members.containsKey(member2.id)); + assertFalse(lb.members.containsKey(member3.id)); + assertFalse(lb.members.containsKey(member4.id)); + + //verify member cleanup from pool + assertFalse(lb.pools.get(member1.poolId).members.contains(member1.id)); + assertFalse(lb.pools.get(member2.poolId).members.contains(member2.id)); + assertFalse(lb.pools.get(member3.poolId).members.contains(member3.id)); + assertFalse(lb.pools.get(member4.poolId).members.contains(member4.id)); + + } + + @Test + public void testTwoSubsequentIcmpRequests() throws Exception { + testCreateVip(); + testCreatePool(); + testCreateMember(); + + IOFSwitch sw1; + + IPacket arpRequest1, arpRequest2, arpReply1, arpReply2, icmpPacket1, icmpPacket2; + + byte[] arpRequest1Serialized, arpRequest2Serialized; + byte[] arpReply1Serialized, arpReply2Serialized; + byte[] icmpPacket1Serialized, icmpPacket2Serialized; + + OFPacketIn arpRequestPacketIn1, arpRequestPacketIn2; + OFPacketIn icmpPacketIn1, icmpPacketIn2; + + OFPacketOut arpReplyPacketOut1, arpReplyPacketOut2; + + Capture<OFMessage> wc1 = new Capture<OFMessage>(CaptureType.ALL); + Capture<FloodlightContext> bc1 = + new Capture<FloodlightContext>(CaptureType.ALL); + + int 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; + + sw1 = EasyMock.createNiceMock(IOFSwitch.class); + expect(sw1.getId()).andReturn(1L).anyTimes(); + expect(sw1.getStringId()).andReturn("00:00:00:00:00:01").anyTimes(); + expect(sw1.getAttribute(IOFSwitch.PROP_FASTWILDCARDS)).andReturn((Integer)fastWildcards).anyTimes(); + expect(sw1.hasAttribute(IOFSwitch.PROP_SUPPORTS_OFPP_TABLE)).andReturn(true).anyTimes(); + sw1.write(capture(wc1), capture(bc1)); + expectLastCall().anyTimes(); + sw1.flush(); + expectLastCall().anyTimes(); + + replay(sw1); + sfp.addedSwitch(sw1); + verify(sw1); + + /* Test plan: + * - two clients and two servers on sw1 port 1, 2, 3, 4 + * - mock arp request received towards vip1 from (1L, 1) + * - proxy arp got pushed out to (1L, 1)- check sw1 getting the packetout + * - mock icmp request received towards vip1 from (1L, 1) + * - device manager list of devices queried to identify source and dest devices + * - routing engine queried to get inbound and outbound routes + * - check getRoute calls and responses + * - sfp called to install flows + * - check sfp calls + */ + + // Build topology + reset(topology); + expect(topology.isIncomingBroadcastAllowed(anyLong(), anyShort())).andReturn(true).anyTimes(); + expect(topology.getL2DomainId(1L)).andReturn(1L).anyTimes(); + expect(topology.isAttachmentPointPort(1L, (short)1)).andReturn(true).anyTimes(); + expect(topology.isAttachmentPointPort(1L, (short)2)).andReturn(true).anyTimes(); + expect(topology.isAttachmentPointPort(1L, (short)3)).andReturn(true).anyTimes(); + expect(topology.isAttachmentPointPort(1L, (short)4)).andReturn(true).anyTimes(); + replay(topology); + + + + // Build arp packets + arpRequest1 = new Ethernet() + .setSourceMACAddress("00:00:00:00:00:01") + .setDestinationMACAddress("ff:ff:ff:ff:ff:ff") + .setEtherType(Ethernet.TYPE_ARP) + .setVlanID((short) 0) + .setPriorityCode((byte) 0) + .setPayload( + new ARP() + .setHardwareType(ARP.HW_TYPE_ETHERNET) + .setProtocolType(ARP.PROTO_TYPE_IP) + .setHardwareAddressLength((byte) 6) + .setProtocolAddressLength((byte) 4) + .setOpCode(ARP.OP_REQUEST) + .setSenderHardwareAddress(HexString.fromHexString("00:00:00:00:00:01")) + .setSenderProtocolAddress(IPv4.toIPv4AddressBytes("10.0.0.1")) + .setTargetHardwareAddress(HexString.fromHexString("00:00:00:00:00:00")) + .setTargetProtocolAddress(IPv4.toIPv4AddressBytes("10.0.0.100"))); + + arpRequest1Serialized = arpRequest1.serialize(); + + arpRequestPacketIn1 = + ((OFPacketIn) getMockFloodlightProvider().getOFMessageFactory(). + getMessage(OFType.PACKET_IN)) + .setBufferId(-1) + .setInPort((short) 1) + .setPacketData(arpRequest1Serialized) + .setReason(OFPacketInReason.NO_MATCH) + .setTotalLength((short) arpRequest1Serialized.length); + + IFloodlightProviderService.bcStore.put(cntx, + IFloodlightProviderService.CONTEXT_PI_PAYLOAD, + (Ethernet) arpRequest1); + + // Mock proxy arp packet-out + arpReply1 = new Ethernet() + .setSourceMACAddress(LBVip.LB_PROXY_MAC) + .setDestinationMACAddress(HexString.fromHexString("00:00:00:00:00:01")) + .setEtherType(Ethernet.TYPE_ARP) + .setVlanID((short) 0) + .setPriorityCode((byte) 0) + .setPayload( + new ARP() + .setHardwareType(ARP.HW_TYPE_ETHERNET) + .setProtocolType(ARP.PROTO_TYPE_IP) + .setHardwareAddressLength((byte) 6) + .setProtocolAddressLength((byte) 4) + .setOpCode(ARP.OP_REPLY) + .setSenderHardwareAddress(HexString.fromHexString(LBVip.LB_PROXY_MAC)) + .setSenderProtocolAddress(IPv4.toIPv4AddressBytes("10.0.0.100")) + .setTargetHardwareAddress(HexString.fromHexString("00:00:00:00:00:01")) + .setTargetProtocolAddress(IPv4.toIPv4AddressBytes("10.0.0.1"))); + + arpReply1Serialized = arpReply1.serialize(); + + arpReplyPacketOut1 = + (OFPacketOut) getMockFloodlightProvider().getOFMessageFactory(). + getMessage(OFType.PACKET_OUT); + arpReplyPacketOut1.setBufferId(OFPacketOut.BUFFER_ID_NONE) + .setInPort(OFPort.OFPP_NONE.getValue()); + List<OFAction> poactions = new ArrayList<OFAction>(); + poactions.add(new OFActionOutput(arpRequestPacketIn1.getInPort(), (short) 0xffff)); + arpReplyPacketOut1.setActions(poactions) + .setActionsLength((short) OFActionOutput.MINIMUM_LENGTH) + .setPacketData(arpReply1Serialized) + .setLengthU(OFPacketOut.MINIMUM_LENGTH+ + arpReplyPacketOut1.getActionsLength()+ + arpReply1Serialized.length); + + lb.receive(sw1, arpRequestPacketIn1, cntx); + verify(sw1, topology); + + assertTrue(wc1.hasCaptured()); // wc1 should get packetout + + List<OFMessage> msglist1 = wc1.getValues(); + + for (OFMessage m: msglist1) { + if (m instanceof OFPacketOut) + assertEquals(arpReplyPacketOut1, m); + else + assertTrue(false); // unexpected message + } + + // + // Skip arpRequest2 test - in reality this will happen, but for unit test the same logic + // is already validated with arpRequest1 test above + // + + // Build icmp packets + icmpPacket1 = new Ethernet() + .setSourceMACAddress("00:00:00:00:00:01") + .setDestinationMACAddress(LBVip.LB_PROXY_MAC) + .setEtherType(Ethernet.TYPE_IPv4) + .setVlanID((short) 0) + .setPriorityCode((byte) 0) + .setPayload( + new IPv4() + .setSourceAddress("10.0.0.1") + .setDestinationAddress("10.0.0.100") + .setProtocol(IPv4.PROTOCOL_ICMP) + .setPayload(new ICMP() + .setIcmpCode((byte) 0) + .setIcmpType((byte) 0))); + + icmpPacket1Serialized = icmpPacket1.serialize(); + + icmpPacketIn1 = + ((OFPacketIn) getMockFloodlightProvider().getOFMessageFactory(). + getMessage(OFType.PACKET_IN)) + .setBufferId(-1) + .setInPort((short) 1) + .setPacketData(icmpPacket1Serialized) + .setReason(OFPacketInReason.NO_MATCH) + .setTotalLength((short) icmpPacket1Serialized.length); + + icmpPacket2 = new Ethernet() + .setSourceMACAddress("00:00:00:00:00:02") + .setDestinationMACAddress(LBVip.LB_PROXY_MAC) + .setEtherType(Ethernet.TYPE_IPv4) + .setVlanID((short) 0) + .setPriorityCode((byte) 0) + .setPayload( + new IPv4() + .setSourceAddress("10.0.0.2") + .setDestinationAddress("10.0.0.100") + .setProtocol(IPv4.PROTOCOL_ICMP) + .setPayload(new ICMP() + .setIcmpCode((byte) 0) + .setIcmpType((byte) 0))); + + icmpPacket2Serialized = icmpPacket2.serialize(); + + icmpPacketIn2 = + ((OFPacketIn) getMockFloodlightProvider().getOFMessageFactory(). + getMessage(OFType.PACKET_IN)) + .setBufferId(-1) + .setInPort((short) 2) + .setPacketData(icmpPacket2Serialized) + .setReason(OFPacketInReason.NO_MATCH) + .setTotalLength((short) icmpPacket2Serialized.length); + + byte[] dataLayerSource1 = ((Ethernet)icmpPacket1).getSourceMACAddress(); + int networkSource1 = ((IPv4)((Ethernet)icmpPacket1).getPayload()).getSourceAddress(); + byte[] dataLayerDest1 = HexString.fromHexString("00:00:00:00:00:03"); + int networkDest1 = IPv4.toIPv4Address("10.0.0.3"); + byte[] dataLayerSource2 = ((Ethernet)icmpPacket2).getSourceMACAddress(); + int networkSource2 = ((IPv4)((Ethernet)icmpPacket2).getPayload()).getSourceAddress(); + byte[] dataLayerDest2 = HexString.fromHexString("00:00:00:00:00:04"); + int networkDest2 = IPv4.toIPv4Address("10.0.0.4"); + + deviceManager.learnEntity(Ethernet.toLong(dataLayerSource1), + null, networkSource1, + 1L, 1); + deviceManager.learnEntity(Ethernet.toLong(dataLayerSource2), + null, networkSource2, + 1L, 2); + deviceManager.learnEntity(Ethernet.toLong(dataLayerDest1), + null, networkDest1, + 1L, 3); + deviceManager.learnEntity(Ethernet.toLong(dataLayerDest2), + null, networkDest2, + 1L, 4); + + // in bound #1 + Route route1 = new Route(1L, 1L); + List<NodePortTuple> nptList1 = new ArrayList<NodePortTuple>(); + nptList1.add(new NodePortTuple(1L, (short)1)); + nptList1.add(new NodePortTuple(1L, (short)3)); + route1.setPath(nptList1); + expect(routingEngine.getRoute(1L, (short)1, 1L, (short)3, 0)).andReturn(route1).atLeastOnce(); + + // outbound #1 + Route route2 = new Route(1L, 1L); + List<NodePortTuple> nptList2 = new ArrayList<NodePortTuple>(); + nptList2.add(new NodePortTuple(1L, (short)3)); + nptList2.add(new NodePortTuple(1L, (short)1)); + route2.setPath(nptList2); + expect(routingEngine.getRoute(1L, (short)3, 1L, (short)1, 0)).andReturn(route2).atLeastOnce(); + + // inbound #2 + Route route3 = new Route(1L, 1L); + List<NodePortTuple> nptList3 = new ArrayList<NodePortTuple>(); + nptList3.add(new NodePortTuple(1L, (short)2)); + nptList3.add(new NodePortTuple(1L, (short)4)); + route3.setPath(nptList3); + expect(routingEngine.getRoute(1L, (short)2, 1L, (short)4, 0)).andReturn(route3).atLeastOnce(); + + // outbound #2 + Route route4 = new Route(1L, 1L); + List<NodePortTuple> nptList4 = new ArrayList<NodePortTuple>(); + nptList4.add(new NodePortTuple(1L, (short)4)); + nptList4.add(new NodePortTuple(1L, (short)2)); + route4.setPath(nptList3); + expect(routingEngine.getRoute(1L, (short)4, 1L, (short)2, 0)).andReturn(route4).atLeastOnce(); + + replay(routingEngine); + + wc1.reset(); + + IFloodlightProviderService.bcStore.put(cntx, + IFloodlightProviderService.CONTEXT_PI_PAYLOAD, + (Ethernet) icmpPacket1); + lb.receive(sw1, icmpPacketIn1, cntx); + + IFloodlightProviderService.bcStore.put(cntx, + IFloodlightProviderService.CONTEXT_PI_PAYLOAD, + (Ethernet) icmpPacket2); + lb.receive(sw1, icmpPacketIn2, cntx); + + assertTrue(wc1.hasCaptured()); // wc1 should get packetout + + List<OFMessage> msglist2 = wc1.getValues(); + + assertTrue(msglist2.size()==2); // has inbound and outbound packetouts + // TODO: not seeing flowmods yet ... + + Map<String, OFFlowMod> map = sfp.getFlows("00:00:00:00:00:00:00:01"); + + assertTrue(map.size()==4); + } + + +} -- GitLab