diff --git a/build.xml b/build.xml
index cc45e43ca1cdcb87492d0bc0f0a0ffef9bb71dce..0f95be469b708e6b9763abb7c48783df3a302d98 100644
--- a/build.xml
+++ b/build.xml
@@ -67,6 +67,10 @@
         <include name="jython-2.5.2.jar"/>
         <include name="libthrift-0.7.0.jar"/>
         <include name="guava-13.0.1.jar" />
+	<include name="commons-logging-1.1.1.jar" />
+	<include name="httpclient-4.2.2.jar" />
+	<include name="httpcore-4.2.2.jar" />
+	<include name="json-simple-1.1.1.jar" />
     </patternset>
 
     <path id="classpath">
@@ -140,7 +144,7 @@
         </pathconvert>
         <echo message="Running thrift generator on ${thrift.file.list}"/>
         <exec executable="thrift" dir="${basedir}" failonerror="true">
-            <arg line="--strict -v --gen java -o ${thrift.out.dir}/.. ${thrift.file.list}"/>
+            <arg line="--strict -v --gen java -o ${thrift.out.dir}/.. '${thrift.file.list}'"/>
         </exec>
         <!-- Get rid of annoying warnings in thrift java: at annotations -->
         <echo message="Adding @SuppressWarning annotations"/>
diff --git a/lib/commons-logging-1.1.1.jar b/lib/commons-logging-1.1.1.jar
new file mode 100644
index 0000000000000000000000000000000000000000..1deef144cb17ed2c11c6cdcdcb2d9530fa8d0b47
Binary files /dev/null and b/lib/commons-logging-1.1.1.jar differ
diff --git a/lib/gen-java/net/floodlightcontroller/packetstreamer/thrift/OFMessageType.java b/lib/gen-java/net/floodlightcontroller/packetstreamer/thrift/OFMessageType.java
index b9b2843485cfbb2e925eae132a5c4ff127853b32..ebbb6c166dd2a844acfe188dea42886f88372ff4 100644
--- a/lib/gen-java/net/floodlightcontroller/packetstreamer/thrift/OFMessageType.java
+++ b/lib/gen-java/net/floodlightcontroller/packetstreamer/thrift/OFMessageType.java
@@ -34,7 +34,9 @@ import org.apache.thrift.TEnum;
   STATS_REQUEST(16),
   STATS_REPLY(17),
   BARRIER_REQUEST(18),
-  BARRIER_REPLY(19);
+  BARRIER_REPLY(19),
+  QUEUE_GET_CONFIG_REQUEST(20),
+  QUEUE_GET_CONFIG_REPLY(21);
 
   private final int value;
 
@@ -95,6 +97,10 @@ import org.apache.thrift.TEnum;
         return BARRIER_REQUEST;
       case 19:
         return BARRIER_REPLY;
+      case 20:
+        return QUEUE_GET_CONFIG_REQUEST;
+      case 21:
+        return QUEUE_GET_CONFIG_REPLY;
       default:
         return null;
     }
diff --git a/lib/httpclient-4.2.2.jar b/lib/httpclient-4.2.2.jar
new file mode 100644
index 0000000000000000000000000000000000000000..5f768c46407a6506d46766d1011f2fac342ec333
Binary files /dev/null and b/lib/httpclient-4.2.2.jar differ
diff --git a/lib/httpcore-4.2.2.jar b/lib/httpcore-4.2.2.jar
new file mode 100644
index 0000000000000000000000000000000000000000..a64cd2f5e3eff5ea0ff91a545ba2da4dc3fd612b
Binary files /dev/null and b/lib/httpcore-4.2.2.jar differ
diff --git a/lib/json-simple-1.1.1.jar b/lib/json-simple-1.1.1.jar
new file mode 100644
index 0000000000000000000000000000000000000000..66347a6c86b7d6442358ca7643e4dc484fb01866
Binary files /dev/null and b/lib/json-simple-1.1.1.jar differ
diff --git a/setup-eclipse.sh b/setup-eclipse.sh
index a39dc62d692e958b5747c35392e2851a150d306b..de92c3493d07eef70b89d8f721153bd134490fad 100755
--- a/setup-eclipse.sh
+++ b/setup-eclipse.sh
@@ -1,12 +1,11 @@
 #!/bin/bash
-
-d=$(dirname $0)
+d=$(dirname "$0")
 MAIN_CLASS=$1
 LIBRARIES=$2
 [ "${MAIN_CLASS}" ] || { echo "Run 'ant eclipse' to generate Eclipse project files"; exit 1; }
 
 
-cat >$d/.project <<EOF
+cat >"$d/.project" <<EOF
 <?xml version="1.0" encoding="UTF-8"?>
 <projectDescription>
 	<name>floodlight</name>
@@ -27,7 +26,7 @@ cat >$d/.project <<EOF
 EOF
 
 
-cat >$d/.classpath <<EOF
+cat >"$d/.classpath" <<EOF
 <?xml version="1.0" encoding="UTF-8"?>
 <classpath>
 	<classpathentry kind="src" path="src/main/java" output="target/bin"/>
@@ -43,7 +42,7 @@ cat >>$d/.classpath <<EOF
 EOF
 done
 )
-cat >>$d/.classpath <<EOF
+cat >>"$d/.classpath" <<EOF
 	<classpathentry exported="true" kind="con" path="org.eclipse.jdt.launching.JRE_CONTAINER"/>
 	<classpathentry kind="output" path="target/bin"/>
 </classpath>
diff --git a/src/main/java/net/floodlightcontroller/loadbalancer/ILoadBalancerService.java b/src/main/java/net/floodlightcontroller/loadbalancer/ILoadBalancerService.java
new file mode 100644
index 0000000000000000000000000000000000000000..c88ee382a232f4113520227925a57a8f41d1ee07
--- /dev/null
+++ b/src/main/java/net/floodlightcontroller/loadbalancer/ILoadBalancerService.java
@@ -0,0 +1,142 @@
+package net.floodlightcontroller.loadbalancer;
+
+import java.util.Collection;
+
+import net.floodlightcontroller.core.module.IFloodlightService;
+
+public interface ILoadBalancerService extends IFloodlightService {
+
+    /**
+     * List all current Vips.
+     */
+    public Collection<LBVip> listVips();
+
+    /**
+     * List selected Vip by its ID.
+     * @param vipId Id of requested Vip
+     */
+    public Collection<LBVip> listVip(String vipId);
+
+    /**
+     * Create and return a new Vip.
+     * @param LBVip vip: data structure with caller provided Vip attributes 
+     * @return LBVip: Created Vip 
+     */
+    public LBVip createVip(LBVip vip);
+
+    /**
+     * Update and return an existing Vip.
+     * @param LBVip vip: data structure with caller provided Vip attributes 
+     * @return LBVip: Updated Vip 
+     */
+    public LBVip updateVip(LBVip vip);
+
+    /**
+     * Remove an existing Vip.
+     * @param String vipId  
+     * @return int: removal status 
+     */
+    public int removeVip(String vipId);
+
+    /**
+     * List all current pools.
+     */
+    public Collection<LBPool> listPools();
+
+    /**
+     * List selected pool by its ID.
+     * @param poolId Id of requested pool
+     */
+    public Collection<LBPool> listPool(String poolId);
+
+    /**
+     * Create and return a new pool.
+     * @param LBPool pool: data structure with caller provided pool attributes 
+     * @return LBPool: Created pool 
+     */
+    public LBPool createPool(LBPool pool);
+
+    /**
+     * Update and return an existing pool.
+     * @param LBPool pool: data structure with caller provided pool attributes 
+     * @return LBPool: Updated pool 
+     */
+    public LBPool updatePool(LBPool pool);
+
+    /**
+     * Remove an existing pool.
+     * @param String poolId 
+     * @return int: removal status 
+     */
+    public int removePool(String poolId);
+    
+    /**
+     * List all current members.
+     */
+    public Collection<LBMember> listMembers();
+
+    /**
+     * List selected member by its ID.
+     * @param memberId Id of requested member
+     */
+    public Collection<LBMember> listMember(String memberId);
+
+    /**
+     * List all members in a specified pool.
+     */
+    public Collection<LBMember> listMembersByPool(String poolId);
+    
+    /**
+     * Create and return a new member.
+     * @param LBMember member: data structure with caller provided member attributes 
+     * @return LBMember: Created member 
+     */
+    public LBMember createMember(LBMember member);
+
+    /**
+     * Update and return an existing member.
+     * @param LBMember member: data structure with caller provided member attributes 
+     * @return LBMember: Updated member 
+     */
+    public LBMember updateMember(LBMember member);
+
+    /**
+     * Remove an existing member.
+     * @param String memberId 
+     * @return int: removal status 
+     */
+    public int removeMember(String memberId);
+    
+    /**
+     * List all current monitors.
+     */
+    public Collection<LBMonitor> listMonitors();
+
+    /**
+     * List selected monitor by its ID.
+     * @param monitorId Id of requested monitor
+     */
+    public Collection<LBMonitor> listMonitor(String monitorId);
+
+    /**
+     * Create and return a new monitor.
+     * @param LBMonitor monitor: data structure with caller provided monitor attributes 
+     * @return LBMonitor: Created monitor 
+     */
+    public LBMonitor createMonitor(LBMonitor monitor);
+
+    /**
+     * Update and return an existing monitor.
+     * @param LBMonitor monitor: data structure with caller provided pool attributes 
+     * @return LBMonitor: Updated monitor 
+     */
+    public LBMonitor updateMonitor(LBMonitor monitor);
+
+    /**
+     * Remove an existing monitor.
+     * @param String monitorId 
+     * @return int: removal status 
+     */
+    public int removeMonitor(String monitorId);
+
+}
diff --git a/src/main/java/net/floodlightcontroller/loadbalancer/LBMember.java b/src/main/java/net/floodlightcontroller/loadbalancer/LBMember.java
new file mode 100644
index 0000000000000000000000000000000000000000..d1109dea262c7b111876353968dd7096b2039188
--- /dev/null
+++ b/src/main/java/net/floodlightcontroller/loadbalancer/LBMember.java
@@ -0,0 +1,38 @@
+package net.floodlightcontroller.loadbalancer;
+
+import org.codehaus.jackson.map.annotate.JsonSerialize;
+
+/**
+ * Data structure for Load Balancer based on
+ * Quantum proposal http://wiki.openstack.org/LBaaS/CoreResourceModel/proposal 
+ * 
+ * @author KC Wang
+ */
+
+@JsonSerialize(using=LBMemberSerializer.class)
+public class LBMember {
+    protected String id;
+    protected int address;
+    protected short port;
+    protected String macString;
+    
+    protected int connectionLimit;
+    protected short adminState;
+    protected short status;
+
+    protected String poolId;
+    protected String vipId;
+    
+    public LBMember() {
+        id = String.valueOf((int) (Math.random()*10000));
+        address = 0;
+        macString = null;
+        port = 0;
+        
+        connectionLimit = 0;
+        adminState = 0;
+        status = 0;
+        poolId = null;
+        vipId = null;
+    }
+}
diff --git a/src/main/java/net/floodlightcontroller/loadbalancer/LBMemberSerializer.java b/src/main/java/net/floodlightcontroller/loadbalancer/LBMemberSerializer.java
new file mode 100644
index 0000000000000000000000000000000000000000..a0726df2eb1b4a28b9d7fb817c281c1b65d5f64a
--- /dev/null
+++ b/src/main/java/net/floodlightcontroller/loadbalancer/LBMemberSerializer.java
@@ -0,0 +1,27 @@
+package net.floodlightcontroller.loadbalancer;
+
+import java.io.IOException;
+
+import org.codehaus.jackson.JsonGenerator;
+import org.codehaus.jackson.JsonProcessingException;
+import org.codehaus.jackson.map.JsonSerializer;
+import org.codehaus.jackson.map.SerializerProvider;
+
+public class LBMemberSerializer extends JsonSerializer<LBMember>{
+
+    @Override
+    public void serialize(LBMember member, JsonGenerator jGen,
+                          SerializerProvider serializer) throws IOException,
+                                                  JsonProcessingException {
+        jGen.writeStartObject();
+        
+        jGen.writeStringField("id", member.id);
+        jGen.writeStringField("address", String.valueOf(member.address));
+        jGen.writeStringField("port", Short.toString(member.port));
+        jGen.writeStringField("poolId", member.poolId);
+        jGen.writeStringField("vipId", member.vipId);
+
+        jGen.writeEndObject();        
+    }
+
+}
diff --git a/src/main/java/net/floodlightcontroller/loadbalancer/LBMonitor.java b/src/main/java/net/floodlightcontroller/loadbalancer/LBMonitor.java
new file mode 100644
index 0000000000000000000000000000000000000000..f246f962266554236bdeea9ef1bc486012159cdd
--- /dev/null
+++ b/src/main/java/net/floodlightcontroller/loadbalancer/LBMonitor.java
@@ -0,0 +1,44 @@
+package net.floodlightcontroller.loadbalancer;
+
+/**
+ * Data structure for Load Balancer based on
+ * Quantum proposal http://wiki.openstack.org/LBaaS/CoreResourceModel/proposal 
+ * 
+ * @author KC Wang
+ */
+
+public class LBMonitor {
+    protected String id;
+    protected String name;
+    protected short type;
+    protected short delay;
+    protected short timeout;
+    protected short attemptsBeforeDeactivation;
+    
+    protected String netId;
+    protected int address;
+    protected byte protocol;
+    protected short port;
+
+    //protected path??
+    
+    protected short adminState;
+    protected short status;
+
+    public LBMonitor() {
+        id = null;
+        name = null;
+        type = 0;
+        delay = 0;
+        timeout = 0;
+        attemptsBeforeDeactivation = 0;
+        netId = null;
+        address = 0;
+        protocol = 0;
+        port = 0;
+        adminState = 0;
+        status = 0;
+        
+    }
+    
+}
diff --git a/src/main/java/net/floodlightcontroller/loadbalancer/LBPool.java b/src/main/java/net/floodlightcontroller/loadbalancer/LBPool.java
new file mode 100644
index 0000000000000000000000000000000000000000..f628765ed2ccdc98b90572e0dd990029ffe4eee6
--- /dev/null
+++ b/src/main/java/net/floodlightcontroller/loadbalancer/LBPool.java
@@ -0,0 +1,58 @@
+package net.floodlightcontroller.loadbalancer;
+
+import java.util.ArrayList;
+
+import org.codehaus.jackson.map.annotate.JsonSerialize;
+
+import net.floodlightcontroller.loadbalancer.LoadBalancer.IPClient;
+
+/**
+ * Data structure for Load Balancer based on
+ * Quantum proposal http://wiki.openstack.org/LBaaS/CoreResourceModel/proposal 
+ * 
+ * @author KC Wang
+ */
+
+
+@JsonSerialize(using=LBPoolSerializer.class)
+public class LBPool {
+    protected String id;
+    protected String name;
+    protected String tenantId;
+    protected String netId;
+    protected short lbMethod;
+    protected byte protocol;
+    protected ArrayList<String> members;
+    protected ArrayList<String> monitors;
+    protected short adminState;
+    protected short status;    
+    
+    protected String vipId;
+    
+    protected int previousMemberIndex;
+    
+    public LBPool() {
+        id = String.valueOf((int) (Math.random()*10000));
+        name = null;
+        tenantId = null;
+        netId = null;
+        lbMethod = 0;
+        protocol = 0;
+        members = new ArrayList<String>();
+        monitors = new ArrayList<String>();
+        adminState = 0;
+        status = 0;
+        previousMemberIndex = -1;
+    }
+    
+    public String pickMember(IPClient client) {
+        // simple round robin for now; add different lbmethod later
+        if (members.size() > 0) {
+            previousMemberIndex = (previousMemberIndex + 1) % members.size();
+            return members.get(previousMemberIndex);
+        } else {
+            return null;
+        }
+    }
+
+}
diff --git a/src/main/java/net/floodlightcontroller/loadbalancer/LBPoolSerializer.java b/src/main/java/net/floodlightcontroller/loadbalancer/LBPoolSerializer.java
new file mode 100644
index 0000000000000000000000000000000000000000..b637eb53b151409c326ea5b76eac78f7a1f959e3
--- /dev/null
+++ b/src/main/java/net/floodlightcontroller/loadbalancer/LBPoolSerializer.java
@@ -0,0 +1,28 @@
+package net.floodlightcontroller.loadbalancer;
+
+import java.io.IOException;
+
+import org.codehaus.jackson.JsonGenerator;
+import org.codehaus.jackson.JsonProcessingException;
+import org.codehaus.jackson.map.JsonSerializer;
+import org.codehaus.jackson.map.SerializerProvider;
+
+public class LBPoolSerializer extends JsonSerializer<LBPool>{
+
+    @Override
+    public void serialize(LBPool pool, JsonGenerator jGen,
+                          SerializerProvider serializer) throws IOException,
+                                                  JsonProcessingException {
+        jGen.writeStartObject();
+        
+        jGen.writeStringField("name", pool.name);
+        jGen.writeStringField("id", pool.id);
+        jGen.writeStringField("vipId", pool.vipId);
+
+        for (int i=0; i<pool.members.size(); i++)
+            jGen.writeStringField("pool", pool.members.get(i));
+
+        jGen.writeEndObject();   
+    }
+
+}
diff --git a/src/main/java/net/floodlightcontroller/loadbalancer/LBStats.java b/src/main/java/net/floodlightcontroller/loadbalancer/LBStats.java
new file mode 100644
index 0000000000000000000000000000000000000000..74e55d47df410f79046e6861dc8fd90f1d870b37
--- /dev/null
+++ b/src/main/java/net/floodlightcontroller/loadbalancer/LBStats.java
@@ -0,0 +1,22 @@
+package net.floodlightcontroller.loadbalancer;
+
+/**
+ * Data structure for Load Balancer based on
+ * Quantum proposal http://wiki.openstack.org/LBaaS/CoreResourceModel/proposal 
+ * 
+ * @author KC Wang
+ */
+
+public class LBStats {
+    protected int bytesIn;
+    protected int bytesOut;
+    protected int activeConnections;
+    protected int totalConnections;
+    
+    public LBStats() {
+        bytesIn = 0;
+        bytesOut = 0;
+        activeConnections = 0;
+        totalConnections = 0;
+    }
+}
diff --git a/src/main/java/net/floodlightcontroller/loadbalancer/LBVip.java b/src/main/java/net/floodlightcontroller/loadbalancer/LBVip.java
new file mode 100644
index 0000000000000000000000000000000000000000..fd8c0bd451ab87c75bdecbcc94016126006bb945
--- /dev/null
+++ b/src/main/java/net/floodlightcontroller/loadbalancer/LBVip.java
@@ -0,0 +1,61 @@
+package net.floodlightcontroller.loadbalancer;
+
+import java.util.ArrayList;
+
+import org.codehaus.jackson.map.annotate.JsonSerialize;
+
+import net.floodlightcontroller.loadbalancer.LoadBalancer.IPClient;
+import net.floodlightcontroller.util.MACAddress;
+
+/**
+ * Data structure for Load Balancer based on
+ * Quantum proposal http://wiki.openstack.org/LBaaS/CoreResourceModel/proposal 
+ * 
+ * @author KC Wang
+ */
+
+@JsonSerialize(using=LBVipSerializer.class)
+public class LBVip {
+    protected String id;    
+    protected String name;
+    protected String tenantId;
+    protected String netId;
+    protected int address;
+    protected byte protocol;
+    protected short lbMethod;
+    protected short port;
+    protected ArrayList<String> pools;
+    protected boolean sessionPersistence;
+    protected int connectionLimit;
+    protected short adminState;
+    protected short status;
+    
+    protected MACAddress proxyMac;
+    
+    public LBVip() {
+        this.id = String.valueOf((int) (Math.random()*10000));
+        this.name = null;
+        this.tenantId = null;
+        this.netId = null;
+        this.address = 0;
+        this.protocol = 0;
+        this.lbMethod = 0;
+        this.port = 0;
+        this.pools = new ArrayList<String>();
+        this.sessionPersistence = false;
+        this.connectionLimit = 0;
+        this.address = 0;
+        this.status = 0;
+        
+        this.proxyMac = MACAddress.valueOf("12:34:56:78:90:12");
+    }
+    
+    public String pickPool(IPClient client) {
+        // for now, return the first pool; consider different pool choice policy later
+        if (pools.size() > 0)
+            return pools.get(0);
+        else
+            return null;
+    }
+
+}
diff --git a/src/main/java/net/floodlightcontroller/loadbalancer/LBVipSerializer.java b/src/main/java/net/floodlightcontroller/loadbalancer/LBVipSerializer.java
new file mode 100644
index 0000000000000000000000000000000000000000..acbecf614ce627efa89cd67b25871cdf8211d912
--- /dev/null
+++ b/src/main/java/net/floodlightcontroller/loadbalancer/LBVipSerializer.java
@@ -0,0 +1,27 @@
+package net.floodlightcontroller.loadbalancer;
+
+import java.io.IOException;
+import org.codehaus.jackson.JsonGenerator;
+import org.codehaus.jackson.JsonProcessingException;
+import org.codehaus.jackson.map.JsonSerializer;
+import org.codehaus.jackson.map.SerializerProvider;
+
+public class LBVipSerializer extends JsonSerializer<LBVip>{
+
+    @Override
+    public void serialize(LBVip vip, JsonGenerator jGen,
+                          SerializerProvider serializer) throws IOException,
+                                                  JsonProcessingException {
+        jGen.writeStartObject();
+        
+        jGen.writeStringField("name", vip.name);
+        jGen.writeStringField("id", vip.id);
+        jGen.writeStringField("address", String.valueOf(vip.address));
+        jGen.writeStringField("protocol", Byte.toString(vip.protocol));
+        jGen.writeStringField("port", Short.toString(vip.port));
+
+        jGen.writeEndObject();
+    }
+
+    
+}
diff --git a/src/main/java/net/floodlightcontroller/loadbalancer/LoadBalancer.java b/src/main/java/net/floodlightcontroller/loadbalancer/LoadBalancer.java
new file mode 100644
index 0000000000000000000000000000000000000000..a9870db97a8502436bceb7ad523312b4bfeff248
--- /dev/null
+++ b/src/main/java/net/floodlightcontroller/loadbalancer/LoadBalancer.java
@@ -0,0 +1,810 @@
+package net.floodlightcontroller.loadbalancer;
+
+import java.io.BufferedReader;
+import java.io.IOException;
+import java.io.InputStreamReader;
+import java.io.UnsupportedEncodingException;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Collection;
+import java.util.Comparator;
+import java.util.EnumSet;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Map;
+
+import org.apache.http.HttpResponse;
+import org.apache.http.client.ClientProtocolException;
+import org.apache.http.client.HttpClient;
+import org.apache.http.client.methods.HttpPost;
+import org.apache.http.entity.StringEntity;
+import org.apache.http.impl.client.DefaultHttpClient;
+import org.apache.http.message.BasicHeader;
+import org.apache.http.protocol.HTTP;
+import org.json.simple.JSONObject;
+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.action.OFAction;
+import org.openflow.protocol.action.OFActionOutput;
+import org.openflow.util.HexString;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import net.floodlightcontroller.core.FloodlightContext;
+import net.floodlightcontroller.core.IFloodlightProviderService;
+import net.floodlightcontroller.core.IOFMessageListener;
+import net.floodlightcontroller.core.IOFSwitch;
+import net.floodlightcontroller.core.module.FloodlightModuleContext;
+import net.floodlightcontroller.core.module.FloodlightModuleException;
+import net.floodlightcontroller.core.module.IFloodlightModule;
+import net.floodlightcontroller.core.module.IFloodlightService;
+import net.floodlightcontroller.counter.ICounterStoreService;
+import net.floodlightcontroller.devicemanager.IDevice;
+import net.floodlightcontroller.devicemanager.IDeviceService;
+import net.floodlightcontroller.devicemanager.SwitchPort;
+import net.floodlightcontroller.packet.ARP;
+import net.floodlightcontroller.packet.Ethernet;
+import net.floodlightcontroller.packet.IPacket;
+import net.floodlightcontroller.packet.IPv4;
+import net.floodlightcontroller.packet.TCP;
+import net.floodlightcontroller.packet.UDP;
+import net.floodlightcontroller.restserver.IRestApiService;
+import net.floodlightcontroller.routing.IRoutingService;
+import net.floodlightcontroller.routing.Route;
+import net.floodlightcontroller.topology.ITopologyService;
+import net.floodlightcontroller.topology.NodePortTuple;
+import net.floodlightcontroller.util.MACAddress;
+import net.floodlightcontroller.util.OFMessageDamper;
+
+/**
+ * A simple load balancer module for ping, tcp, and udp flows. This module is accessed 
+ * via a REST API defined close to the OpenStack Quantum LBaaS (Load-balancer-as-a-Service)
+ * v1.0 API proposal. Since the proposal has not been final, no efforts have yet been 
+ * made to confirm compatibility at this time. 
+ * 
+ * Limitations:
+ * - client records and static flows not purged after use, will exhaust switch flow tables over time
+ * - round robin policy among servers based on connections, not traffic volume
+ * - health monitoring feature not implemented yet
+ *  
+ * @author kcwang
+ */
+public class LoadBalancer implements IFloodlightModule,
+    ILoadBalancerService, IOFMessageListener {
+
+    protected static Logger log = LoggerFactory.getLogger(LoadBalancer.class);
+
+    // Our dependencies
+    protected IFloodlightProviderService floodlightProvider;
+    protected IRestApiService restApi;
+    
+    protected ICounterStoreService counterStore;
+    protected OFMessageDamper messageDamper;
+    protected IDeviceService deviceManager;
+    protected IRoutingService routingEngine;
+    protected ITopologyService topology;
+    
+    protected HashMap<String, LBVip> vips;
+    protected HashMap<String, LBPool> pools;
+    protected HashMap<String, LBMember> members;
+    protected HashMap<Integer, String> vipIpToId;
+    protected HashMap<Integer, MACAddress> vipIpToMac;
+    protected HashMap<Integer, String> memberIpToId;
+    protected HashMap<IPClient, LBMember> clientToMember;
+    
+    //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 
+    // Comparator for sorting by SwitchCluster
+    public Comparator<SwitchPort> clusterIdComparator =
+            new Comparator<SwitchPort>() {
+                @Override
+                public int compare(SwitchPort d1, SwitchPort d2) {
+                    Long d1ClusterId = 
+                            topology.getL2DomainId(d1.getSwitchDPID());
+                    Long d2ClusterId = 
+                            topology.getL2DomainId(d2.getSwitchDPID());
+                    return d1ClusterId.compareTo(d2ClusterId);
+                }
+            };
+
+    // data structure for storing connected
+    public class IPClient {
+        int ipAddress;
+        byte nw_proto;
+        short srcPort; // tcp/udp src port. icmp type (OFMatch convention)
+        short targetPort; // tcp/udp dst port, icmp code (OFMatch convention)
+        
+        public IPClient() {
+            ipAddress = 0;
+            nw_proto = 0;
+            srcPort = -1;
+            targetPort = -1;
+        }
+    }
+    
+    @Override
+    public String getName() {
+        return "loadbalancer";
+    }
+
+    @Override
+    public boolean isCallbackOrderingPrereq(OFType type, String name) {
+        return (type.equals(OFType.PACKET_IN) && 
+                (name.equals("topology") || 
+                 name.equals("devicemanager")));
+    }
+
+    @Override
+    public boolean isCallbackOrderingPostreq(OFType type, String name) {
+        return (type.equals(OFType.PACKET_IN) && name.equals("forwarding"));
+   }
+
+    @Override
+    public net.floodlightcontroller.core.IListener.Command
+            receive(IOFSwitch sw, OFMessage msg, FloodlightContext cntx) {
+        switch (msg.getType()) {
+            case PACKET_IN:
+                return processPacketIn(sw, (OFPacketIn)msg, cntx);
+            default:
+                break;
+        }
+        log.warn("Received unexpected message {}", msg);
+        return Command.CONTINUE;
+    }
+
+    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();
+ 
+        if (eth.isBroadcast() || eth.isMulticast()) {
+            // handle ARP for VIP
+            if (eth.getEtherType() == Ethernet.TYPE_ARP) {
+                // retrieve arp to determine target IP address                                                       
+                ARP arpRequest = (ARP) eth.getPayload();
+
+                int targetProtocolAddress = IPv4.toIPv4Address(arpRequest
+                                                               .getTargetProtocolAddress());
+
+                if (vipIpToId.containsKey(targetProtocolAddress)) {
+                    String vipId = vipIpToId.get(targetProtocolAddress);                    
+                    vipProxyArpReply(sw, pi, cntx, vipId);
+                    return Command.STOP;
+                }
+            }
+        } else {
+            // currently only load balance IPv4 packets - no-op for other traffic 
+            if (pkt instanceof IPv4) {
+                IPv4 ip_pkt = (IPv4) pkt;                
+                
+                // If match Vip and port, check pool and choose member
+                int destIpAddress = ip_pkt.getDestinationAddress();
+                
+                if (vipIpToId.containsKey(destIpAddress)){
+                    IPClient client = new IPClient();
+                    client.ipAddress = ip_pkt.getSourceAddress();
+                    client.nw_proto = ip_pkt.getProtocol();
+                    if (client.nw_proto == IPv4.PROTOCOL_TCP) {
+                        TCP tcp_pkt = (TCP) ip_pkt.getPayload();
+                        client.srcPort = tcp_pkt.getSourcePort();
+                        client.targetPort = tcp_pkt.getDestinationPort();
+                    }
+                    if (client.nw_proto == IPv4.PROTOCOL_UDP) {
+                        UDP udp_pkt = (UDP) ip_pkt.getPayload();
+                        client.srcPort = udp_pkt.getSourcePort();
+                        client.targetPort = udp_pkt.getDestinationPort();
+                    }
+                    if (client.nw_proto == IPv4.PROTOCOL_ICMP) {
+                        client.srcPort = 8; 
+                        client.targetPort = 0; 
+                    }
+                    
+                    LBVip vip = vips.get(vipIpToId.get(destIpAddress));
+                    LBPool pool = pools.get(vip.pickPool(client));
+                    LBMember member = members.get(pool.pickMember(client));
+
+                    // 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.getInPort(), OFPort.OFPP_TABLE.getValue(),
+                                cntx, true);
+                                        
+                    return Command.STOP;
+                }
+            }
+        }
+        // bypass non-load-balanced traffic for normal processing (forwarding)
+        return Command.CONTINUE;
+    }
+
+    /**
+     * used to send proxy Arp for load balanced service requests
+     * @param IOFSwitch sw
+     * @param OFPacketIn pi
+     * @param FloodlightContext cntx
+     * @param String vipId
+     */
+    
+    protected void vipProxyArpReply(IOFSwitch sw, OFPacketIn pi, FloodlightContext cntx, String vipId) {
+        log.debug("vipProxyArpReply");
+            
+        Ethernet eth = IFloodlightProviderService.bcStore.get(cntx,
+                                                              IFloodlightProviderService.CONTEXT_PI_PAYLOAD);
+
+        // retrieve original arp to determine host configured gw IP address                                          
+        ARP arpRequest = (ARP) eth.getPayload();
+        
+        // have to do proxy arp reply since at this point we cannot determine the requesting application type
+        byte[] vipProxyMacBytes = vips.get(vipId).proxyMac.toBytes();
+        
+        // generate proxy ARP reply
+        IPacket arpReply = new Ethernet()
+            .setSourceMACAddress(vipProxyMacBytes)
+            .setDestinationMACAddress(eth.getSourceMACAddress())
+            .setEtherType(Ethernet.TYPE_ARP)
+            .setVlanID(eth.getVlanID())
+            .setPriorityCode(eth.getPriorityCode())
+            .setPayload(
+                new ARP()
+                .setHardwareType(ARP.HW_TYPE_ETHERNET)
+                .setProtocolType(ARP.PROTO_TYPE_IP)
+                .setHardwareAddressLength((byte) 6)
+                .setProtocolAddressLength((byte) 4)
+                .setOpCode(ARP.OP_REPLY)
+                .setSenderHardwareAddress(vipProxyMacBytes)
+                .setSenderProtocolAddress(
+                        arpRequest.getTargetProtocolAddress())
+                .setTargetHardwareAddress(
+                        eth.getSourceMACAddress())
+                .setTargetProtocolAddress(
+                        arpRequest.getSenderProtocolAddress()));
+                
+        // push ARP reply out
+        pushPacket(arpReply, sw, OFPacketOut.BUFFER_ID_NONE, OFPort.OFPP_NONE.getValue(),
+                   pi.getInPort(), cntx, true);
+        log.debug("proxy ARP reply pushed as {}", IPv4.fromIPv4Address(vips.get(vipId).address));
+        
+        return;
+    }
+
+    /**
+     * used to push any packet - borrowed routine from Forwarding
+     * 
+     * @param OFPacketIn pi
+     * @param IOFSwitch sw
+     * @param int bufferId
+     * @param short inPort
+     * @param short outPort
+     * @param FloodlightContext cntx
+     * @param boolean flush
+     */    
+    public void pushPacket(IPacket packet, 
+                           IOFSwitch sw,
+                           int bufferId,
+                           short inPort,
+                           short outPort, 
+                           FloodlightContext cntx,
+                           boolean flush) {
+        if (log.isTraceEnabled()) {
+            log.trace("PacketOut srcSwitch={} inPort={} outPort={}", 
+                      new Object[] {sw, inPort, outPort});
+        }
+
+        OFPacketOut po =
+                (OFPacketOut) floodlightProvider.getOFMessageFactory()
+                                                .getMessage(OFType.PACKET_OUT);
+
+        // set actions
+        List<OFAction> actions = new ArrayList<OFAction>();
+        actions.add(new OFActionOutput(outPort, (short) 0xffff));
+
+        po.setActions(actions)
+          .setActionsLength((short) OFActionOutput.MINIMUM_LENGTH);
+        short poLength =
+                (short) (po.getActionsLength() + OFPacketOut.MINIMUM_LENGTH);
+
+        // set buffer_id, in_port
+        po.setBufferId(bufferId);
+        po.setInPort(inPort);
+
+        // set data - only if buffer_id == -1
+        if (po.getBufferId() == OFPacketOut.BUFFER_ID_NONE) {
+            if (packet == null) {
+                log.error("BufferId is not set and packet data is null. " +
+                          "Cannot send packetOut. " +
+                        "srcSwitch={} inPort={} outPort={}",
+                        new Object[] {sw, inPort, outPort});
+                return;
+            }
+            byte[] packetData = packet.serialize();
+            poLength += packetData.length;
+            po.setPacketData(packetData);
+        }
+
+        po.setLength(poLength);
+
+        try {
+            counterStore.updatePktOutFMCounterStoreLocal(sw, po);
+            messageDamper.write(sw, po, cntx, flush);
+        } catch (IOException e) {
+            log.error("Failure writing packet out", e);
+        }
+    }
+
+    /**
+     * used to find and push in-bound and out-bound routes using StaticFlowEntryPusher
+     * @param IOFSwitch sw
+     * @param OFPacketIn pi
+     * @param FloodlightContext cntx
+     * @param IPClient client
+     * @param LBMember member
+     */
+    protected void pushBidirectionalVipRoutes(IOFSwitch sw, OFPacketIn pi, FloodlightContext cntx, IPClient client, LBMember member) {
+        
+        // borrowed code from Forwarding to retrieve src and dst device entities
+        // Check if we have the location of the destination
+        IDevice srcDevice = null;
+        IDevice dstDevice = null;
+        
+        // retrieve all known devices                                                          
+        Collection<? extends IDevice> allDevices = deviceManager
+                .getAllDevices();
+        
+        for (IDevice d : allDevices) {
+            for (int j = 0; j < d.getIPv4Addresses().length; j++) {
+                    if (srcDevice == null && client.ipAddress == d.getIPv4Addresses()[j])
+                        srcDevice = d;
+                    if (dstDevice == null && member.address == d.getIPv4Addresses()[j]) {
+                        dstDevice = d;
+                        member.macString = dstDevice.getMACAddressString();
+                    }
+                    if (srcDevice != null && dstDevice != null)
+                        break;
+            }
+        }   
+        
+        Long srcIsland = topology.getL2DomainId(sw.getId());
+
+        if (srcIsland == null) {
+            log.debug("No openflow island found for source {}/{}", 
+                      sw.getStringId(), pi.getInPort());
+            return;
+        }
+        
+        // Validate that we have a destination known on the same island
+        // Validate that the source and destination are not on the same switchport
+        boolean on_same_island = false;
+        boolean on_same_if = false;
+        for (SwitchPort dstDap : dstDevice.getAttachmentPoints()) {
+            long dstSwDpid = dstDap.getSwitchDPID();
+            Long dstIsland = topology.getL2DomainId(dstSwDpid);
+            if ((dstIsland != null) && dstIsland.equals(srcIsland)) {
+                on_same_island = true;
+                if ((sw.getId() == dstSwDpid) &&
+                        (pi.getInPort() == dstDap.getPort())) {
+                    on_same_if = true;
+                }
+                break;
+            }
+        }
+        
+        if (!on_same_island) {
+            // Flood since we don't know the dst device
+            if (log.isTraceEnabled()) {
+                log.trace("No first hop island found for destination " + 
+                        "device {}, Action = flooding", dstDevice);
+            }
+            return;
+        }            
+        
+        if (on_same_if) {
+            if (log.isTraceEnabled()) {
+                log.trace("Both source and destination are on the same " + 
+                        "switch/port {}/{}, Action = NOP", 
+                        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 
+        // traverse the attachment points in O(m+n) time
+        SwitchPort[] srcDaps = srcDevice.getAttachmentPoints();
+        Arrays.sort(srcDaps, clusterIdComparator);
+        SwitchPort[] dstDaps = dstDevice.getAttachmentPoints();
+        Arrays.sort(dstDaps, clusterIdComparator);
+        
+        int iSrcDaps = 0, iDstDaps = 0;
+
+        // following Forwarding's same routing routine, retrieve both in-bound and out-bound routes for
+        // all clusters.
+        while ((iSrcDaps < srcDaps.length) && (iDstDaps < dstDaps.length)) {
+            SwitchPort srcDap = srcDaps[iSrcDaps];
+            SwitchPort dstDap = dstDaps[iDstDaps];
+            Long srcCluster = 
+                    topology.getL2DomainId(srcDap.getSwitchDPID());
+            Long dstCluster = 
+                    topology.getL2DomainId(dstDap.getSwitchDPID());
+
+            int srcVsDest = srcCluster.compareTo(dstCluster);
+            if (srcVsDest == 0) {
+                if (!srcDap.equals(dstDap) && 
+                        (srcCluster != null) && 
+                        (dstCluster != null)) {
+                    Route routeIn = 
+                            routingEngine.getRoute(srcDap.getSwitchDPID(),
+                                                   (short)srcDap.getPort(),
+                                                   dstDap.getSwitchDPID(),
+                                                   (short)dstDap.getPort());
+                    Route routeOut = 
+                            routingEngine.getRoute(dstDap.getSwitchDPID(),
+                                                   (short)dstDap.getPort(),
+                                                   srcDap.getSwitchDPID(),
+                                                   (short)srcDap.getPort());
+
+                    // use static flow entry pusher to push flow mod along in and out path
+                    // in: match src client (ip, port), rewrite dest from vip ip/port to member ip/port, forward
+                    // out: match dest client (ip, port), rewrite src from member ip/port to vip ip/port, forward
+                    
+                    if (routeIn != null) {                            
+                        pushStaticVipRoute(true, routeIn, client, member, sw.getId());
+                    }
+                        
+                    if (routeOut != null) {                            
+                        pushStaticVipRoute(false, routeOut, client, member, sw.getId());
+                    }
+
+                }
+                iSrcDaps++;
+                iDstDaps++;
+            } else if (srcVsDest < 0) {
+                iSrcDaps++;
+            } else {
+                iDstDaps++;
+            }
+        }
+        return;
+    }
+    
+    /**
+     * used to push given route using static flow entry pusher
+     * @param boolean inBound
+     * @param Route route
+     * @param IPClient client
+     * @param LBMember member
+     * @param long pinSwitch
+     */
+    @SuppressWarnings("unchecked")
+    public void pushStaticVipRoute(boolean inBound, Route route, IPClient client, LBMember member, long pinSwitch) {
+        List<NodePortTuple> path = route.getPath();
+        if (path.size()>0) {
+            
+           for (int i = 0; i < path.size(); i+=2) {
+               JSONObject json = new JSONObject();
+               long sw = path.get(i).getNodeId();
+
+               json.put("switch", HexString.toHexString(sw));
+               if (inBound) {
+                   json.put("name","inbound-vip-"+ member.vipId+"client-"+client.ipAddress+"-port-"+client.targetPort
+                            +"srcswitch-"+path.get(0).getNodeId()+"sw-"+sw);
+                   json.put("src-ip",IPv4.fromIPv4Address(client.ipAddress));
+                   json.put("protocol",String.valueOf(client.nw_proto));
+                   json.put("src-port",String.valueOf(client.srcPort & 0xffff));
+                   json.put("ether-type","0x800");
+                   json.put("priority","32768");
+                   json.put("ingress-port",String.valueOf(path.get(i).getPortId()));
+                   json.put("active","true");
+                   if (sw == pinSwitch) {
+                       json.put("actions","set-dst-ip="+IPv4.fromIPv4Address(member.address)+"," 
+                                + "set-dst-mac="+member.macString+","
+                                + "output="+path.get(i+1).getPortId());
+                   } else {
+                       json.put("actions",
+                               "output="+path.get(i+1).getPortId());
+                   }
+               } else {
+                   json.put("name","outbound-vip-"+ member.vipId+"client-"+client.ipAddress+"-port-"+client.targetPort
+                            +"srcswitch-"+path.get(0).getNodeId()+"sw-"+sw);
+                   json.put("dst-ip",IPv4.fromIPv4Address(client.ipAddress));
+                   json.put("protocol",String.valueOf(client.nw_proto));
+                   json.put("dst-port",String.valueOf(client.srcPort & 0xffff));
+                   json.put("ether-type","0x800");
+                   json.put("priority","32768");
+                   json.put("ingress-port",String.valueOf(path.get(i).getPortId()));
+                   json.put("active","true");
+                   if (sw == pinSwitch) {
+                       json.put("actions","set-src-ip="+IPv4.fromIPv4Address(vips.get(member.vipId).address)+","
+                               + "set-src-mac="+vips.get(member.vipId).proxyMac.toString()+","
+                               + "output="+path.get(i+1).getPortId());
+                   } else {
+                       json.put("actions",
+                               "output="+path.get(i+1).getPortId());
+                   }
+                   
+               }
+               try {
+                   HttpClient httpclient = new DefaultHttpClient();
+                   HttpPost httpPost = new HttpPost("http://127.0.0.1:8080/wm/staticflowentrypusher/json");
+                   StringEntity se = new StringEntity(json.toString());  
+                   se.setContentEncoding(new BasicHeader(HTTP.CONTENT_TYPE, "application/json"));
+                   httpPost.setEntity(se);
+                   
+                   HttpResponse response = null;
+
+                   try {
+                       response = httpclient.execute(httpPost);
+                   } catch (ClientProtocolException cliente) {
+                       cliente.printStackTrace();
+                   } catch (IOException ioe) {
+                       ioe.printStackTrace();
+                   }
+                   
+                   BufferedReader rd = null;
+                   try {
+                       if (response !=null)
+                           rd = new BufferedReader(new InputStreamReader(response.getEntity().getContent()));
+                   } catch (IllegalStateException statee) {
+                       statee.printStackTrace();
+                   } catch (IOException ioe) {
+                       ioe.printStackTrace();
+                   }
+                   
+                   String line = "";
+                   try {
+                       if (rd!= null) {
+                           while ((line = rd.readLine()) != null) {
+                               System.out.println(line);
+                           }
+                       }
+                   } catch (IOException e) {
+                       e.printStackTrace();
+                   }
+               } catch (UnsupportedEncodingException e) {
+                   e.printStackTrace();
+               }            
+           }
+        }
+        
+        return;
+    }
+
+    
+    @Override
+    public Collection<LBVip> listVips() {
+        return vips.values();
+    }
+
+    @Override
+    public Collection<LBVip> listVip(String vipId) {
+        Collection<LBVip> result = new HashSet<LBVip>();
+        result.add(vips.get(vipId));
+        return result;    }
+
+    @Override
+    public LBVip createVip(LBVip vip) {
+        if (vip == null)
+            vip = new LBVip();
+        
+        vips.put(vip.id, vip);
+        vipIpToId.put(vip.address, vip.id);
+        vipIpToMac.put(vip.address, vip.proxyMac);
+        
+        return vip;
+    }
+
+    @Override
+    public LBVip updateVip(LBVip vip) {
+        vips.put(vip.id, vip);
+        return vip;
+    }
+
+    @Override
+    public int removeVip(String vipId) {
+        if(vips.containsKey(vipId)){
+            vips.remove(vipId);
+            return 0;
+        } else {
+            return -1;
+        }
+    }
+
+    @Override
+    public Collection<LBPool> listPools() {
+        return pools.values();
+    }
+
+    @Override
+    public Collection<LBPool> listPool(String poolId) {
+        Collection<LBPool> result = new HashSet<LBPool>();
+        result.add(pools.get(poolId));
+        return result;
+    }
+
+    @Override
+    public LBPool createPool(LBPool pool) {
+        if (pool==null)
+            pool = new LBPool();
+        
+        pools.put(pool.id, pool);
+        if (pool.vipId != null)
+            vips.get(pool.vipId).pools.add(pool.id);
+        else
+            log.error("pool must be specified with non-null vip-id");
+
+        return pool;
+    }
+
+    @Override
+    public LBPool updatePool(LBPool pool) {
+        pools.put(pool.id, pool);
+        return null;
+    }
+
+    @Override
+    public int removePool(String poolId) {
+        if(pools.containsKey(poolId)){
+            pools.remove(poolId);
+            return 0;
+        } else {
+            return -1;
+        }    
+    }
+
+    @Override
+    public Collection<LBMember> listMembers() {
+        return members.values();
+    }
+
+    @Override
+    public Collection<LBMember> listMember(String memberId) {
+        Collection<LBMember> result = new HashSet<LBMember>();
+        result.add(members.get(memberId));
+        return result;    
+        }
+
+    @Override
+    public Collection<LBMember> listMembersByPool(String poolId) {
+        Collection<LBMember> result = new HashSet<LBMember>();
+        
+        if(pools.containsKey(poolId)) {
+            ArrayList<String> memberIds = pools.get(poolId).members;
+            for (int i=0; i<memberIds.size(); i++)
+                result.add(members.get(memberIds.get(i)));
+        }
+        return result;    
+    }
+    
+    @Override
+    public LBMember createMember(LBMember member) {
+        if (member == null)
+            member = new LBMember();
+        
+        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);
+        } else
+            log.error("member must be specified with non-null pool_id");
+        
+        return member;
+    }
+
+    @Override
+    public LBMember updateMember(LBMember member) {
+        members.put(member.id, member);
+        return member;
+    }
+
+    @Override
+    public int removeMember(String memberId) {
+        if(members.containsKey(memberId)){
+            members.remove(memberId);
+            return 0;
+        } else {
+            return -1;
+        }    
+    }
+
+    @Override
+    public Collection<LBMonitor> listMonitors() {
+        // TODO Auto-generated method stub
+        return null;
+    }
+
+    @Override
+    public Collection<LBMonitor> listMonitor(String monitorId) {
+        // TODO Auto-generated method stub
+        return null;
+    }
+
+    @Override
+    public LBMonitor createMonitor(LBMonitor monitor) {
+        // TODO Auto-generated method stub
+        return null;
+    }
+
+    @Override
+    public LBMonitor updateMonitor(LBMonitor monitor) {
+        // TODO Auto-generated method stub
+        return null;
+    }
+
+    @Override
+    public int removeMonitor(String monitorId) {
+        // TODO Auto-generated method stub
+        return 0;
+    }
+
+    @Override
+    public Collection<Class<? extends IFloodlightService>>
+            getModuleServices() {
+        Collection<Class<? extends IFloodlightService>> l = 
+                new ArrayList<Class<? extends IFloodlightService>>();
+        l.add(ILoadBalancerService.class);
+        return l;
+   }
+
+    @Override
+    public Map<Class<? extends IFloodlightService>, IFloodlightService>
+            getServiceImpls() {
+        Map<Class<? extends IFloodlightService>, IFloodlightService> m = 
+                new HashMap<Class<? extends IFloodlightService>,
+                    IFloodlightService>();
+        m.put(ILoadBalancerService.class, this);
+        return m;
+    }
+
+    @Override
+    public Collection<Class<? extends IFloodlightService>>
+            getModuleDependencies() {
+        Collection<Class<? extends IFloodlightService>> l = 
+                new ArrayList<Class<? extends IFloodlightService>>();
+        l.add(IFloodlightProviderService.class);
+        l.add(IRestApiService.class);
+        l.add(ICounterStoreService.class);
+        l.add(IDeviceService.class);
+        l.add(ITopologyService.class);
+        l.add(IRoutingService.class);
+
+        return l;
+    }
+
+    @Override
+    public void init(FloodlightModuleContext context)
+                                                 throws FloodlightModuleException {
+        floodlightProvider = context.getServiceImpl(IFloodlightProviderService.class);
+        restApi = context.getServiceImpl(IRestApiService.class);
+        counterStore = context.getServiceImpl(ICounterStoreService.class);
+        deviceManager = context.getServiceImpl(IDeviceService.class);
+        routingEngine = context.getServiceImpl(IRoutingService.class);
+        topology = context.getServiceImpl(ITopologyService.class);
+        
+        messageDamper = new OFMessageDamper(OFMESSAGE_DAMPER_CAPACITY, 
+                                            EnumSet.of(OFType.FLOW_MOD),
+                                            OFMESSAGE_DAMPER_TIMEOUT);
+        
+        vips = new HashMap<String, LBVip>();
+        pools = new HashMap<String, LBPool>();
+        members = new HashMap<String, LBMember>();
+        vipIpToId = new HashMap<Integer, String>();
+        vipIpToMac = new HashMap<Integer, MACAddress>();
+        memberIpToId = new HashMap<Integer, String>();
+    }
+
+    @Override
+    public void startUp(FloodlightModuleContext context) {
+        floodlightProvider.addOFMessageListener(OFType.PACKET_IN, this);
+        restApi.addRestletRoutable(new LoadBalancerWebRoutable());
+    }
+
+}
diff --git a/src/main/java/net/floodlightcontroller/loadbalancer/LoadBalancerWebRoutable.java b/src/main/java/net/floodlightcontroller/loadbalancer/LoadBalancerWebRoutable.java
new file mode 100644
index 0000000000000000000000000000000000000000..170346aa13529cd9032a834605a9cd1db130d410
--- /dev/null
+++ b/src/main/java/net/floodlightcontroller/loadbalancer/LoadBalancerWebRoutable.java
@@ -0,0 +1,33 @@
+package net.floodlightcontroller.loadbalancer;
+
+import org.restlet.Context;
+import org.restlet.Restlet;
+import org.restlet.routing.Router;
+
+import net.floodlightcontroller.restserver.RestletRoutable;
+import net.floodlightcontroller.virtualnetwork.NoOp;
+
+public class LoadBalancerWebRoutable implements RestletRoutable {
+
+    @Override
+    public Restlet getRestlet(Context context) {
+        Router router = new Router(context);
+        router.attach("/vips/", VipsResource.class); // GET, POST
+        router.attach("/vips/{vip}", VipsResource.class); // GET, PUT, DELETE 
+        router.attach("/pools/", PoolsResource.class); // GET, POST
+        router.attach("/pools/{pool}", PoolsResource.class); // GET, PUT, DELETE
+        router.attach("/members/", MembersResource.class); // GET, POST
+        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.attachDefault(NoOp.class);
+        return router;
+     }
+
+    @Override
+    public String basePath() {
+        return "/quantum/v1.0";
+    }
+
+}
diff --git a/src/main/java/net/floodlightcontroller/loadbalancer/MembersResource.java b/src/main/java/net/floodlightcontroller/loadbalancer/MembersResource.java
new file mode 100644
index 0000000000000000000000000000000000000000..0cd9a3d5668f8bb0a75ea34a54d08e1d5e3eec38
--- /dev/null
+++ b/src/main/java/net/floodlightcontroller/loadbalancer/MembersResource.java
@@ -0,0 +1,133 @@
+package net.floodlightcontroller.loadbalancer;
+
+import java.io.IOException;
+import java.util.Collection;
+
+import net.floodlightcontroller.packet.IPv4;
+
+import org.codehaus.jackson.JsonParseException;
+import org.codehaus.jackson.JsonParser;
+import org.codehaus.jackson.JsonToken;
+import org.codehaus.jackson.map.MappingJsonFactory;
+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;
+
+public class MembersResource extends ServerResource {
+
+    protected static Logger log = LoggerFactory.getLogger(MembersResource.class);
+    
+    @Get("json")
+    public Collection <LBMember> retrieve() {
+        ILoadBalancerService lbs =
+                (ILoadBalancerService)getContext().getAttributes().
+                    get(ILoadBalancerService.class.getCanonicalName());
+        
+        String memberId = (String) getRequestAttributes().get("member");
+        if (memberId!=null)
+            return lbs.listMember(memberId);
+        else        
+            return lbs.listMembers();               
+    }
+    
+    @Put
+    @Post
+    public LBMember createMember(String postData) {        
+
+        LBMember member=null;
+        try {
+            member=jsonToMember(postData);
+        } catch (IOException e) {
+            log.error("Could not parse JSON {}", e.getMessage());
+        }
+        
+        ILoadBalancerService lbs =
+                (ILoadBalancerService)getContext().getAttributes().
+                    get(ILoadBalancerService.class.getCanonicalName());
+        
+        String memberId = (String) getRequestAttributes().get("member");
+        if (memberId != null)
+            return lbs.updateMember(member);
+        else        
+            return lbs.createMember(member);
+    }
+    
+    @Delete
+    public int removeMember() {
+        
+        String memberId = (String) getRequestAttributes().get("member");
+               
+        ILoadBalancerService lbs =
+                (ILoadBalancerService)getContext().getAttributes().
+                    get(ILoadBalancerService.class.getCanonicalName());
+
+        return lbs.removeMember(memberId);
+    }
+
+    protected LBMember jsonToMember(String json) throws IOException {
+        MappingJsonFactory f = new MappingJsonFactory();
+        JsonParser jp;
+        LBMember member = new LBMember();
+        
+        try {
+            jp = f.createJsonParser(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")) {
+                member.id = jp.getText();
+                continue;
+            } else
+            if (n.equals("address")) {
+                member.address = IPv4.toIPv4Address(jp.getText());
+                continue;
+            } else
+            if (n.equals("port")) {
+                member.port = Short.parseShort(jp.getText());
+                continue;
+            } else
+            if (n.equals("connection_limit")) {
+                member.connectionLimit = Integer.parseInt(jp.getText());
+                continue;
+            } else
+            if (n.equals("admin_state")) {
+                member.adminState = Short.parseShort(jp.getText());
+                continue;
+            } else
+            if (n.equals("status")) {
+                member.status = Short.parseShort(jp.getText());
+                continue;
+            } else
+            if (n.equals("pool_id")) {
+                member.poolId = jp.getText();
+                continue;
+            } 
+            
+            log.warn("Unrecognized field {} in " +
+                    "parsing Members", 
+                    jp.getText());
+        }
+        jp.close();
+
+        return member;
+    }
+}
diff --git a/src/main/java/net/floodlightcontroller/loadbalancer/MonitorsResource.java b/src/main/java/net/floodlightcontroller/loadbalancer/MonitorsResource.java
new file mode 100644
index 0000000000000000000000000000000000000000..a726325454dda0de57b98e1ed4f1d9c409eb81b6
--- /dev/null
+++ b/src/main/java/net/floodlightcontroller/loadbalancer/MonitorsResource.java
@@ -0,0 +1,156 @@
+package net.floodlightcontroller.loadbalancer;
+
+import java.io.IOException;
+import java.util.Collection;
+
+import org.codehaus.jackson.JsonParseException;
+import org.codehaus.jackson.JsonParser;
+import org.codehaus.jackson.JsonToken;
+import org.codehaus.jackson.map.MappingJsonFactory;
+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;
+
+public class MonitorsResource extends ServerResource {
+    protected static Logger log = LoggerFactory.getLogger(MonitorsResource.class);
+    
+    @Get("json")
+    public Collection <LBMonitor> retrieve() {
+        ILoadBalancerService lbs =
+                (ILoadBalancerService)getContext().getAttributes().
+                    get(ILoadBalancerService.class.getCanonicalName());
+        
+        String monitorId = (String) getRequestAttributes().get("monitor");
+        if (monitorId!=null)
+            return lbs.listMonitor(monitorId);
+        else        
+            return lbs.listMonitors();               
+    }
+    
+    @Put
+    @Post
+    public LBMonitor createMonitor(String postData) {        
+
+        LBMonitor monitor=null;
+        try {
+            monitor=jsonToMonitor(postData);
+        } catch (IOException e) {
+            log.error("Could not parse JSON {}", e.getMessage());
+        }
+        
+        ILoadBalancerService lbs =
+                (ILoadBalancerService)getContext().getAttributes().
+                    get(ILoadBalancerService.class.getCanonicalName());
+        
+        String monitorId = (String) getRequestAttributes().get("monitor");
+        if (monitorId != null)
+            return lbs.updateMonitor(monitor);
+        else        
+            return lbs.createMonitor(monitor);
+    }
+    
+    @Delete
+    public int removeMonitor() {
+        
+        String monitorId = (String) getRequestAttributes().get("monitor");
+               
+        ILoadBalancerService lbs =
+                (ILoadBalancerService)getContext().getAttributes().
+                    get(ILoadBalancerService.class.getCanonicalName());
+
+        return lbs.removeMonitor(monitorId);
+    }
+
+    protected LBMonitor jsonToMonitor(String json) throws IOException {
+        MappingJsonFactory f = new MappingJsonFactory();
+        JsonParser jp;
+        LBMonitor monitor = new LBMonitor();
+        
+        try {
+            jp = f.createJsonParser(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;
+            else if (n.equals("monitor")) {
+                while (jp.nextToken() != JsonToken.END_OBJECT) {
+                    String field = jp.getCurrentName();
+                    
+                    if (field.equals("id")) {
+                        monitor.id = jp.getText();
+                        continue;
+                    } 
+                    if (field.equals("name")) {
+                        monitor.name = jp.getText();
+                        continue;
+                    }
+                    if (field.equals("type")) {
+                        monitor.type = Short.parseShort(jp.getText());
+                        continue;
+                    }
+                    if (field.equals("delay")) {
+                        monitor.delay = Short.parseShort(jp.getText());
+                        continue;
+                    }
+                    if (field.equals("timeout")) {
+                        monitor.timeout = Short.parseShort(jp.getText());
+                        continue;
+                    }
+                    if (field.equals("attempts_before_deactivation")) {
+                        monitor.attemptsBeforeDeactivation = Short.parseShort(jp.getText());
+                        continue;
+                    }
+                    if (field.equals("network_id")) {
+                        monitor.netId = jp.getText();
+                        continue;
+                    }
+                    if (field.equals("address")) {
+                        monitor.address = Integer.parseInt(jp.getText());
+                        continue;
+                    }
+                    if (field.equals("protocol")) {
+                        monitor.protocol = Byte.parseByte(jp.getText());
+                        continue;
+                    }
+                    if (field.equals("port")) {
+                        monitor.port = Short.parseShort(jp.getText());
+                        continue;
+                    }
+                    if (field.equals("admin_state")) {
+                        monitor.adminState = Short.parseShort(jp.getText());
+                        continue;
+                    }
+                    if (field.equals("status")) {
+                        monitor.status = Short.parseShort(jp.getText());
+                        continue;
+                    }
+                    
+                    log.warn("Unrecognized field {} in " +
+                            "parsing Vips", 
+                            jp.getText());
+                }
+            }
+        }
+        jp.close();
+
+        return monitor;
+    }
+}
diff --git a/src/main/java/net/floodlightcontroller/loadbalancer/PoolMemberResource.java b/src/main/java/net/floodlightcontroller/loadbalancer/PoolMemberResource.java
new file mode 100644
index 0000000000000000000000000000000000000000..21f0444122e574c3fa0a6e289c292ee66861a854
--- /dev/null
+++ b/src/main/java/net/floodlightcontroller/loadbalancer/PoolMemberResource.java
@@ -0,0 +1,25 @@
+package net.floodlightcontroller.loadbalancer;
+
+import java.util.Collection;
+
+import org.restlet.resource.Get;
+import org.restlet.resource.ServerResource;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+public class PoolMemberResource extends ServerResource {
+    protected static Logger log = LoggerFactory.getLogger(PoolMemberResource.class);
+    
+    @Get("json")
+    public Collection <LBMember> retrieve() {
+        ILoadBalancerService lbs =
+                (ILoadBalancerService)getContext().getAttributes().
+                    get(ILoadBalancerService.class.getCanonicalName());
+        
+        String poolId = (String) getRequestAttributes().get("pool");
+        if (poolId!=null)
+            return lbs.listMembersByPool(poolId);
+        else
+            return null;
+    }
+}
diff --git a/src/main/java/net/floodlightcontroller/loadbalancer/PoolsResource.java b/src/main/java/net/floodlightcontroller/loadbalancer/PoolsResource.java
new file mode 100644
index 0000000000000000000000000000000000000000..9efb50c451bb7e976fdf18b114af7d90bb0bc88b
--- /dev/null
+++ b/src/main/java/net/floodlightcontroller/loadbalancer/PoolsResource.java
@@ -0,0 +1,143 @@
+package net.floodlightcontroller.loadbalancer;
+
+import java.io.IOException;
+import java.util.Collection;
+
+import net.floodlightcontroller.packet.IPv4;
+
+import org.codehaus.jackson.JsonParseException;
+import org.codehaus.jackson.JsonParser;
+import org.codehaus.jackson.JsonToken;
+import org.codehaus.jackson.map.MappingJsonFactory;
+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;
+
+public class PoolsResource extends ServerResource {
+
+    protected static Logger log = LoggerFactory.getLogger(PoolsResource.class);
+    
+    @Get("json")
+    public Collection <LBPool> retrieve() {
+        ILoadBalancerService lbs =
+                (ILoadBalancerService)getContext().getAttributes().
+                    get(ILoadBalancerService.class.getCanonicalName());
+        
+        String poolId = (String) getRequestAttributes().get("pool");
+        if (poolId!=null)
+            return lbs.listPool(poolId);
+        else        
+            return lbs.listPools();               
+    }
+    
+    @Put
+    @Post
+    public LBPool createPool(String postData) {        
+
+        LBPool pool=null;
+        try {
+            pool=jsonToPool(postData);
+        } catch (IOException e) {
+            log.error("Could not parse JSON {}", e.getMessage());
+        }
+        
+        ILoadBalancerService lbs =
+                (ILoadBalancerService)getContext().getAttributes().
+                    get(ILoadBalancerService.class.getCanonicalName());
+        
+        String poolId = (String) getRequestAttributes().get("pool");
+        if (poolId != null)
+            return lbs.updatePool(pool);
+        else        
+            return lbs.createPool(pool);
+    }
+    
+    @Delete
+    public int removePool() {
+        
+        String poolId = (String) getRequestAttributes().get("pool");
+               
+        ILoadBalancerService lbs =
+                (ILoadBalancerService)getContext().getAttributes().
+                    get(ILoadBalancerService.class.getCanonicalName());
+
+        return lbs.removePool(poolId);
+    }
+
+    protected LBPool jsonToPool(String json) throws IOException {
+        if (json==null) return null;
+
+        MappingJsonFactory f = new MappingJsonFactory();
+        JsonParser jp;
+        LBPool pool = new LBPool();
+        
+        try {
+            jp = f.createJsonParser(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")) {
+                pool.id = jp.getText();
+                continue;
+            } 
+            if (n.equals("tenant_id")) {
+                pool.tenantId = jp.getText();
+                continue;
+            } 
+            if (n.equals("name")) {
+                pool.name = jp.getText();
+                continue;
+            }
+            if (n.equals("network_id")) {
+                pool.netId = jp.getText();
+                continue;
+            }
+            if (n.equals("lb_method")) {
+                pool.lbMethod = Short.parseShort(jp.getText());
+                continue;
+            }
+            if (n.equals("protocol")) {
+                String tmp = jp.getText();
+                if (tmp.equalsIgnoreCase("TCP")) {
+                    pool.protocol = IPv4.PROTOCOL_TCP;
+                } else if (tmp.equalsIgnoreCase("UDP")) {
+                    pool.protocol = IPv4.PROTOCOL_UDP;
+                } else if (tmp.equalsIgnoreCase("ICMP")) {
+                    pool.protocol = IPv4.PROTOCOL_ICMP;
+                } 
+                continue;
+            }                    
+            if (n.equals("vip_id")) {
+                pool.vipId = jp.getText();
+                continue;
+            } 
+            
+            log.warn("Unrecognized field {} in " +
+                    "parsing Pools", 
+                    jp.getText());
+        }
+        jp.close();
+
+        return pool;
+    }
+    
+}
diff --git a/src/main/java/net/floodlightcontroller/loadbalancer/VipsResource.java b/src/main/java/net/floodlightcontroller/loadbalancer/VipsResource.java
new file mode 100644
index 0000000000000000000000000000000000000000..20bf882cdbc2d2f1c72954875a674902d97da1fd
--- /dev/null
+++ b/src/main/java/net/floodlightcontroller/loadbalancer/VipsResource.java
@@ -0,0 +1,148 @@
+package net.floodlightcontroller.loadbalancer;
+
+import java.io.IOException;
+import java.util.Collection;
+
+import net.floodlightcontroller.packet.IPv4;
+
+import org.codehaus.jackson.JsonParseException;
+import org.codehaus.jackson.JsonParser;
+import org.codehaus.jackson.JsonToken;
+import org.codehaus.jackson.map.MappingJsonFactory;
+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;
+
+public class VipsResource extends ServerResource {
+    protected static Logger log = LoggerFactory.getLogger(VipsResource.class);
+    
+    @Get("json")
+    public Collection <LBVip> retrieve() {
+        ILoadBalancerService lbs =
+                (ILoadBalancerService)getContext().getAttributes().
+                    get(ILoadBalancerService.class.getCanonicalName());
+        
+        String vipId = (String) getRequestAttributes().get("vip");
+        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.createJsonParser(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 = IPv4.PROTOCOL_TCP;
+                } else if (tmp.equalsIgnoreCase("UDP")) {
+                    vip.protocol = IPv4.PROTOCOL_UDP;
+                } else if (tmp.equalsIgnoreCase("ICMP")) {
+                    vip.protocol = IPv4.PROTOCOL_ICMP;
+                } 
+                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/org/openflow/protocol/OFPacketQueue.java b/src/main/java/org/openflow/protocol/OFPacketQueue.java
new file mode 100644
index 0000000000000000000000000000000000000000..e8de1af56b950465c23cc140ad4991e0922aa34f
--- /dev/null
+++ b/src/main/java/org/openflow/protocol/OFPacketQueue.java
@@ -0,0 +1,142 @@
+/**
+*    Copyright 2012, Andrew Ferguson, Brown University
+*
+*    Licensed under the Apache License, Version 2.0 (the "License"); you may
+*    not use this file except in compliance with the License. You may obtain
+*    a copy of the License at
+*
+*         http://www.apache.org/licenses/LICENSE-2.0
+*
+*    Unless required by applicable law or agreed to in writing, software
+*    distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+*    WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+*    License for the specific language governing permissions and limitations
+*    under the License.
+**/
+
+package org.openflow.protocol;
+
+import java.util.ArrayList;
+import java.util.List;
+
+import org.jboss.netty.buffer.ChannelBuffer;
+import org.openflow.util.U16;
+
+/**
+ * Represents ofp_packet_queue
+ * @author Andrew Ferguson (adf@cs.brown.edu)
+ */
+public class OFPacketQueue {
+    public static int MINIMUM_LENGTH = 8;
+
+    protected int queueId;
+    protected short length;
+    protected List<OFQueueProp> properties = new ArrayList<OFQueueProp>();
+
+    public OFPacketQueue() {
+        this.queueId = -1;
+        this.length = U16.t(MINIMUM_LENGTH);
+    }
+
+    public OFPacketQueue(int queueId) {
+        this.queueId = queueId;
+        this.length = U16.t(MINIMUM_LENGTH);
+    }
+
+    /**
+     * @return the queueId
+     */
+    public long getQueueId() {
+        return queueId;
+    }
+
+    /**
+     * @param queueId the queueId to set
+     */
+    public void setQueueId(int queueId) {
+        this.queueId = queueId;
+    }
+
+    /**
+     * @return the queue's properties
+     */
+    public List<OFQueueProp> getProperties() {
+        return properties;
+    }
+
+    /**
+     * @param properties the properties to set
+     */
+    public void setProperties(List<OFQueueProp> properties) {
+        this.properties = properties;
+
+        this.length = U16.t(MINIMUM_LENGTH);
+        for (OFQueueProp prop : properties) {
+            this.length += prop.getLength();
+        }
+    }
+
+    /**
+     * @return the length
+     */
+    public short getLength() {
+        return length;
+    }
+
+    public void readFrom(ChannelBuffer data) {
+        this.queueId = data.readInt();
+        this.length = data.readShort();
+        data.readShort(); // pad
+
+        int availLength = (this.length - MINIMUM_LENGTH);
+        this.properties.clear();
+
+        while (availLength > 0) {
+            OFQueueProp prop = new OFQueueProp();
+            prop.readFrom(data);
+            properties.add(prop);
+            availLength -= prop.getLength();
+        }
+    }
+
+    public void writeTo(ChannelBuffer data) {
+        data.writeInt(queueId);
+        data.writeShort(length);
+        data.writeShort(0); // pad
+
+        for (OFQueueProp prop : properties) {
+            prop.writeTo(data);
+        }
+    }
+
+    @Override
+    public int hashCode() {
+        final int prime = 359;
+        int result = super.hashCode();
+        result = prime * result + queueId;
+        result = prime * result + length;
+        result = prime * result + properties.hashCode();
+        return result;
+    }
+
+    @Override
+    public boolean equals(Object obj) {
+        if (this == obj) {
+            return true;
+        }
+        if (!super.equals(obj)) {
+            return false;
+        }
+        if (!(obj instanceof OFPacketQueue)) {
+            return false;
+        }
+        OFPacketQueue other = (OFPacketQueue) obj;
+        if (queueId != other.queueId) {
+            return false;
+        }
+        if (! properties.equals(other.properties)) {
+            return false;
+        }
+        return true;
+    }
+}
diff --git a/src/main/java/org/openflow/protocol/OFQueueGetConfigReply.java b/src/main/java/org/openflow/protocol/OFQueueGetConfigReply.java
new file mode 100644
index 0000000000000000000000000000000000000000..62be90d59f4106e8a6581dcf81bc5153cee83ce1
--- /dev/null
+++ b/src/main/java/org/openflow/protocol/OFQueueGetConfigReply.java
@@ -0,0 +1,125 @@
+/**
+*    Copyright 2012, Andrew Ferguson, Brown University
+*
+*    Licensed under the Apache License, Version 2.0 (the "License"); you may
+*    not use this file except in compliance with the License. You may obtain
+*    a copy of the License at
+*
+*         http://www.apache.org/licenses/LICENSE-2.0
+*
+*    Unless required by applicable law or agreed to in writing, software
+*    distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+*    WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+*    License for the specific language governing permissions and limitations
+*    under the License.
+**/
+
+package org.openflow.protocol;
+
+import java.util.ArrayList;
+import java.util.List;
+
+import org.jboss.netty.buffer.ChannelBuffer;
+import org.openflow.util.U16;
+
+/**
+ * Represents an ofp_queue_get_config_request message
+ * @author Andrew Ferguson (adf@cs.brown.edu)
+ */
+public class OFQueueGetConfigReply extends OFMessage {
+    public static int MINIMUM_LENGTH = 16;
+
+    protected short portNumber;
+    protected List<OFPacketQueue> queues = new ArrayList<OFPacketQueue>();
+
+    public OFQueueGetConfigReply() {
+        super();
+        this.type = OFType.QUEUE_GET_CONFIG_REPLY;
+        this.length = U16.t(MINIMUM_LENGTH);
+    }
+
+    /**
+     * @return the portNumber
+     */
+    public short getPortNumber() {
+        return portNumber;
+    }
+
+    /**
+     * @param portNumber the portNumber to set
+     */
+    public void setPortNumber(short portNumber) {
+        this.portNumber = portNumber;
+    }
+
+    /**
+     * @return the port's queues
+     */
+    public List<OFPacketQueue> getQueues() {
+        return queues;
+    }
+
+    /**
+     * @param queues the queues to set
+     */
+    public void setQueues(List<OFPacketQueue> queues) {
+        this.queues.clear();
+        this.queues.addAll(queues);
+    }
+
+    @Override
+    public void readFrom(ChannelBuffer data) {
+        super.readFrom(data);
+        this.portNumber = data.readShort();
+        data.readInt();   // pad
+        data.readShort(); // pad
+
+        int availLength = (this.length - MINIMUM_LENGTH);
+        this.queues.clear();
+
+        while (availLength > 0) {
+            OFPacketQueue queue = new OFPacketQueue();
+            queue.readFrom(data);
+            queues.add(queue);
+            availLength -= queue.getLength();
+        }
+    }
+
+    @Override
+    public void writeTo(ChannelBuffer data) {
+        super.writeTo(data);
+        data.writeShort(this.portNumber);
+        data.writeInt(0);   // pad
+        data.writeShort(0); // pad
+
+        for (OFPacketQueue queue : queues) {
+            queue.writeTo(data);
+        }
+    }
+
+    @Override
+    public int hashCode() {
+        final int prime = 349;
+        int result = super.hashCode();
+        result = prime * result + portNumber;
+        return result;
+    }
+
+    @Override
+    public boolean equals(Object obj) {
+        if (this == obj) {
+            return true;
+        }
+        if (!super.equals(obj)) {
+            return false;
+        }
+        if (!(obj instanceof OFQueueGetConfigReply)) {
+            return false;
+        }
+        OFQueueGetConfigReply other = (OFQueueGetConfigReply) obj;
+        if (portNumber != other.portNumber) {
+            return false;
+        }
+        return true;
+    }
+}
diff --git a/src/main/java/org/openflow/protocol/OFQueueGetConfigRequest.java b/src/main/java/org/openflow/protocol/OFQueueGetConfigRequest.java
new file mode 100644
index 0000000000000000000000000000000000000000..cbb4a3734b9bc6510362afa237b6121398d9e4cd
--- /dev/null
+++ b/src/main/java/org/openflow/protocol/OFQueueGetConfigRequest.java
@@ -0,0 +1,95 @@
+/**
+*    Copyright 2012, Andrew Ferguson, Brown University
+*
+*    Licensed under the Apache License, Version 2.0 (the "License"); you may
+*    not use this file except in compliance with the License. You may obtain
+*    a copy of the License at
+*
+*         http://www.apache.org/licenses/LICENSE-2.0
+*
+*    Unless required by applicable law or agreed to in writing, software
+*    distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+*    WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+*    License for the specific language governing permissions and limitations
+*    under the License.
+**/
+
+package org.openflow.protocol;
+
+import org.jboss.netty.buffer.ChannelBuffer;
+import org.openflow.util.U16;
+
+/**
+ * Represents an ofp_queue_get_config_request message
+ * @author Andrew Ferguson (adf@cs.brown.edu)
+ */
+public class OFQueueGetConfigRequest extends OFMessage {
+    public static int MINIMUM_LENGTH = 12;
+
+    protected short portNumber;
+
+    public OFQueueGetConfigRequest(short portNumber) {
+        super();
+        this.type = OFType.QUEUE_GET_CONFIG_REQUEST;
+        this.length = U16.t(MINIMUM_LENGTH);
+        this.portNumber = portNumber;
+    }
+
+    public OFQueueGetConfigRequest() {
+        this((short) 0);
+    }
+
+    /**
+     * @return the portNumber
+     */
+    public short getPortNumber() {
+        return portNumber;
+    }
+
+    /**
+     * @param portNumber the portNumber to set
+     */
+    public void setPortNumber(short portNumber) {
+        this.portNumber = portNumber;
+    }
+
+    @Override
+    public void readFrom(ChannelBuffer data) {
+        super.readFrom(data);
+        this.portNumber = data.readShort();
+        data.readShort(); // pad
+    }
+
+    @Override
+    public void writeTo(ChannelBuffer data) {
+        super.writeTo(data);
+        data.writeShort(this.portNumber);
+        data.writeShort(0); // pad
+    }
+
+    @Override
+    public int hashCode() {
+        final int prime = 347;
+        int result = super.hashCode();
+        result = prime * result + portNumber;
+        return result;
+    }
+
+    @Override
+    public boolean equals(Object obj) {
+        if (this == obj) {
+            return true;
+        }
+        if (!super.equals(obj)) {
+            return false;
+        }
+        if (!(obj instanceof OFQueueGetConfigRequest)) {
+            return false;
+        }
+        OFQueueGetConfigRequest other = (OFQueueGetConfigRequest) obj;
+        if (portNumber != other.portNumber) {
+            return false;
+        }
+        return true;
+    }
+}
diff --git a/src/main/java/org/openflow/protocol/OFQueueProp.java b/src/main/java/org/openflow/protocol/OFQueueProp.java
new file mode 100644
index 0000000000000000000000000000000000000000..55c4d33e40f7b4cd4ed191f980fbf584d2e9000f
--- /dev/null
+++ b/src/main/java/org/openflow/protocol/OFQueueProp.java
@@ -0,0 +1,166 @@
+/**
+*    Copyright 2012, Andrew Ferguson, Brown University
+*
+*    Licensed under the Apache License, Version 2.0 (the "License"); you may
+*    not use this file except in compliance with the License. You may obtain
+*    a copy of the License at
+*
+*         http://www.apache.org/licenses/LICENSE-2.0
+*
+*    Unless required by applicable law or agreed to in writing, software
+*    distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+*    WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+*    License for the specific language governing permissions and limitations
+*    under the License.
+**/
+
+package org.openflow.protocol;
+
+import org.jboss.netty.buffer.ChannelBuffer;
+import org.openflow.util.U16;
+
+public class OFQueueProp {
+    private int NONE_MINIMUM_LENGTH = 8;
+    private int MIN_RATE_MINIMUM_LENGTH = 16;
+
+    public enum OFQueuePropType {
+        OFPQT_NONE       (0),
+        OFPQT_MIN_RATE   (1);
+
+        protected int value;
+
+        private OFQueuePropType(int value) {
+            this.value = value;
+        }
+
+        /**
+         * @return the value
+         */
+        public int getValue() {
+            return value;
+        }
+
+        public static OFQueuePropType fromShort(short x) {
+            switch (x) {
+                case 0:
+                    return OFPQT_NONE;
+                case 1:
+                    return OFPQT_MIN_RATE;
+            }
+            return null;
+        }
+    }
+
+    protected OFQueuePropType type;
+    protected short length;
+    protected short rate = -1; // not valid unless type == OFPQT_MIN_RATE
+
+    public OFQueueProp() {
+        this.type = OFQueuePropType.OFPQT_NONE;
+        this.length = U16.t(NONE_MINIMUM_LENGTH);
+    }
+
+    /**
+     * @return the type
+     */
+    public OFQueuePropType getType() {
+        return type;
+    }
+
+    /**
+     * @param type the type to set
+     */
+    public void setType(OFQueuePropType type) {
+        this.type = type;
+
+        switch (type) {
+            case OFPQT_NONE:
+                this.length = U16.t(NONE_MINIMUM_LENGTH);
+                break;
+            case OFPQT_MIN_RATE:
+                this.length = U16.t(MIN_RATE_MINIMUM_LENGTH);
+                break;
+        }
+    }
+
+    /**
+     * @return the rate
+     */
+    public short getRate() {
+        return rate;
+    }
+
+    /**
+     * @param rate the rate to set
+     */
+    public void setRate(short rate) {
+        this.rate = rate;
+    }
+
+    /**
+     * @return the length
+     */
+    public short getLength() {
+        return length;
+    }
+
+    public void readFrom(ChannelBuffer data) {
+        this.type = OFQueuePropType.fromShort(data.readShort());
+        this.length = data.readShort();
+        data.readInt(); // pad
+
+        if (this.type == OFQueuePropType.OFPQT_MIN_RATE) {
+            assert(this.length == MIN_RATE_MINIMUM_LENGTH);
+
+            this.rate = data.readShort();
+            data.readInt(); // pad
+            data.readShort(); // pad
+        } else {
+            assert(this.length == NONE_MINIMUM_LENGTH);
+        }
+    }
+
+    public void writeTo(ChannelBuffer data) {
+        data.writeShort(this.type.getValue());
+        data.writeShort(this.length);
+        data.writeInt(0); // pad
+
+        if (this.type == OFQueuePropType.OFPQT_MIN_RATE) {
+            data.writeShort(this.rate);
+            data.writeInt(0); // pad
+            data.writeShort(0); // pad
+        }
+    }
+
+    @Override
+    public int hashCode() {
+        final int prime = 353;
+        int result = super.hashCode();
+        result = prime * result + type.getValue();
+        result = prime * result + rate;
+        return result;
+    }
+
+    @Override
+    public boolean equals(Object obj) {
+        if (this == obj) {
+            return true;
+        }
+        if (!super.equals(obj)) {
+            return false;
+        }
+        if (!(obj instanceof OFQueueProp)) {
+            return false;
+        }
+        OFQueueProp other = (OFQueueProp) obj;
+        if (type != other.type) {
+            return false;
+        }
+        if (type == OFQueuePropType.OFPQT_MIN_RATE) {
+            if (rate != other.rate) {
+                return false;
+            }
+        }
+        return true;
+    }
+}
diff --git a/src/main/java/org/openflow/protocol/OFType.java b/src/main/java/org/openflow/protocol/OFType.java
index c828f0a928ec4ae798a2445972ee9d0681ad0ca1..f1c81e2884b0f850efe420aa54c1fe810869442e 100644
--- a/src/main/java/org/openflow/protocol/OFType.java
+++ b/src/main/java/org/openflow/protocol/OFType.java
@@ -127,7 +127,17 @@ public enum OFType {
                             @Override
                             public OFMessage instantiate() {
                                 return new OFBarrierReply();
-                            }});
+                            }}),
+    QUEUE_GET_CONFIG_REQUEST    (20, OFQueueGetConfigRequest.class, new Instantiable<OFMessage>() {
+                                    @Override
+                                    public OFMessage instantiate() {
+                                        return new OFQueueGetConfigRequest();
+                                    }}),
+    QUEUE_GET_CONFIG_REPLY      (21, OFQueueGetConfigReply.class, new Instantiable<OFMessage>() {
+                                    @Override
+                                    public OFMessage instantiate() {
+                                        return new OFQueueGetConfigReply();
+                                    }});
 
     static OFType[] mapping;
 
diff --git a/src/main/java/org/openflow/vendor/openflow/OFOpenFlowVendorData.java b/src/main/java/org/openflow/vendor/openflow/OFOpenFlowVendorData.java
new file mode 100644
index 0000000000000000000000000000000000000000..9be821f2ace4fb624a0a2314e0b997ec9d086f14
--- /dev/null
+++ b/src/main/java/org/openflow/vendor/openflow/OFOpenFlowVendorData.java
@@ -0,0 +1,98 @@
+/**
+*    Copyright 2012, Andrew Ferguson, Brown University
+*
+*    Licensed under the Apache License, Version 2.0 (the "License"); you may
+*    not use this file except in compliance with the License. You may obtain
+*    a copy of the License at
+*
+*         http://www.apache.org/licenses/LICENSE-2.0
+*
+*    Unless required by applicable law or agreed to in writing, software
+*    distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+*    WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+*    License for the specific language governing permissions and limitations
+*    under the License.
+**/
+
+package org.openflow.vendor.openflow;
+
+import org.jboss.netty.buffer.ChannelBuffer;
+import org.openflow.protocol.vendor.OFVendorData;
+
+/**
+ * Base class for vendor data corresponding to extensions to OpenFlow 1.0.
+ * Based on org.openflow.vendor.nicira
+ *
+ * @author Andrew Ferguson (adf@cs.brown.edu)
+ */
+public class OFOpenFlowVendorData implements OFVendorData {
+
+    public static final int OF_VENDOR_ID = 0x000026e1;
+
+    /**
+     * The value of the integer data type at the beginning of the vendor data
+     */
+    protected int dataType;
+
+    /**
+     * Construct empty (i.e. unspecified data type) OpenFlow vendor data.
+     */
+    public OFOpenFlowVendorData() {
+    }
+
+    /**
+     * Construct OpenFlow vendor data with the specified data type
+     * @param dataType the data type value at the beginning of the vendor data.
+     */
+    public OFOpenFlowVendorData(int dataType) {
+        this.dataType = dataType;
+    }
+
+    /**
+     * Get the data type value at the beginning of the vendor data
+     * @return the integer data type value
+     */
+    public int getDataType() {
+        return dataType;
+    }
+
+    /**
+     * Set the data type value
+     * @param dataType the integer data type value at the beginning of the
+     *     vendor data.
+     */
+    public void setDataType(int dataType) {
+        this.dataType = dataType;
+    }
+
+    /**
+     * Get the length of the vendor data. This implementation will normally
+     * be the superclass for another class that will override this to return
+     * the overall vendor data length. This implementation just returns the
+     * length of the part that includes the 4-byte integer data type value
+     * at the beginning of the vendor data.
+     */
+    @Override
+    public int getLength() {
+        return 4;
+    }
+
+    /**
+     * Read the vendor data from the ChannelBuffer
+     * @param data the channel buffer from which we're deserializing
+     * @param length the length to the end of the enclosing message
+     */
+    @Override
+    public void readFrom(ChannelBuffer data, int length) {
+        dataType = data.readInt();
+    }
+
+    /**
+     * Write the vendor data to the ChannelBuffer
+     * @param data the channel buffer to which we're serializing
+     */
+    @Override
+    public void writeTo(ChannelBuffer data) {
+        data.writeInt(dataType);
+    }
+}
diff --git a/src/main/java/org/openflow/vendor/openflow/OFOpenFlowVendorExtensions.java b/src/main/java/org/openflow/vendor/openflow/OFOpenFlowVendorExtensions.java
new file mode 100644
index 0000000000000000000000000000000000000000..3fa10298cbc0ad4307368983cd157e51116e20ef
--- /dev/null
+++ b/src/main/java/org/openflow/vendor/openflow/OFOpenFlowVendorExtensions.java
@@ -0,0 +1,47 @@
+/**
+*    Copyright 2012, Andrew Ferguson, Brown University
+*
+*    Licensed under the Apache License, Version 2.0 (the "License"); you may
+*    not use this file except in compliance with the License. You may obtain
+*    a copy of the License at
+*
+*         http://www.apache.org/licenses/LICENSE-2.0
+*
+*    Unless required by applicable law or agreed to in writing, software
+*    distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+*    WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+*    License for the specific language governing permissions and limitations
+*    under the License.
+**/
+
+package org.openflow.vendor.openflow;
+
+import org.openflow.protocol.vendor.OFBasicVendorDataType;
+import org.openflow.protocol.vendor.OFBasicVendorId;
+import org.openflow.protocol.vendor.OFVendorId;
+
+public class OFOpenFlowVendorExtensions {
+    private static boolean initialized = false;
+
+    public static synchronized void initialize() {
+        if (initialized)
+            return;
+
+        // Configure openflowj to be able to parse the OpenFlow extensions.
+        OFBasicVendorId openflowVendorId =
+                new OFBasicVendorId(OFOpenFlowVendorData.OF_VENDOR_ID, 4);
+        OFVendorId.registerVendorId(openflowVendorId);
+
+        OFBasicVendorDataType queueModifyVendorData =
+                new OFBasicVendorDataType(OFQueueModifyVendorData.OFP_EXT_QUEUE_MODIFY,
+                        OFQueueModifyVendorData.getInstantiable());
+        openflowVendorId.registerVendorDataType(queueModifyVendorData);
+
+        OFBasicVendorDataType queueDeleteVendorData =
+                new OFBasicVendorDataType(OFQueueDeleteVendorData.OFP_EXT_QUEUE_DELETE,
+                        OFQueueModifyVendorData.getInstantiable());
+        openflowVendorId.registerVendorDataType(queueDeleteVendorData);
+
+        initialized = true;
+    }
+}
diff --git a/src/main/java/org/openflow/vendor/openflow/OFQueueDeleteVendorData.java b/src/main/java/org/openflow/vendor/openflow/OFQueueDeleteVendorData.java
new file mode 100644
index 0000000000000000000000000000000000000000..4fc52bacb337733d19647ab89f3ee04f553ef018
--- /dev/null
+++ b/src/main/java/org/openflow/vendor/openflow/OFQueueDeleteVendorData.java
@@ -0,0 +1,52 @@
+/**
+*    Copyright 2012, Andrew Ferguson, Brown University
+*
+*    Licensed under the Apache License, Version 2.0 (the "License"); you may
+*    not use this file except in compliance with the License. You may obtain
+*    a copy of the License at
+*
+*         http://www.apache.org/licenses/LICENSE-2.0
+*
+*    Unless required by applicable law or agreed to in writing, software
+*    distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+*    WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+*    License for the specific language governing permissions and limitations
+*    under the License.
+**/
+
+package org.openflow.vendor.openflow;
+
+import org.openflow.protocol.Instantiable;
+import org.openflow.protocol.vendor.OFVendorData;
+
+/**
+ * Class that represents the vendor data in the queue delete request
+ *
+ * @author Andrew Ferguson (adf@cs.brown.edu)
+ */
+public class OFQueueDeleteVendorData extends OFQueueVendorData {
+
+    protected static Instantiable<OFVendorData> instantiable =
+            new Instantiable<OFVendorData>() {
+                public OFVendorData instantiate() {
+                    return new OFQueueDeleteVendorData();
+                }
+            };
+
+    /**
+     * @return a subclass of Instantiable<OFVendorData> that instantiates
+     *         an instance of OFQueueDeleteVendorData.
+     */
+    public static Instantiable<OFVendorData> getInstantiable() {
+        return instantiable;
+    }
+
+    /**
+     * The data type value for a queue delete request
+     */
+    public static final int OFP_EXT_QUEUE_DELETE = 1;
+
+    public OFQueueDeleteVendorData() {
+        super(OFP_EXT_QUEUE_DELETE);
+    }
+}
diff --git a/src/main/java/org/openflow/vendor/openflow/OFQueueModifyVendorData.java b/src/main/java/org/openflow/vendor/openflow/OFQueueModifyVendorData.java
new file mode 100644
index 0000000000000000000000000000000000000000..0d2f31b524c22f2e1152735eb5db26d8ae210914
--- /dev/null
+++ b/src/main/java/org/openflow/vendor/openflow/OFQueueModifyVendorData.java
@@ -0,0 +1,52 @@
+/**
+*    Copyright 2012, Andrew Ferguson, Brown University
+*
+*    Licensed under the Apache License, Version 2.0 (the "License"); you may
+*    not use this file except in compliance with the License. You may obtain
+*    a copy of the License at
+*
+*         http://www.apache.org/licenses/LICENSE-2.0
+*
+*    Unless required by applicable law or agreed to in writing, software
+*    distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+*    WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+*    License for the specific language governing permissions and limitations
+*    under the License.
+**/
+
+package org.openflow.vendor.openflow;
+
+import org.openflow.protocol.Instantiable;
+import org.openflow.protocol.vendor.OFVendorData;
+
+/**
+ * Class that represents the vendor data in the queue modify request
+ *
+ * @author Andrew Ferguson (adf@cs.brown.edu)
+ */
+public class OFQueueModifyVendorData extends OFQueueVendorData {
+
+    protected static Instantiable<OFVendorData> instantiable =
+            new Instantiable<OFVendorData>() {
+                public OFVendorData instantiate() {
+                    return new OFQueueModifyVendorData();
+                }
+            };
+
+    /**
+     * @return a subclass of Instantiable<OFVendorData> that instantiates
+     *         an instance of OFQueueModifyVendorData.
+     */
+    public static Instantiable<OFVendorData> getInstantiable() {
+        return instantiable;
+    }
+
+    /**
+     * The data type value for a queue modify request
+     */
+    public static final int OFP_EXT_QUEUE_MODIFY = 0;
+
+    public OFQueueModifyVendorData() {
+        super(OFP_EXT_QUEUE_MODIFY);
+    }
+}
diff --git a/src/main/java/org/openflow/vendor/openflow/OFQueueVendorData.java b/src/main/java/org/openflow/vendor/openflow/OFQueueVendorData.java
new file mode 100644
index 0000000000000000000000000000000000000000..eeae9aace6436f42de2c26151aba1f125e26d83b
--- /dev/null
+++ b/src/main/java/org/openflow/vendor/openflow/OFQueueVendorData.java
@@ -0,0 +1,119 @@
+/**
+*    Copyright 2012, Andrew Ferguson, Brown University
+*
+*    Licensed under the Apache License, Version 2.0 (the "License"); you may
+*    not use this file except in compliance with the License. You may obtain
+*    a copy of the License at
+*
+*         http://www.apache.org/licenses/LICENSE-2.0
+*
+*    Unless required by applicable law or agreed to in writing, software
+*    distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+*    WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+*    License for the specific language governing permissions and limitations
+*    under the License.
+**/
+
+package org.openflow.vendor.openflow;
+
+import java.util.ArrayList;
+import java.util.List;
+
+import org.jboss.netty.buffer.ChannelBuffer;
+import org.openflow.protocol.OFPacketQueue;
+
+/**
+ * Class that represents the vendor data in a queue modify or delete request
+ *
+ * @author Andrew Ferguson (adf@cs.brown.edu)
+ */
+public class OFQueueVendorData extends OFOpenFlowVendorData {
+    public static int MINIMUM_LENGTH = 8;
+
+    protected short portNumber;
+    protected List<OFPacketQueue> queues = new ArrayList<OFPacketQueue>();
+
+    public OFQueueVendorData(int dataType) {
+        super(dataType);
+    }
+
+    /**
+     * @return the portNumber
+     */
+    public short getPortNumber() {
+        return portNumber;
+    }
+
+    /**
+     * @param port the port on which the queue is
+     */
+    public void setPortNumber(short portNumber) {
+        this.portNumber = portNumber;
+    }
+
+
+    /**
+     * @return the queues
+     */
+    public List<OFPacketQueue> getQueues() {
+        return queues;
+    }
+
+    /**
+     * @param queues the queues to modify or delete
+     */
+    public void setQueues(List<OFPacketQueue> queues) {
+        this.queues = queues;
+    }
+
+    /**
+     * @return the total length of the queue modify or delete msg
+     */
+    @Override
+    public int getLength() {
+        int queuesLength = 0;
+
+        for (OFPacketQueue queue : queues) {
+            queuesLength += queue.getLength();
+        }
+
+        return super.getLength() + MINIMUM_LENGTH + queuesLength;
+    }
+
+    /**
+     * Read the queue message data from the ChannelBuffer
+     * @param data the channel buffer from which we're deserializing
+     * @param length the length to the end of the enclosing message
+     */
+    public void readFrom(ChannelBuffer data, int length) {
+        super.readFrom(data, length);
+        portNumber = data.readShort();
+        data.readInt();   // pad
+        data.readShort(); // pad
+
+        int availLength = (length - MINIMUM_LENGTH);
+        this.queues.clear();
+
+        while (availLength > 0) {
+            OFPacketQueue queue = new OFPacketQueue();
+            queue.readFrom(data);
+            queues.add(queue);
+            availLength -= queue.getLength();
+        }
+    }
+
+    /**
+     * Write the queue message data to the ChannelBuffer
+     * @param data the channel buffer to which we're serializing
+     */
+    public void writeTo(ChannelBuffer data) {
+        super.writeTo(data);
+        data.writeShort(this.portNumber);
+        data.writeInt(0);   // pad
+        data.writeShort(0); // pad
+
+        for (OFPacketQueue queue : queues) {
+            queue.writeTo(data);
+        }
+    }
+}
diff --git a/src/main/resources/META-INF/services/net.floodlightcontroller.core.module.IFloodlightModule b/src/main/resources/META-INF/services/net.floodlightcontroller.core.module.IFloodlightModule
index 07985a1268a9a66755c1745fc9696c9272c290ec..935fe105c9f6a40b0415d21ef18816bc084042bf 100644
--- a/src/main/resources/META-INF/services/net.floodlightcontroller.core.module.IFloodlightModule
+++ b/src/main/resources/META-INF/services/net.floodlightcontroller.core.module.IFloodlightModule
@@ -23,4 +23,5 @@ net.floodlightcontroller.devicemanager.internal.DefaultEntityClassifier
 net.floodlightcontroller.devicemanager.test.MockDeviceManager
 net.floodlightcontroller.core.test.MockFloodlightProvider
 net.floodlightcontroller.core.test.MockThreadPoolService
-net.floodlightcontroller.firewall.Firewall
\ No newline at end of file
+net.floodlightcontroller.firewall.Firewall
+net.floodlightcontroller.loadbalancer.LoadBalancer
\ No newline at end of file
diff --git a/src/main/resources/floodlightdefault.properties b/src/main/resources/floodlightdefault.properties
index 5bb2e28832f44fd7c4db3984002c102f71bc7933..30dfdcaaa06d8e73d98a80a0fc9cb43b827ef347 100644
--- a/src/main/resources/floodlightdefault.properties
+++ b/src/main/resources/floodlightdefault.properties
@@ -13,7 +13,8 @@ net.floodlightcontroller.flowcache.FlowReconcileManager, \
 net.floodlightcontroller.jython.JythonDebugInterface,\
 net.floodlightcontroller.counter.CounterStore,\
 net.floodlightcontroller.perfmon.PktInProcessingTime,\
-net.floodlightcontroller.ui.web.StaticWebRoutable
+net.floodlightcontroller.ui.web.StaticWebRoutable,\
+net.floodlightcontroller.loadbalancer.LoadBalancer
 net.floodlightcontroller.restserver.RestApiServer.port = 8080
 net.floodlightcontroller.core.FloodlightProvider.openflowport = 6633
 net.floodlightcontroller.jython.JythonDebugInterface.port = 6655
diff --git a/src/main/thrift/packetstreamer.thrift b/src/main/thrift/packetstreamer.thrift
index 827dd8525d1a9a22f0a218911e05d4669cafe2e4..ca683014219af978cafbba7bd1a579be89415298 100644
--- a/src/main/thrift/packetstreamer.thrift
+++ b/src/main/thrift/packetstreamer.thrift
@@ -38,6 +38,8 @@ enum OFMessageType {
   STATS_REPLY = 17,
   BARRIER_REQUEST = 18,
   BARRIER_REPLY = 19,
+  QUEUE_GET_CONFIG_REQUEST = 20,
+  QUEUE_GET_CONFIG_REPLY = 21,
 }
 
 /**