From 3a20f00de09e41fc184ea328474e326fc0f5c5be Mon Sep 17 00:00:00 2001 From: Diogo <diogo_572@hotmail.com> Date: Wed, 26 Apr 2017 17:09:35 +0100 Subject: [PATCH] clean up code --- .../loadbalancer/LBPool.java | 39 ++- .../loadbalancer/LoadBalancer.java | 25 +- .../loadbalancer/MembersResource.java | 1 + .../loadbalancer/LoadBalancerTest.java | 248 +++++++++++++----- 4 files changed, 209 insertions(+), 104 deletions(-) diff --git a/src/main/java/net/floodlightcontroller/loadbalancer/LBPool.java b/src/main/java/net/floodlightcontroller/loadbalancer/LBPool.java index 92778f855..2259a64d5 100644 --- a/src/main/java/net/floodlightcontroller/loadbalancer/LBPool.java +++ b/src/main/java/net/floodlightcontroller/loadbalancer/LBPool.java @@ -96,26 +96,25 @@ public class LBPool { } log.debug("Member picked using LB statistics: {}", poolMembersId.get(bandwidthValues.indexOf(Collections.min(bandwidthValues)))); return poolMembersId.get(bandwidthValues.indexOf(Collections.min(bandwidthValues))); - } - } else if(lbMethod == WEIGHTED_RR && !membersWeight.isEmpty() && membersWeight.values() != null){ - Random randomNumb = new Random(); - short totalWeight = 0; - - for(Short weight: membersWeight.values()){ - totalWeight += weight; - } - if(totalWeight > 0){ - int rand = randomNumb.nextInt(totalWeight); - short val = 0; - for(String memberId: membersWeight.keySet()){ - val += membersWeight.get(memberId); - if(val > rand){ - log.debug("Member picked using WRR: {}",memberId); - return memberId; - } - } - } - log.warn("All the members of this pool have weights set to 0"); + } + return null; + } else if(lbMethod == WEIGHTED_RR && !membersWeight.isEmpty()){ + Random randomNumb = new Random(); + short totalWeight = 0; + + for(Short weight: membersWeight.values()){ + totalWeight += weight; + } + int rand = randomNumb.nextInt(totalWeight); + short val = 0; + for(String memberId: membersWeight.keySet()){ + val += membersWeight.get(memberId); + if(val > rand){ + log.debug("Member picked using WRR: {}",memberId); + return memberId; + } + } + return null; }else { // simple round robin previousMemberIndex = (previousMemberIndex + 1) % members.size(); diff --git a/src/main/java/net/floodlightcontroller/loadbalancer/LoadBalancer.java b/src/main/java/net/floodlightcontroller/loadbalancer/LoadBalancer.java index 5f415966b..39a510750 100644 --- a/src/main/java/net/floodlightcontroller/loadbalancer/LoadBalancer.java +++ b/src/main/java/net/floodlightcontroller/loadbalancer/LoadBalancer.java @@ -211,10 +211,7 @@ ILoadBalancerService, IOFMessageListener { int destIpAddress = ip_pkt.getDestinationAddress().getInt(); if (vipIpToId.containsKey(destIpAddress)){ - - // Switch statistics collection to pick a member - HashMap<String, U64> memberPortBandwidth = collectSwitchStatistics(); - + IPClient client = new IPClient(); client.ipAddress = ip_pkt.getSourceAddress(); client.nw_proto = ip_pkt.getProtocol(); @@ -242,12 +239,17 @@ ILoadBalancerService, IOFMessageListener { return Command.CONTINUE; HashMap<String, Short> memberWeights = new HashMap<String, Short>(); - if(pool.lbMethod == 3){ + HashMap<String, U64> memberPortBandwidth = new HashMap<String, U64>(); + + if(pool.lbMethod == LBPool.WEIGHTED_RR){ for(String memberId: pool.members){ memberWeights.put(memberId,members.get(memberId).weight); } } - log.info("WEIGHTS: {}", memberWeights); + // Switch statistics collection + if(pool.lbMethod == LBPool.STATISTICS && statisticsService != null) + memberPortBandwidth = collectSwitchPortBandwidth(); + LBMember member = members.get(pool.pickMember(client,memberPortBandwidth,memberWeights)); if(member == null) //fix dereference violations return Command.CONTINUE; @@ -272,8 +274,8 @@ ILoadBalancerService, IOFMessageListener { * used to collect statistics from members switch port * @return HashMap<String, U64> portBandwidth <memberId,bitsPerSecond RX> of port connected to member */ - public HashMap<String, U64> collectSwitchStatistics(){ - HashMap<String,U64> portBandwidth = new HashMap<String, U64>(); + public HashMap<String, U64> collectSwitchPortBandwidth(){ + HashMap<String,U64> memberPortBandwidth = new HashMap<String, U64>(); // retrieve all known devices to know which ones are attached to the members Collection<? extends IDevice> allDevices = deviceManagerService.getAllDevices(); @@ -295,11 +297,11 @@ ILoadBalancerService, IOFMessageListener { for(SwitchPort dstDap: membersDevice.getAttachmentPoints()){ SwitchPortBandwidth bandwidthOfPort = statisticsService.getBandwidthConsumption(dstDap.getNodeId(), dstDap.getPortId()); if(bandwidthOfPort != null) // needs time for 1st collection, this avoids nullPointerException - portBandwidth.put(memberId, bandwidthOfPort.getBitsPerSecondRx()); + memberPortBandwidth.put(memberId, bandwidthOfPort.getBitsPerSecondRx()); } } } - return portBandwidth; + return memberPortBandwidth; } /** @@ -829,7 +831,7 @@ ILoadBalancerService, IOFMessageListener { log.error("Invalid value for member weight " + e.getMessage()); return -1; } - if(member != null && (value <= 10 && value >= 0)){ + if(member != null && (value <= 10 && value >= 1)){ member.weight = value; return 0; } @@ -941,6 +943,5 @@ ILoadBalancerService, IOFMessageListener { restApiService.addRestletRoutable(new LoadBalancerWebRoutable()); debugCounterService.registerModule(this.getName()); counterPacketOut = debugCounterService.registerCounter(this.getName(), "packet-outs-written", "Packet outs written by the LoadBalancer", MetaData.WARN); - statisticsService.collectStatistics(true); } } diff --git a/src/main/java/net/floodlightcontroller/loadbalancer/MembersResource.java b/src/main/java/net/floodlightcontroller/loadbalancer/MembersResource.java index b061cb179..746d2dd91 100644 --- a/src/main/java/net/floodlightcontroller/loadbalancer/MembersResource.java +++ b/src/main/java/net/floodlightcontroller/loadbalancer/MembersResource.java @@ -139,6 +139,7 @@ public class MembersResource extends ServerResource { } if(n.equals("weight")){ member.weight = Short.parseShort(jp.getText()); + continue; } log.warn("Unrecognized field {} in " + diff --git a/src/test/java/net/floodlightcontroller/loadbalancer/LoadBalancerTest.java b/src/test/java/net/floodlightcontroller/loadbalancer/LoadBalancerTest.java index df26f7c61..c1551b86e 100644 --- a/src/test/java/net/floodlightcontroller/loadbalancer/LoadBalancerTest.java +++ b/src/test/java/net/floodlightcontroller/loadbalancer/LoadBalancerTest.java @@ -51,6 +51,7 @@ import org.projectfloodlight.openflow.types.IpProtocol; import org.projectfloodlight.openflow.types.MacAddress; import org.projectfloodlight.openflow.types.OFBufferId; import org.projectfloodlight.openflow.types.OFPort; +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; @@ -72,6 +73,7 @@ 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.loadbalancer.LoadBalancer.IPClient; import net.floodlightcontroller.packet.ARP; import net.floodlightcontroller.packet.Ethernet; import net.floodlightcontroller.packet.ICMP; @@ -105,12 +107,14 @@ public class LoadBalancerTest extends FloodlightTestCase { protected RestApiServer restApi; protected VipsResource vipsResource; protected PoolsResource poolsResource; + protected WRRResource wrrResource; + protected PoolMemberResource poolMemberResource; protected MembersResource membersResource; private MockSyncService mockSyncService; protected IDebugCounterService debugCounterService; protected LBVip vip1, vip2; protected LBPool pool1, pool2, pool3; - protected LBMember member1, member2, member3, member4; + protected LBMember member1, member2, member3, member4, member5, member6; private OFFactory factory; @Override @@ -119,7 +123,7 @@ public class LoadBalancerTest extends FloodlightTestCase { super.setUp(); factory = OFFactories.getFactory(OFVersion.OF_13); - + lb = new LoadBalancer(); cntx = new FloodlightContext(); @@ -178,6 +182,8 @@ public class LoadBalancerTest extends FloodlightTestCase { vipsResource = new VipsResource(); poolsResource = new PoolsResource(); membersResource = new MembersResource(); + wrrResource = new WRRResource(); + poolMemberResource = new PoolMemberResource(); vip1=null; vip2=null; @@ -190,6 +196,8 @@ public class LoadBalancerTest extends FloodlightTestCase { member2=null; member3=null; member4=null; + member5=null; + member6=null; } @Test @@ -249,8 +257,8 @@ public class LoadBalancerTest extends FloodlightTestCase { testCreateVip(); - postData1 = "{\"id\":\"1\",\"name\":\"pool1\",\"protocol\":\"icmp\",\"vip_id\":\"1\"}"; - postData2 = "{\"id\":\"2\",\"name\":\"pool2\",\"protocol\":\"tcp\",\"vip_id\":\"2\"}"; + postData1 = "{\"id\":\"1\",\"name\":\"pool1\",\"protocol\":\"icmp\",\"lb_method\":\"STATISTICS\",\"vip_id\":\"1\"}"; + postData2 = "{\"id\":\"2\",\"name\":\"pool2\",\"protocol\":\"tcp\",\"lb_method\":\"WRR\",\"vip_id\":\"2\"}"; postData3 = "{\"id\":\"3\",\"name\":\"pool3\",\"protocol\":\"udp\",\"vip_id\":\"3\"}"; try { @@ -317,16 +325,19 @@ public class LoadBalancerTest extends FloodlightTestCase { @Test public void testCreateMember() { - String postData1, postData2, postData3, postData4; + String postData1, postData2, postData3, postData4,postData5,postData6; 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\"}"; + postData1 = "{\"id\":\"1\",\"address\":\"10.0.0.3\",\"port\":\"8\",\"pool_id\":\"1\",\"weight\":\"2\"}"; + postData2 = "{\"id\":\"2\",\"address\":\"10.0.0.4\",\"port\":\"8\",\"pool_id\":\"1\",\"weight\":\"3\"}"; + postData3 = "{\"id\":\"3\",\"address\":\"10.0.0.5\",\"port\":\"100\",\"pool_id\":\"2\",\"weight\":\"4\"}"; postData4 = "{\"id\":\"4\",\"address\":\"10.0.0.6\",\"port\":\"100\",\"pool_id\":\"2\"}"; + postData5 = "{\"id\":\"5\",\"address\":\"10.0.0.7\",\"port\":\"100\",\"pool_id\":\"1\",\"weight\":\"5\"}"; + postData6 = "{\"id\":\"6\",\"address\":\"10.0.0.8\",\"port\":\"100\",\"pool_id\":\"1\",\"weight\":\"5\"}"; + try { member1 = membersResource.jsonToMember(postData1); @@ -348,18 +359,33 @@ public class LoadBalancerTest extends FloodlightTestCase { } catch (IOException e) { error = e; } + try { + member5= membersResource.jsonToMember(postData5); + } catch (IOException e) { + error = e; + } + try { + member6= membersResource.jsonToMember(postData6); + } catch (IOException e) { + error = e; + } + // verify correct parsing assertFalse(member1==null); assertFalse(member2==null); assertFalse(member3==null); assertFalse(member4==null); + assertFalse(member5==null); + assertFalse(member6==null); assertTrue(error==null); lb.createMember(member1); lb.createMember(member2); lb.createMember(member3); lb.createMember(member4); + lb.createMember(member5); + lb.createMember(member6); // add the same server a second time lb.createMember(member1); @@ -369,12 +395,23 @@ public class LoadBalancerTest extends FloodlightTestCase { assertTrue(lb.members.containsKey(member2.id)); assertTrue(lb.members.containsKey(member3.id)); assertTrue(lb.members.containsKey(member4.id)); + assertTrue(lb.members.containsKey(member5.id)); + assertTrue(lb.members.containsKey(member6.id)); - assertTrue(lb.pools.get(member1.poolId).members.size()==2); + assertTrue(lb.pools.get(member1.poolId).members.size()==4); assertTrue(lb.pools.get(member3.poolId).members.size()==2); // member1 should inherit valid vipId from pool assertTrue(lb.vips.get(member1.vipId)!=null); + + assertTrue(member1.weight==2); + assertTrue(member2.weight==3); + assertTrue(member3.weight==4); + assertTrue(member5.weight==5); + assertTrue(member6.weight==5); + + // default weight value + assertTrue(member4.weight==1); } @Test @@ -439,10 +476,10 @@ public class LoadBalancerTest extends FloodlightTestCase { expect(sw1.hasAttribute(IOFSwitch.PROP_SUPPORTS_OFPP_TABLE)).andReturn(true).anyTimes(); expect(sw1.getOFFactory()).andReturn(factory).anyTimes(); expect(sw1.write(capture(wc1))).andReturn(true).anyTimes(); - + replay(sw1); sfp.switchAdded(DatapathId.of(1L)); - + verify(sw1); /* Test plan: @@ -469,22 +506,22 @@ public class LoadBalancerTest extends FloodlightTestCase { // Build arp packets arpRequest1 = new Ethernet() - .setSourceMACAddress("00:00:00:00:00:01") - .setDestinationMACAddress("ff:ff:ff:ff:ff:ff") - .setEtherType(EthType.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(MacAddress.of("00:00:00:00:00:01")) - .setSenderProtocolAddress(IPv4Address.of("10.0.0.1")) - .setTargetHardwareAddress(MacAddress.of("00:00:00:00:00:00")) - .setTargetProtocolAddress(IPv4Address.of("10.0.0.100"))); + .setSourceMACAddress("00:00:00:00:00:01") + .setDestinationMACAddress("ff:ff:ff:ff:ff:ff") + .setEtherType(EthType.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(MacAddress.of("00:00:00:00:00:01")) + .setSenderProtocolAddress(IPv4Address.of("10.0.0.1")) + .setTargetHardwareAddress(MacAddress.of("00:00:00:00:00:00")) + .setTargetProtocolAddress(IPv4Address.of("10.0.0.100"))); arpRequest1Serialized = arpRequest1.serialize(); @@ -501,22 +538,22 @@ public class LoadBalancerTest extends FloodlightTestCase { // Mock proxy arp packet-out arpReply1 = new Ethernet() - .setSourceMACAddress(LBVip.LB_PROXY_MAC) - .setDestinationMACAddress(MacAddress.of("00:00:00:00:00:01")) - .setEtherType(EthType.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(MacAddress.of(LBVip.LB_PROXY_MAC)) - .setSenderProtocolAddress(IPv4Address.of("10.0.0.100")) - .setTargetHardwareAddress(MacAddress.of("00:00:00:00:00:01")) - .setTargetProtocolAddress(IPv4Address.of("10.0.0.1"))); + .setSourceMACAddress(LBVip.LB_PROXY_MAC) + .setDestinationMACAddress(MacAddress.of("00:00:00:00:00:01")) + .setEtherType(EthType.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(MacAddress.of(LBVip.LB_PROXY_MAC)) + .setSenderProtocolAddress(IPv4Address.of("10.0.0.100")) + .setTargetHardwareAddress(MacAddress.of("00:00:00:00:00:01")) + .setTargetProtocolAddress(IPv4Address.of("10.0.0.1"))); arpReply1Serialized = arpReply1.serialize(); @@ -530,7 +567,7 @@ public class LoadBalancerTest extends FloodlightTestCase { .setXid(22) .build(); sw1.write(arpReplyPacketOut1); - + lb.receive(sw1, arpRequestPacketIn1, cntx); verify(sw1, topology); @@ -540,7 +577,7 @@ public class LoadBalancerTest extends FloodlightTestCase { for (OFMessage m: msglist1) { if (m instanceof OFPacketOut) - assertEquals(OFMessageUtils.OFMessageIgnoreXid.of(arpReplyPacketOut1), OFMessageUtils.OFMessageIgnoreXid.of(m)); + assertEquals(OFMessageUtils.OFMessageIgnoreXid.of(arpReplyPacketOut1), OFMessageUtils.OFMessageIgnoreXid.of(m)); else assertTrue(false); // unexpected message } @@ -549,7 +586,7 @@ public class LoadBalancerTest extends FloodlightTestCase { // Skip arpRequest2 test - in reality this will happen, but for unit test the same logic // is already validated with arpRequest1 test above // - + // Keep the StaticFlowEntryPusher happy with a switch in the switch service Map<DatapathId, IOFSwitch> switches = new HashMap<DatapathId, IOFSwitch>(1); switches.put(DatapathId.of(1), sw1); @@ -558,19 +595,19 @@ public class LoadBalancerTest extends FloodlightTestCase { // Build icmp packets icmpPacket1 = new Ethernet() - .setSourceMACAddress("00:00:00:00:00:01") - .setDestinationMACAddress(LBVip.LB_PROXY_MAC) - .setEtherType(EthType.IPv4) - .setVlanID((short) 0) - .setPriorityCode((byte) 0) - .setPayload( - new IPv4() - .setSourceAddress("10.0.0.1") - .setDestinationAddress("10.0.0.100") - .setProtocol(IpProtocol.ICMP) - .setPayload(new ICMP() - .setIcmpCode((byte) 0) - .setIcmpType((byte) 0))); + .setSourceMACAddress("00:00:00:00:00:01") + .setDestinationMACAddress(LBVip.LB_PROXY_MAC) + .setEtherType(EthType.IPv4) + .setVlanID((short) 0) + .setPriorityCode((byte) 0) + .setPayload( + new IPv4() + .setSourceAddress("10.0.0.1") + .setDestinationAddress("10.0.0.100") + .setProtocol(IpProtocol.ICMP) + .setPayload(new ICMP() + .setIcmpCode((byte) 0) + .setIcmpType((byte) 0))); icmpPacket1Serialized = icmpPacket1.serialize(); @@ -581,19 +618,19 @@ public class LoadBalancerTest extends FloodlightTestCase { .setReason(OFPacketInReason.NO_MATCH) .build(); icmpPacket2 = new Ethernet() - .setSourceMACAddress("00:00:00:00:00:02") - .setDestinationMACAddress(LBVip.LB_PROXY_MAC) - .setEtherType(EthType.IPv4) - .setVlanID((short) 0) - .setPriorityCode((byte) 0) - .setPayload( - new IPv4() - .setSourceAddress("10.0.0.2") - .setDestinationAddress("10.0.0.100") - .setProtocol(IpProtocol.ICMP) - .setPayload(new ICMP() - .setIcmpCode((byte) 0) - .setIcmpType((byte) 0))); + .setSourceMACAddress("00:00:00:00:00:02") + .setDestinationMACAddress(LBVip.LB_PROXY_MAC) + .setEtherType(EthType.IPv4) + .setVlanID((short) 0) + .setPriorityCode((byte) 0) + .setPayload( + new IPv4() + .setSourceAddress("10.0.0.2") + .setDestinationAddress("10.0.0.100") + .setProtocol(IpProtocol.ICMP) + .setPayload(new ICMP() + .setIcmpCode((byte) 0) + .setIcmpType((byte) 0))); icmpPacket2Serialized = icmpPacket2.serialize(); @@ -683,5 +720,72 @@ public class LoadBalancerTest extends FloodlightTestCase { assertTrue(map.size()==4); } + @Test + public void testSetMemberWeight() { + testCreateVip(); + testCreatePool(); + testCreateMember(); + + lb.setMemberWeight(member1.id, "5"); + lb.setMemberWeight(member2.id, "2"); + lb.setMemberWeight(member3.id, "2"); + lb.setMemberWeight(member4.id, "9"); + + assertTrue(member1.weight==5); + assertTrue(member2.weight==2); + assertTrue(member3.weight==2); + assertTrue(member4.weight==9); + int inf_limit = lb.setMemberWeight(member1.id,"0"); + + int sup_limit = lb.setMemberWeight(member1.id,"11"); + + assertTrue(inf_limit == -1); + assertTrue(sup_limit == -1); + } + + @Test + public void testSetPriorityMember() { + testCreateVip(); + testCreatePool(); + testCreateMember(); + + lb.setPriorityToMember(member1.id,member1.poolId); + + assertTrue(member1.weight==3); + assertTrue(member2.weight==1); + assertTrue(member5.weight==1); + assertTrue(member6.weight==1); + } + + @Test + public void testPoolAlgorithms() { + testCreateVip(); + testCreatePool(); + testCreateMember(); + + IPClient client = lb.new IPClient(); + + HashMap<String, U64> membersBandwidth = new HashMap<String, U64>(); + membersBandwidth.put(member1.id,U64.of(4999)); + membersBandwidth.put(member2.id,U64.of(1344)); + membersBandwidth.put(member3.id,U64.ZERO); + membersBandwidth.put(member4.id,U64.of(230)); + membersBandwidth.put(member5.id,U64.of(2002)); + membersBandwidth.put(member6.id,U64.of(1345)); + + HashMap<String, Short> membersWeight = new HashMap<String, Short>(); + + String memberPickedStats = pool1.pickMember(client, membersBandwidth, membersWeight); + + String noMembers = pool3.pickMember(client, membersBandwidth, membersWeight); + + membersBandwidth.clear(); + String memberPickedNoData = pool1.pickMember(client, membersBandwidth, membersWeight); + + assertTrue(memberPickedStats.equals("2")); + assertTrue(memberPickedNoData.equals("1")); // simple round robin + + assertTrue(noMembers==null); + } } -- GitLab