From 3bf531a5c632c4ded51d603e816f73a53bdd8162 Mon Sep 17 00:00:00 2001
From: Diogo <diogo_572@hotmail.com>
Date: Thu, 6 Apr 2017 16:55:27 +0100
Subject: [PATCH] HTTP packet parsed, starting REST API changes

---
 .../loadbalancer/L7RulesResource.java         | 149 +++++++++
 .../loadbalancer/LBPool.java                  |   4 +-
 .../loadbalancer/LoadBalancer.java            | 309 +++++++++++++++++-
 .../loadbalancer/LoadBalancerWebRoutable.java |   6 +-
 .../net/floodlightcontroller/packet/HTTP.java | 104 ++++++
 .../net/floodlightcontroller/packet/TCP.java  |   8 +-
 .../routing/ForwardingBase.java               |   1 -
 .../resources/floodlightdefault.properties    |   6 +-
 8 files changed, 560 insertions(+), 27 deletions(-)
 create mode 100644 src/main/java/net/floodlightcontroller/loadbalancer/L7RulesResource.java
 create mode 100644 src/main/java/net/floodlightcontroller/packet/HTTP.java

diff --git a/src/main/java/net/floodlightcontroller/loadbalancer/L7RulesResource.java b/src/main/java/net/floodlightcontroller/loadbalancer/L7RulesResource.java
new file mode 100644
index 000000000..0de3d4735
--- /dev/null
+++ b/src/main/java/net/floodlightcontroller/loadbalancer/L7RulesResource.java
@@ -0,0 +1,149 @@
+package net.floodlightcontroller.loadbalancer;
+
+import java.io.IOException;
+import java.util.Collection;
+
+import org.projectfloodlight.openflow.types.IpProtocol;
+import org.restlet.resource.Delete;
+import org.restlet.resource.Get;
+import org.restlet.resource.Post;
+import org.restlet.resource.Put;
+import org.restlet.resource.ServerResource;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import com.fasterxml.jackson.core.JsonParseException;
+import com.fasterxml.jackson.core.JsonParser;
+import com.fasterxml.jackson.core.JsonToken;
+import com.fasterxml.jackson.databind.MappingJsonFactory;
+
+import net.floodlightcontroller.packet.IPv4;
+
+public class L7RulesResource extends ServerResource {
+	protected static Logger log = LoggerFactory.getLogger(L7RulesResource.class);
+	
+	@Get("json")
+    public Collection <LBVip> retrieve() {
+        ILoadBalancerService lbs =
+                (ILoadBalancerService)getContext().getAttributes().
+                    get(ILoadBalancerService.class.getCanonicalName());
+        
+        String vipId = (String) getRequestAttributes().get("rule");
+        if (vipId!=null)
+            return lbs.listVip(vipId);
+        else
+            return lbs.listVips();
+    }
+    
+    @Put
+    @Post
+    public LBVip createVip(String postData) {
+
+        LBVip vip=null;
+        try {
+            vip=jsonToVip(postData);
+        } catch (IOException e) {
+            log.error("Could not parse JSON {}", e.getMessage());
+        }
+        
+        ILoadBalancerService lbs =
+                (ILoadBalancerService)getContext().getAttributes().
+                    get(ILoadBalancerService.class.getCanonicalName());
+        
+        String vipId = (String) getRequestAttributes().get("vip");
+        if (vipId != null)
+            return lbs.updateVip(vip);
+        else
+            return lbs.createVip(vip);
+    }
+    
+    @Delete
+    public int removeVip() {
+        
+        String vipId = (String) getRequestAttributes().get("vip");
+        
+        ILoadBalancerService lbs =
+                (ILoadBalancerService)getContext().getAttributes().
+                    get(ILoadBalancerService.class.getCanonicalName());
+
+        return lbs.removeVip(vipId);
+    }
+
+    protected LBVip jsonToVip(String json) throws IOException {
+        
+        if (json==null) return null;
+        
+        MappingJsonFactory f = new MappingJsonFactory();
+        JsonParser jp;
+        LBVip vip = new LBVip();
+        
+        try {
+            jp = f.createParser(json);
+        } catch (JsonParseException e) {
+            throw new IOException(e);
+        }
+        
+        jp.nextToken();
+        if (jp.getCurrentToken() != JsonToken.START_OBJECT) {
+            throw new IOException("Expected START_OBJECT");
+        }
+        
+        while (jp.nextToken() != JsonToken.END_OBJECT) {
+            if (jp.getCurrentToken() != JsonToken.FIELD_NAME) {
+                throw new IOException("Expected FIELD_NAME");
+            }
+            
+            String n = jp.getCurrentName();
+            jp.nextToken();
+            if (jp.getText().equals("")) 
+                continue;
+ 
+            if (n.equals("id")) {
+                vip.id = jp.getText();
+                continue;
+            } 
+            if (n.equals("tenant_id")) {
+                vip.tenantId = jp.getText();
+                continue;
+            } 
+            if (n.equals("name")) {
+                vip.name = jp.getText();
+                continue;
+            }
+            if (n.equals("network_id")) {
+                vip.netId = jp.getText();
+                continue;
+            }
+            if (n.equals("protocol")) {
+                String tmp = jp.getText();
+                if (tmp.equalsIgnoreCase("TCP")) {
+                    vip.protocol = (byte) IpProtocol.TCP.getIpProtocolNumber();
+                } else if (tmp.equalsIgnoreCase("UDP")) {
+                    vip.protocol = (byte) IpProtocol.UDP.getIpProtocolNumber();
+                } else if (tmp.equalsIgnoreCase("ICMP")) {
+                    vip.protocol = (byte) IpProtocol.ICMP.getIpProtocolNumber();
+                } 
+                continue;
+            }
+            if (n.equals("address")) {
+                vip.address = IPv4.toIPv4Address(jp.getText());
+                continue;
+            }
+            if (n.equals("port")) {
+                vip.port = Short.parseShort(jp.getText());
+                continue;
+            }
+            if (n.equals("pool_id")) {
+                vip.pools.add(jp.getText());
+                continue;
+            }
+            
+            log.warn("Unrecognized field {} in " +
+                    "parsing Vips", 
+                    jp.getText());
+        }
+        jp.close();
+        
+        return vip;
+    }
+}
diff --git a/src/main/java/net/floodlightcontroller/loadbalancer/LBPool.java b/src/main/java/net/floodlightcontroller/loadbalancer/LBPool.java
index 385ef7908..5a83a8cf6 100644
--- a/src/main/java/net/floodlightcontroller/loadbalancer/LBPool.java
+++ b/src/main/java/net/floodlightcontroller/loadbalancer/LBPool.java
@@ -77,7 +77,7 @@ public class LBPool {
 
 		// Get the members that belong to this pool and the statistics for them
 		if(members.size() > 0){
-			if (lbMethod == STATISTICS && membersbandwidth.values() !=null) {	
+			if (lbMethod == STATISTICS && membersbandwidth != null && membersbandwidth.values() !=null) {	
 				ArrayList<String> poolMembersId = new ArrayList<String>();
 				for(String memberId: membersbandwidth.keySet()){
 					for(int i=0;i<members.size();i++){
@@ -98,7 +98,7 @@ public class LBPool {
 					return poolMembersId.get(bandwidthValues.indexOf(Collections.min(bandwidthValues)));
 				}
 				// simple round robin
-			} else if(lbMethod == ROUND_ROBIN || lbMethod == 0){			
+			} else {			
 				previousMemberIndex = (previousMemberIndex + 1) % members.size();
 				return members.get(previousMemberIndex);
 			}
diff --git a/src/main/java/net/floodlightcontroller/loadbalancer/LoadBalancer.java b/src/main/java/net/floodlightcontroller/loadbalancer/LoadBalancer.java
index b940e115d..abd56ff88 100644
--- a/src/main/java/net/floodlightcontroller/loadbalancer/LoadBalancer.java
+++ b/src/main/java/net/floodlightcontroller/loadbalancer/LoadBalancer.java
@@ -16,6 +16,7 @@
 
 package net.floodlightcontroller.loadbalancer;
 
+import java.nio.ByteBuffer;
 import java.util.ArrayList;
 import java.util.Arrays;
 import java.util.Collection;
@@ -24,7 +25,6 @@ import java.util.HashMap;
 import java.util.HashSet;
 import java.util.List;
 import java.util.Map;
-import java.util.Set;
 
 import org.projectfloodlight.openflow.protocol.OFFlowMod;
 import org.projectfloodlight.openflow.protocol.match.Match;
@@ -65,6 +65,7 @@ import net.floodlightcontroller.devicemanager.IDevice;
 import net.floodlightcontroller.devicemanager.IDeviceService;
 import net.floodlightcontroller.devicemanager.SwitchPort;
 import net.floodlightcontroller.packet.ARP;
+import net.floodlightcontroller.packet.Data;
 import net.floodlightcontroller.packet.Ethernet;
 import net.floodlightcontroller.packet.ICMP;
 import net.floodlightcontroller.packet.IPacket;
@@ -100,6 +101,9 @@ ILoadBalancerService, IOFMessageListener {
 
 	protected static Logger log = LoggerFactory.getLogger(LoadBalancer.class);
 
+	public static String OFPT_ACTION = "ACTION";
+
+
 	// Our dependencies
 	protected IFloodlightProviderService floodlightProviderService;
 	protected IRestApiService restApiService;
@@ -123,8 +127,6 @@ ILoadBalancerService, IOFMessageListener {
 	protected HashMap<IDevice, String> deviceToMemberId;
 
 	//Copied from Forwarding with message damper routine for pushing proxy Arp 
-	protected static int OFMESSAGE_DAMPER_CAPACITY = 10000; // ms. 
-	protected static int OFMESSAGE_DAMPER_TIMEOUT = 250; // ms 
 	protected static String LB_ETHER_TYPE = "0x800";
 	protected static int LB_PRIORITY = 32768;
 
@@ -188,7 +190,7 @@ ILoadBalancerService, IOFMessageListener {
 	private net.floodlightcontroller.core.IListener.Command processPacketIn(IOFSwitch sw, OFPacketIn pi, FloodlightContext cntx) {
 
 		Ethernet eth = IFloodlightProviderService.bcStore.get(cntx, IFloodlightProviderService.CONTEXT_PI_PAYLOAD);
-		IPacket pkt = eth.getPayload(); 
+		IPacket pkt = eth.getPayload(); 	
 
 		if (eth.isBroadcast() || eth.isMulticast()) {
 			// handle ARP for VIP
@@ -212,8 +214,82 @@ ILoadBalancerService, IOFMessageListener {
 				// If match Vip and port, check pool and choose member
 				int destIpAddress = ip_pkt.getDestinationAddress().getInt();
 
+				// HTTP CHECKER AND PARSER 
+				if(pi.getReason().name().equals(OFPT_ACTION)){
+					if (ip_pkt.getPayload() instanceof TCP) {
+						TCP tcppkt = (TCP) ip_pkt.getPayload();
+						if(tcppkt.getDestinationPort().equals(TransportPort.of(80))){
+							Data dte = (Data) tcppkt.getPayload();
+							if(dte.getData().length > 0){
+								if(members != null){
+									// Se o destino e um membro que esteja na pool HTTP !!! MUDAR MAIS TARDE
+									String[] dest_url = null;
+									for(LBMember member:  members.values()){
+										if(IPv4Address.of(destIpAddress).equals(IPv4Address.of(member.address))){
+											dest_url = parseHTTP(dte.getData());
+										}
+									}
+
+									// Only if HTTP request was for VIP that we should pick another member. 
+									if(vipIpToId.containsKey(IPv4.toIPv4Address(dest_url[0]))){
+										log.info("LALALALA UHH");
+										
+										// PARSE URL, IF URL CONTAINS .html , .js , .css to another pool
+										// IF URL CONTAINS .jpg , .png , .xls, .txt , .php, .asp to another pool
+										
+//										IPClient client = new IPClient();
+//										client.ipAddress = ip_pkt.getSourceAddress();
+//										client.nw_proto = ip_pkt.getProtocol();
+//										client.srcPort = tcppkt.getSourcePort();
+//										client.targetPort = tcppkt.getDestinationPort();
+//
+//										LBVip vip = vips.get(vipIpToId.get(destIpAddress));
+//										if (vip == null)			// fix dereference violations           
+//											return Command.CONTINUE;
+//										LBPool pool = pools.get(vip.pickPool(client));
+//										if (pool == null)			// fix dereference violations
+//											return Command.CONTINUE;
+//										LBMember member = members.get(pool.pickMember(client));
+//										if(member == null)			//fix dereference violations
+//											return Command.CONTINUE;
+//										
+//										// for chosen member, check device manager and find and push routes, in both directions                    
+//										pushBidirectionalVipRoutes(sw, pi, cntx, client, member);
+
+										// packet out based on table rule
+//										pushPacket(pkt, sw, pi.getBufferId(), (pi.getVersion().compareTo(OFVersion.OF_12) < 0) ? pi.getInPort() : pi.getMatch().get(MatchField.IN_PORT), OFPort.TABLE,
+//												cntx, true);
+//
+//										return Command.STOP;
+									}
+								}
+							}
+						}
+					}
+				}
+
+				//				int srcIpAddress = ip_pkt.getSourceAddress().getInt();
+				//
+				//				if (vipIpToId.containsKey(srcIpAddress)){
+				//
+				//					OFPacketInReason reason1 = pi.getReason();
+				//					log.info("REASON SOURCE=VIP: {}",reason1.name().toString());
+				//					if (ip_pkt.getPayload() instanceof TCP) {
+				//						TCP tcp_pkt = (TCP) ip_pkt.getPayload();
+				//						log.info("PACKET FROM VIP {}", tcp_pkt );
+				//						Data dte = (Data) tcp_pkt.getPayload();
+				//
+				//						StringBuilder sb = new StringBuilder();
+				//						for (byte b : dte.getData()) {
+				//							sb.append(String.format("%02X ", b));
+				//						}
+				//						log.info("YEAAH {}", sb);
+				//					}
+				//
+				//				}
+
 				if (vipIpToId.containsKey(destIpAddress)){
-					
+
 					// Switch statistics collection to pick a member
 					HashMap<String, U64> memberPortBandwidth = collectSwitchStatistics();
 
@@ -222,6 +298,10 @@ ILoadBalancerService, IOFMessageListener {
 					client.nw_proto = ip_pkt.getProtocol();
 					if (ip_pkt.getPayload() instanceof TCP) {
 						TCP tcp_pkt = (TCP) ip_pkt.getPayload();
+						log.info("PACKET TO VIP {}", tcp_pkt );
+						Data dte = (Data) tcp_pkt.getPayload();
+						log.info("DAFUQ ! {}", dte.getData());
+
 						client.srcPort = tcp_pkt.getSourcePort();
 						client.targetPort = tcp_pkt.getDestinationPort();
 					}
@@ -235,7 +315,6 @@ ILoadBalancerService, IOFMessageListener {
 						client.targetPort = TransportPort.of(0); 
 					}
 
-
 					LBVip vip = vips.get(vipIpToId.get(destIpAddress));
 					if (vip == null)			// fix dereference violations           
 						return Command.CONTINUE;
@@ -246,6 +325,11 @@ ILoadBalancerService, IOFMessageListener {
 					if(member == null)			//fix dereference violations
 						return Command.CONTINUE;
 
+
+					if(client.targetPort.equals(TransportPort.of(80))){
+						log.info("PERANTE UM HTTP");
+
+					}
 					// for chosen member, check device manager and find and push routes, in both directions                    
 					pushBidirectionalVipRoutes(sw, pi, cntx, client, member);
 
@@ -253,6 +337,7 @@ ILoadBalancerService, IOFMessageListener {
 					pushPacket(pkt, sw, pi.getBufferId(), (pi.getVersion().compareTo(OFVersion.OF_12) < 0) ? pi.getInPort() : pi.getMatch().get(MatchField.IN_PORT), OFPort.TABLE,
 							cntx, true);
 
+
 					return Command.STOP;
 				}
 			}
@@ -260,7 +345,7 @@ ILoadBalancerService, IOFMessageListener {
 		// bypass non-load-balanced traffic for normal processing (forwarding)
 		return Command.CONTINUE;
 	}
-	
+
 	/**
 	 * used to collect statistics from members switch port
 	 * @return HashMap<String, U64> portBandwidth <memberId,bitsPerSecond RX> of port connected to member
@@ -283,11 +368,13 @@ ILoadBalancerService, IOFMessageListener {
 		}
 
 		// collect statistics of the switch ports attached to the members
-		if(deviceToMemberId != null){
+		if(deviceToMemberId !=null){
 			for(IDevice membersDevice: deviceToMemberId.keySet()){
 				String memberId = deviceToMemberId.get(membersDevice);
 				for(SwitchPort dstDap: membersDevice.getAttachmentPoints()){
-					portBandwidth.put(memberId, statisticsService.getBandwidthConsumption(dstDap.getNodeId(), dstDap.getPortId()).getBitsPerSecondRx());
+					SwitchPortBandwidth bandwidthOfPort = statisticsService.getBandwidthConsumption(dstDap.getNodeId(), dstDap.getPortId());
+					if(bandwidthOfPort != null) // needs time for 1st collection, this avoids nullPointerException 
+						portBandwidth.put(memberId, bandwidthOfPort.getBitsPerSecondRx());
 				}
 			}
 		}
@@ -389,8 +476,10 @@ ILoadBalancerService, IOFMessageListener {
 			pob.setData(packetData);
 		}
 
+
 		counterPacketOut.increment();
 		sw.write(pob.build());
+
 	}
 
 	/**
@@ -439,6 +528,7 @@ ILoadBalancerService, IOFMessageListener {
 		// Validate that the source and destination are not on the same switchport
 		boolean on_same_island = false;
 		boolean on_same_if = false;
+		//Switch
 		for (SwitchPort dstDap : dstDevice.getAttachmentPoints()) {
 			DatapathId dstSwDpid = dstDap.getNodeId();
 			DatapathId dstIsland = topologyService.getClusterId(dstSwDpid);
@@ -467,7 +557,7 @@ ILoadBalancerService, IOFMessageListener {
 						sw.toString(), pi.getInPort());
 			}
 			return;
-		}
+		}	
 
 		// Install all the routes where both src and dst have attachment
 		// points.  Since the lists are stored in sorted order we can 
@@ -510,11 +600,11 @@ ILoadBalancerService, IOFMessageListener {
 					// out: match dest client (ip, port), rewrite src from member ip/port to vip ip/port, forward
 
 					if (! routeIn.getPath().isEmpty()) {
-						pushStaticVipRoute(true, routeIn, client, member, sw);
+						pushStaticVipRoute(true, routeIn, client, member, sw, pi, cntx);
 					}
 
 					if (! routeOut.getPath().isEmpty()) {
-						pushStaticVipRoute(false, routeOut, client, member, sw);
+						pushStaticVipRoute(false, routeOut, client, member, sw, pi, cntx);
 					}
 
 				}
@@ -537,7 +627,31 @@ ILoadBalancerService, IOFMessageListener {
 	 * @param LBMember member
 	 * @param long pinSwitch
 	 */
-	public void pushStaticVipRoute(boolean inBound, Path route, IPClient client, LBMember member, IOFSwitch pinSwitch) {
+	public void pushStaticVipRoute(boolean inBound, Path route, IPClient client, LBMember member, IOFSwitch pinSwitch,OFPacketIn pi, FloodlightContext cntx) {
+		//		Match.Builder mb1 = pinSwitch.getOFFactory().buildMatch();
+		//
+		//		mb1.setExact(MatchField.ETH_TYPE, EthType.IPv4)
+		//		.setExact(MatchField.IP_PROTO, client.nw_proto)
+		//		.setExact(MatchField.IPV4_SRC, client.ipAddress);
+		//		if (client.nw_proto.equals(IpProtocol.TCP)) {
+		//			mb1.setExact(MatchField.TCP_SRC, client.srcPort);
+		//		} else if (client.nw_proto.equals(IpProtocol.UDP)) {
+		//			mb1.setExact(MatchField.UDP_SRC, client.srcPort);
+		//		} else if (client.nw_proto.equals(IpProtocol.SCTP)) {
+		//			mb1.setExact(MatchField.SCTP_SRC, client.srcPort);
+		//		} else if (client.nw_proto.equals(IpProtocol.ICMP)) {
+		//			/* no-op */
+		//		} else {
+		//			log.error("Unknown IpProtocol {} detected during inbound static VIP route push.", client.nw_proto);
+		//		}
+		//
+		//		U64 cookie = U64.ZERO;
+		//		boolean b = pushRoute(route, mb1.build(), pi, pinSwitch.getId(), cookie, 
+		//				cntx, false,
+		//				OFFlowModCommand.ADD);
+		//		log.info("pushed? : {}", b);
+
+
 		List<NodePortTuple> path = route.getPath();
 		if (path.size() > 0) {
 			for (int i = 0; i < path.size(); i+=2) {
@@ -548,8 +662,8 @@ ILoadBalancerService, IOFMessageListener {
 
 				OFFlowMod.Builder fmb = pinSwitch.getOFFactory().buildFlowAdd();
 
-				fmb.setIdleTimeout(FlowModUtils.INFINITE_TIMEOUT);
-				fmb.setHardTimeout(FlowModUtils.INFINITE_TIMEOUT);
+				fmb.setIdleTimeout(5);//FlowModUtils.INFINITE_TIMEOUT);
+				fmb.setHardTimeout(0);//FlowModUtils.INFINITE_TIMEOUT);
 				fmb.setBufferId(OFBufferId.NO_BUFFER);
 				fmb.setOutPort(OFPort.ANY);
 				fmb.setCookie(U64.of(0));  
@@ -578,7 +692,7 @@ ILoadBalancerService, IOFMessageListener {
 
 
 					if (sw.equals(pinSwitch.getId())) {
-						if (pinSwitch.getOFFactory().getVersion().compareTo(OFVersion.OF_12) < 0) { 
+						if (pinSwitch.getOFFactory().getVersion().compareTo(OFVersion.OF_12) < 0) {
 							actions.add(pinSwitch.getOFFactory().actions().setDlDst(MacAddress.of(member.macString)));
 							actions.add(pinSwitch.getOFFactory().actions().setNwDst(IPv4Address.of(member.address)));
 							actions.add(pinSwitch.getOFFactory().actions().output(path.get(i+1).getPortId(), Integer.MAX_VALUE));
@@ -586,6 +700,7 @@ ILoadBalancerService, IOFMessageListener {
 							actions.add(pinSwitch.getOFFactory().actions().setField(pinSwitch.getOFFactory().oxms().ethDst(MacAddress.of(member.macString))));
 							actions.add(pinSwitch.getOFFactory().actions().setField(pinSwitch.getOFFactory().oxms().ipv4Dst(IPv4Address.of(member.address))));
 							actions.add(pinSwitch.getOFFactory().actions().output(path.get(i+1).getPortId(), Integer.MAX_VALUE));
+							actions.add(pinSwitch.getOFFactory().actions().output(OFPort.CONTROLLER, Integer.MAX_VALUE));
 						}
 					} else {
 						//fix concurrency errors
@@ -603,6 +718,7 @@ ILoadBalancerService, IOFMessageListener {
 					mb.setExact(MatchField.ETH_TYPE, EthType.IPv4)
 					.setExact(MatchField.IP_PROTO, client.nw_proto)
 					.setExact(MatchField.IPV4_DST, client.ipAddress)
+					//.setExact(MatchField.IPV4_SRC, IPv4Address.of(vips.get(member.vipId).address)) //!!
 					.setExact(MatchField.IN_PORT, path.get(i).getPortId());
 					if (client.nw_proto.equals(IpProtocol.TCP)) {
 						mb.setExact(MatchField.TCP_DST, client.srcPort);
@@ -624,7 +740,9 @@ ILoadBalancerService, IOFMessageListener {
 						} else { // OXM introduced in OF1.2
 							actions.add(pinSwitch.getOFFactory().actions().setField(pinSwitch.getOFFactory().oxms().ethSrc(vips.get(member.vipId).proxyMac)));
 							actions.add(pinSwitch.getOFFactory().actions().setField(pinSwitch.getOFFactory().oxms().ipv4Src(IPv4Address.of(vips.get(member.vipId).address))));
+							//actions.add(pinSwitch.getOFFactory().actions().output(OFPort.CONTROLLER, Integer.MAX_VALUE));
 							actions.add(pinSwitch.getOFFactory().actions().output(path.get(i+1).getPortId(), Integer.MAX_VALUE));
+
 						}
 					} else {
 						//fix concurrency errors
@@ -642,12 +760,169 @@ ILoadBalancerService, IOFMessageListener {
 				fmb.setActions(actions);
 				fmb.setPriority(U16.t(LB_PRIORITY));
 				fmb.setMatch(mb.build());
+				//pinSwitch.write(fmb.build());
+				//messageDamper.write(pinSwitch, fmb.build());
 				sfpService.addFlow(entryName, fmb.build(), sw);
 			}
 		}
+
 		return;
 	}
 
+	//
+	//	private boolean pushRoute(Path route, Match  match, OFPacketIn pi, DatapathId pinSwitch, U64 cookie, FloodlightContext cntx,
+	//			boolean requestFlowRemovedNotification, OFFlowModCommand add) {
+	//
+	//
+	//		boolean packetOutSent = false;
+	//
+	//		List<NodePortTuple> switchPortList = route.getPath();
+	//
+	//		for (int indx = switchPortList.size() - 1; indx > 0; indx -= 2) {
+	//			// indx and indx-1 will always have the same switch DPID.
+	//			DatapathId switchDPID = switchPortList.get(indx).getNodeId();
+	//			IOFSwitch sw = switchService.getSwitch(switchDPID);
+	//
+	//			if (sw == null) {
+	//				if (log.isWarnEnabled()) {
+	//					log.warn("Unable to push route, switch at DPID {} " + "not available", switchDPID);
+	//				}
+	//				return packetOutSent;
+	//			}
+	//			OFFlowMod.Builder fmb;
+	//			fmb = sw.getOFFactory().buildFlowAdd();
+	//
+	//			OFActionOutput.Builder aob = sw.getOFFactory().actions().buildOutput();
+	//			List<OFAction> actions = new ArrayList<OFAction>();	
+	//			Match.Builder mb = MatchUtils.convertToVersion(match, sw.getOFFactory().getVersion());
+	//
+	//			// set input and output ports on the switch
+	//			OFPort outPort = switchPortList.get(indx).getPortId();
+	//			OFPort inPort = switchPortList.get(indx - 1).getPortId();
+	//			if (FLOWMOD_DEFAULT_MATCH_IN_PORT) {
+	//				mb.setExact(MatchField.IN_PORT, inPort);
+	//			}
+	//			aob.setPort(outPort);
+	//			aob.setMaxLen(Integer.MAX_VALUE);
+	//			actions.add(aob.build());
+	//
+	//			if (FLOWMOD_DEFAULT_SET_SEND_FLOW_REM_FLAG || requestFlowRemovedNotification) {
+	//				Set<OFFlowModFlags> flags = new HashSet<>();
+	//				flags.add(OFFlowModFlags.SEND_FLOW_REM);
+	//				fmb.setFlags(flags);
+	//			}
+	//
+	//			fmb.setMatch(mb.build())
+	//			.setIdleTimeout(FLOWMOD_DEFAULT_IDLE_TIMEOUT)
+	//			.setHardTimeout(FLOWMOD_DEFAULT_HARD_TIMEOUT)
+	//			.setBufferId(OFBufferId.NO_BUFFER)
+	//			.setCookie(cookie)
+	//			.setOutPort(outPort)
+	//			.setPriority(FLOWMOD_DEFAULT_PRIORITY);
+	//
+	//			FlowModUtils.setActions(fmb, actions, sw);
+	//
+	//			/* Configure for particular switch pipeline */
+	//			if (sw.getOFFactory().getVersion().compareTo(OFVersion.OF_10) != 0) {
+	//				fmb.setTableId(FLOWMOD_DEFAULT_TABLE_ID);
+	//			}
+	//
+	//			if (log.isTraceEnabled()) {
+	//				log.trace("Pushing Route flowmod routeIndx={} " +
+	//						"sw={} inPort={} outPort={}",
+	//						new Object[] {indx,
+	//								sw,
+	//								fmb.getMatch().get(MatchField.IN_PORT),
+	//								outPort });
+	//			}
+	//
+	//			if (OFDPAUtils.isOFDPASwitch(sw)) {
+	//				OFDPAUtils.addLearningSwitchFlow(sw, cookie, 
+	//						FLOWMOD_DEFAULT_PRIORITY, 
+	//						FLOWMOD_DEFAULT_HARD_TIMEOUT,
+	//						FLOWMOD_DEFAULT_IDLE_TIMEOUT,
+	//						fmb.getMatch(), 
+	//						null, 
+	//						outPort);
+	//			} else {
+	//				messageDamper.write(sw, fmb.build());
+	//			}
+	//
+	//			/* Push the packet out the first hop switch */
+	//			if (sw.getId().equals(pinSwitch) &&
+	//					!fmb.getCommand().equals(OFFlowModCommand.DELETE) &&
+	//					!fmb.getCommand().equals(OFFlowModCommand.DELETE_STRICT)) {
+	//				/* Use the buffered packet at the switch, if there's one stored */
+	//				pushPacket(sw, pi, outPort, true, cntx);
+	//				packetOutSent = true;
+	//			}
+	//		}
+	//
+	//		return packetOutSent;
+	//	}
+	//
+	//	private void pushPacket(IOFSwitch sw, OFPacketIn pi, OFPort outPort, boolean useBufferedPacket, FloodlightContext cntx) {
+	//		if (pi == null) {
+	//            return;
+	//        }
+	//
+	//        // The assumption here is (sw) is the switch that generated the
+	//        // packet-in. If the input port is the same as output port, then
+	//        // the packet-out should be ignored.
+	//        if ((pi.getVersion().compareTo(OFVersion.OF_12) < 0 ? pi.getInPort() : pi.getMatch().get(MatchField.IN_PORT)).equals(outPort)) {
+	//            if (log.isDebugEnabled()) {
+	//                log.debug("Attempting to do packet-out to the same " +
+	//                        "interface as packet-in. Dropping packet. " +
+	//                        " SrcSwitch={}, pi={}",
+	//                        new Object[]{sw, pi});
+	//                return;
+	//            }
+	//        }
+	//
+	//        if (log.isTraceEnabled()) {
+	//            log.trace("PacketOut srcSwitch={} pi={}",
+	//                    new Object[] {sw, pi});
+	//        }
+	//
+	//        OFPacketOut.Builder pob = sw.getOFFactory().buildPacketOut();
+	//        List<OFAction> actions = new ArrayList<OFAction>();
+	//        actions.add(sw.getOFFactory().actions().output(outPort, Integer.MAX_VALUE));
+	//        pob.setActions(actions);
+	//
+	//        /* Use packet in buffer if there is a buffer ID set */
+	//        if (useBufferedPacket) {
+	//            pob.setBufferId(pi.getBufferId()); /* will be NO_BUFFER if there isn't one */
+	//        } else {
+	//            pob.setBufferId(OFBufferId.NO_BUFFER);
+	//        }
+	//
+	//        if (pob.getBufferId().equals(OFBufferId.NO_BUFFER)) {
+	//            byte[] packetData = pi.getData();
+	//            pob.setData(packetData);
+	//        }
+	//
+	//        pob.setInPort((pi.getVersion().compareTo(OFVersion.OF_12) < 0 ? pi.getInPort() : pi.getMatch().get(MatchField.IN_PORT)));
+	//
+	//        messageDamper.write(sw, pob.build());
+	//		
+	//	}
+
+	public String[] parseHTTP(byte[] data){
+		// TODO THIS IS REQUEST ,WHAT IF A RESPONSE COMES ?!
+		String path;
+		String destination;
+		String http = new String(data);
+
+		String [] http_fields= http.split("\n");
+		path = http_fields[0].substring(http_fields[0].indexOf(" ")+1,http_fields[0].lastIndexOf(" ", http_fields[0].length()));
+
+		destination = http_fields[3].substring(http_fields[3].indexOf(" ")+1,http_fields[3].length()-1);
+		String [] dest_path = {destination, path};
+
+		return dest_path;
+	}
+
+
 
 	@Override
 	public Collection<LBVip> listVips() {
@@ -861,6 +1136,7 @@ ILoadBalancerService, IOFMessageListener {
 		l.add(ITopologyService.class);
 		l.add(IRoutingService.class);
 		l.add(IStaticEntryPusherService.class);
+		l.add(IStatisticsService.class);
 
 		return l;
 	}
@@ -878,7 +1154,6 @@ ILoadBalancerService, IOFMessageListener {
 		switchService = context.getServiceImpl(IOFSwitchService.class);
 		statisticsService = context.getServiceImpl(IStatisticsService.class);
 
-
 		vips = new HashMap<String, LBVip>();
 		pools = new HashMap<String, LBPool>();
 		members = new HashMap<String, LBMember>();
diff --git a/src/main/java/net/floodlightcontroller/loadbalancer/LoadBalancerWebRoutable.java b/src/main/java/net/floodlightcontroller/loadbalancer/LoadBalancerWebRoutable.java
index 52c5f567d..07f701b23 100644
--- a/src/main/java/net/floodlightcontroller/loadbalancer/LoadBalancerWebRoutable.java
+++ b/src/main/java/net/floodlightcontroller/loadbalancer/LoadBalancerWebRoutable.java
@@ -36,7 +36,11 @@ public class LoadBalancerWebRoutable implements RestletRoutable {
         router.attach("/members/{member}", MembersResource.class); // GET, PUT, DELETE
         router.attach("/pools/{pool}/members", PoolMemberResource.class); //GET
         router.attach("/health_monitors/", MonitorsResource.class); //GET, POST
-        router.attach("/health_monitors/{monitor}", MonitorsResource.class); //GET, PUT, DELETE        
+        router.attach("/health_monitors/{monitor}", MonitorsResource.class); //GET, PUT, DELETE
+        router.attach("/l7rules/", L7RulesResource.class); //GET, PUT, DELETE 
+        router.attach("/l7rules/{rule}", L7RulesResource.class); //GET, PUT, DELETE
+        router.attach("/l7policies/", L7RulesResource.class); //GET, PUT, DELETE 
+        router.attach("/l7policies/{policy}", L7RulesResource.class); //GET, PUT, DELETE
         router.attachDefault(NoOp.class);
         return router;
      }
diff --git a/src/main/java/net/floodlightcontroller/packet/HTTP.java b/src/main/java/net/floodlightcontroller/packet/HTTP.java
new file mode 100644
index 000000000..9b01ee1c8
--- /dev/null
+++ b/src/main/java/net/floodlightcontroller/packet/HTTP.java
@@ -0,0 +1,104 @@
+package net.floodlightcontroller.packet;
+
+import java.nio.ByteBuffer;
+
+import org.projectfloodlight.openflow.types.IpProtocol;
+import org.projectfloodlight.openflow.types.TransportPort;
+
+/**
+ * @author Diogo Coutinho (diogo.m.coutinho@tecnico.ulisboa.pt)
+ *
+ */
+public class HTTP extends BasePacket {
+	
+	protected byte method;
+	protected byte uri;
+	protected byte version;
+	protected short host; // IP DO SERVER
+    // SP = (short) 20 
+	// CRLF = 0d 0a 
+
+	@Override
+	public byte[] serialize() {
+		 int length;
+//	        if (dataOffset == 0)
+//	            dataOffset = 5;  // default header length
+//	        length = dataOffset << 2;
+//	        byte[] payloadData = null;
+//	        if (payload != null) {
+//	            payload.setParent(this);
+//	           
+//	            payloadData = payload.serialize();
+//	            length += payloadData.length;
+//	        }
+//
+//	        byte[] data = new byte[length];
+//	        ByteBuffer bb = ByteBuffer.wrap(data);
+//
+//	        bb.putShort((short)this.sourcePort.getPort()); //TCP ports are defined to be 16 bits
+//	        bb.putShort((short)this.destinationPort.getPort());
+//	        bb.putInt(this.sequence);
+//	        bb.putInt(this.acknowledge);
+//	        bb.putShort((short) (this.flags | (dataOffset << 12)));
+//	        bb.putShort(this.windowSize);
+//	        bb.putShort(this.checksum);
+//	        bb.putShort(this.urgentPointer);
+//	        if (dataOffset > 5) {
+//	            int padding;
+//	            bb.put(options);
+//	            padding = (dataOffset << 2) - 20 - options.length;
+//	            for (int i = 0; i < padding; i++)
+//	                bb.put((byte) 0);
+//	        }
+//	        if (payloadData != null)
+//	            bb.put(payloadData);
+//
+//	        if (this.parent != null && this.parent instanceof IPv4)
+//	            ((IPv4)this.parent).setProtocol(IpProtocol.TCP);
+//	        
+//	        return data;
+		 return null;
+	}
+
+	@Override
+	public IPacket deserialize(byte[] data, int offset, int length) throws PacketParsingException {
+		 ByteBuffer bb = ByteBuffer.wrap(data, offset, length);
+		 
+		 
+		 
+//	        this.sourcePort = TransportPort.of((int) (bb.getShort() & 0xffff)); // short will be signed, pos or neg
+//	        this.destinationPort = TransportPort.of((int) (bb.getShort() & 0xffff)); // convert range 0 to 65534, not -32768 to 32767
+//	        this.sequence = bb.getInt();
+//	        this.acknowledge = bb.getInt();
+//	        this.flags = bb.getShort();
+//	        this.dataOffset = (byte) ((this.flags >> 12) & 0xf);
+//	        if (this.dataOffset < 5) {
+//	            throw new PacketParsingException("Invalid tcp header length < 20");
+//	        }
+//	        this.flags = (short) (this.flags & 0x1ff);
+//	        this.windowSize = bb.getShort();
+//	        this.checksum = bb.getShort();
+//	        this.urgentPointer = bb.getShort();
+//	        if (this.dataOffset > 5) {
+//	            int optLength = (dataOffset << 2) - 20;
+//	            if (bb.limit() < bb.position()+optLength) {
+//	                optLength = bb.limit() - bb.position();
+//	            }
+//	            try {
+//	                this.options = new byte[optLength];
+//	                bb.get(this.options, 0, optLength);
+//	            } catch (IndexOutOfBoundsException e) {
+//	                this.options = null;
+//	            }
+//	        }
+	                        
+	        this.payload = new Data();
+	        int remLength = bb.limit()-bb.position();
+	        this.payload = payload.deserialize(data, bb.position(), remLength);
+
+	        log.info("HTTP payload : {}", this.payload);
+	        
+	        this.payload.setParent(this);
+	        return this;
+	}
+}
\ No newline at end of file
diff --git a/src/main/java/net/floodlightcontroller/packet/TCP.java b/src/main/java/net/floodlightcontroller/packet/TCP.java
index 1fdf1aafd..3d2f4805e 100644
--- a/src/main/java/net/floodlightcontroller/packet/TCP.java
+++ b/src/main/java/net/floodlightcontroller/packet/TCP.java
@@ -178,6 +178,7 @@ public class TCP extends BasePacket {
         byte[] payloadData = null;
         if (payload != null) {
             payload.setParent(this);
+           
             payloadData = payload.serialize();
             length += payloadData.length;
         }
@@ -379,7 +380,7 @@ public class TCP extends BasePacket {
     @Override
     public IPacket deserialize(byte[] data, int offset, int length)
             throws PacketParsingException {
-        ByteBuffer bb = ByteBuffer.wrap(data, offset, length);
+        ByteBuffer bb = ByteBuffer.wrap(data, offset, length);        
         this.sourcePort = TransportPort.of((int) (bb.getShort() & 0xffff)); // short will be signed, pos or neg
         this.destinationPort = TransportPort.of((int) (bb.getShort() & 0xffff)); // convert range 0 to 65534, not -32768 to 32767
         this.sequence = bb.getInt();
@@ -405,11 +406,12 @@ public class TCP extends BasePacket {
                 this.options = null;
             }
         }
-
+                        
         this.payload = new Data();
         int remLength = bb.limit()-bb.position();
         this.payload = payload.deserialize(data, bb.position(), remLength);
+        
         this.payload.setParent(this);
         return this;
-    }
+    }   
 }
diff --git a/src/main/java/net/floodlightcontroller/routing/ForwardingBase.java b/src/main/java/net/floodlightcontroller/routing/ForwardingBase.java
index a624f2119..aa104bc19 100644
--- a/src/main/java/net/floodlightcontroller/routing/ForwardingBase.java
+++ b/src/main/java/net/floodlightcontroller/routing/ForwardingBase.java
@@ -341,7 +341,6 @@ public abstract class ForwardingBase implements IOFMessageListener {
         }
 
         pob.setInPort((pi.getVersion().compareTo(OFVersion.OF_12) < 0 ? pi.getInPort() : pi.getMatch().get(MatchField.IN_PORT)));
-
         messageDamper.write(sw, pob.build());
     }
 
diff --git a/src/main/resources/floodlightdefault.properties b/src/main/resources/floodlightdefault.properties
index 87e5b868a..3955d03c5 100644
--- a/src/main/resources/floodlightdefault.properties
+++ b/src/main/resources/floodlightdefault.properties
@@ -50,10 +50,10 @@ net.floodlightcontroller.core.internal.OFSwitchManager.defaultMaxTablesToReceive
 net.floodlightcontroller.core.internal.OFSwitchManager.maxTablesToReceiveTableMissFlowPerDpid={"00:00:00:00:00:00:00:01":"1","2":"1"}
 net.floodlightcontroller.core.internal.OFSwitchManager.clearTablesOnInitialHandshakeAsMaster=YES
 net.floodlightcontroller.core.internal.OFSwitchManager.clearTablesOnEachTransitionToMaster=YES
-net.floodlightcontroller.core.internal.OFSwitchManager.keyStorePath=/path/to.jecks
-net.floodlightcontroller.core.internal.OFSwitchManager.keyStorePassword=PassFL
+net.floodlightcontroller.core.internal.OFSwitchManager.keyStorePath=/home/diogo/Documents/fdl/floodlight/keystore.jks
+net.floodlightcontroller.core.internal.OFSwitchManager.keyStorePassword=diogo123
 net.floodlightcontroller.core.internal.OFSwitchManager.useSsl=NO
-net.floodlightcontroller.core.internal.OFSwitchManager.supportedOpenFlowVersions=1.0, 1.1, 1.2, 1.3, 1.4, 1.5
+net.floodlightcontroller.core.internal.OFSwitchManager.supportedOpenFlowVersions=1.0, 1.1, 1.2, 1.3
 net.floodlightcontroller.core.internal.OFSwitchManager.switchesInitialState={"00:00:00:00:00:00:00:01":"ROLE_MASTER","00:00:00:00:00:00:00:02":"ROLE_MASTER", "00:00:00:00:00:00:00:03":"ROLE_MASTER", "00:00:00:00:00:00:00:04":"ROLE_MASTER","00:00:00:00:00:00:00:05":"ROLE_MASTER"}
 net.floodlightcontroller.restserver.RestApiServer.keyStorePath=/path/to.jceks
 net.floodlightcontroller.restserver.RestApiServer.keyStorePassword=Password
-- 
GitLab