Merge branch 'master' into arpononos
diff --git a/conf/onos.properties b/conf/onos.properties
index e858adb..ee75680 100644
--- a/conf/onos.properties
+++ b/conf/onos.properties
@@ -10,7 +10,8 @@
 net.onrc.onos.datagrid.HazelcastDatagrid,\
 net.onrc.onos.ofcontroller.flowmanager.FlowManager,\
 net.onrc.onos.ofcontroller.topology.TopologyManager,\
-net.onrc.onos.registry.controller.ZookeeperRegistry
+net.onrc.onos.registry.controller.ZookeeperRegistry, \
+net.onrc.onos.ofcontroller.core.module.OnosModuleLoader
 net.floodlightcontroller.restserver.RestApiServer.port = 8080
 net.floodlightcontroller.core.FloodlightProvider.openflowport = 6633
 net.floodlightcontroller.core.FloodlightProvider.workerthreads = 16
diff --git a/src/main/java/net/onrc/onos/graph/GraphDBConnection.java b/src/main/java/net/onrc/onos/graph/GraphDBConnection.java
index 232deed..bf30297 100644
--- a/src/main/java/net/onrc/onos/graph/GraphDBConnection.java
+++ b/src/main/java/net/onrc/onos/graph/GraphDBConnection.java
@@ -7,7 +7,6 @@
 
 import com.thinkaurelius.titan.core.TitanFactory;
 import com.thinkaurelius.titan.core.TitanGraph;
-import com.thinkaurelius.titan.diskstorage.StorageException;
 import com.tinkerpop.blueprints.TransactionalGraph;
 import com.tinkerpop.blueprints.Vertex;
 import com.tinkerpop.blueprints.util.wrappers.event.EventTransactionalGraph;
@@ -82,6 +81,9 @@
 			if (!s.contains("switch_state")) {
 				graph.createKeyIndex("switch_state", Vertex.class);
 			}
+			if (!s.contains("ipv4_address")) {
+				graph.createKeyIndex("ipv4_address", Vertex.class);
+			}
 			graph.commit();
 			eg = new EventTransactionalGraph<TitanGraph>(graph);
 		}
diff --git a/src/main/java/net/onrc/onos/graph/GraphDBOperation.java b/src/main/java/net/onrc/onos/graph/GraphDBOperation.java
index f1e9b46..489eb5e 100644
--- a/src/main/java/net/onrc/onos/graph/GraphDBOperation.java
+++ b/src/main/java/net/onrc/onos/graph/GraphDBOperation.java
@@ -1,11 +1,14 @@
 package net.onrc.onos.graph;
 
 import java.util.ArrayList;
+import java.util.Iterator;
 import java.util.List;
 
+import net.onrc.onos.ofcontroller.core.INetMapTopologyObjects.IBaseObject;
 import net.onrc.onos.ofcontroller.core.INetMapTopologyObjects.IDeviceObject;
 import net.onrc.onos.ofcontroller.core.INetMapTopologyObjects.IFlowEntry;
 import net.onrc.onos.ofcontroller.core.INetMapTopologyObjects.IFlowPath;
+import net.onrc.onos.ofcontroller.core.INetMapTopologyObjects.IIpv4Address;
 import net.onrc.onos.ofcontroller.core.INetMapTopologyObjects.IPortObject;
 import net.onrc.onos.ofcontroller.core.INetMapTopologyObjects.ISwitchObject;
 import net.onrc.onos.ofcontroller.core.ISwitchStorage.SwitchState;
@@ -225,6 +228,44 @@
 		FramedGraph<TitanGraph> fg = conn.getFramedGraph();	
 		if (fg != null) fg.removeVertex(dev.asVertex());		
 	}
+	
+	public IIpv4Address newIpv4Address() {
+		return newVertex("ipv4Address", IIpv4Address.class);
+	}
+	
+	private <T extends IBaseObject> T newVertex(String type, Class<T> vertexType) {
+		FramedGraph<TitanGraph> fg = conn.getFramedGraph();
+		T newVertex = fg.addVertex(null, vertexType);
+		if (newVertex != null) {
+			newVertex.setType(type);
+		}
+		return newVertex;
+	}
+	
+	public IIpv4Address searchIpv4Address(int intIpv4Address) {
+		return searchForVertex("ipv4_address", intIpv4Address, IIpv4Address.class);
+	}
+	
+	private <T> T searchForVertex(String propertyName, Object propertyValue, Class<T> vertexType) {
+		FramedGraph<TitanGraph> fg = conn.getFramedGraph();
+		if (fg != null) {
+			Iterator<T> it = 
+					fg.getVertices(propertyName, propertyValue, vertexType).iterator();
+			if (it.hasNext()) {
+				return it.next();
+			}
+		}
+		return null;
+	}
+	
+	public IIpv4Address ensureIpv4Address(int intIpv4Address) {
+		IIpv4Address ipv4Vertex = searchIpv4Address(intIpv4Address);
+		if (ipv4Vertex == null) {
+			ipv4Vertex = newIpv4Address();
+			ipv4Vertex.setIpv4Address(intIpv4Address);
+		}
+		return ipv4Vertex;
+	}
 
 	/**
 	 * Create and return a flow path object.
diff --git a/src/main/java/net/onrc/onos/ofcontroller/bgproute/BgpRoute.java b/src/main/java/net/onrc/onos/ofcontroller/bgproute/BgpRoute.java
index d84d30d..a3c8f1f 100644
--- a/src/main/java/net/onrc/onos/ofcontroller/bgproute/BgpRoute.java
+++ b/src/main/java/net/onrc/onos/ofcontroller/bgproute/BgpRoute.java
@@ -34,13 +34,13 @@
 import net.floodlightcontroller.util.MACAddress;
 import net.onrc.onos.ofcontroller.bgproute.RibUpdate.Operation;
 import net.onrc.onos.ofcontroller.core.INetMapTopologyService.ITopoLinkService;
+import net.onrc.onos.ofcontroller.core.config.IConfigInfoService;
 import net.onrc.onos.ofcontroller.core.internal.TopoLinkServiceImpl;
 import net.onrc.onos.ofcontroller.linkdiscovery.ILinkDiscovery;
 import net.onrc.onos.ofcontroller.linkdiscovery.ILinkDiscovery.LDUpdate;
 import net.onrc.onos.ofcontroller.linkdiscovery.ILinkDiscoveryService;
 import net.onrc.onos.ofcontroller.proxyarp.IArpRequester;
 import net.onrc.onos.ofcontroller.proxyarp.IProxyArpService;
-import net.onrc.onos.ofcontroller.proxyarp.ProxyArpManager;
 import net.onrc.onos.ofcontroller.topology.ITopologyNetService;
 import net.onrc.onos.ofcontroller.topology.Topology;
 import net.onrc.onos.ofcontroller.topology.TopologyManager;
@@ -77,7 +77,7 @@
 
 public class BgpRoute implements IFloodlightModule, IBgpRouteService, 
 									ITopologyListener, IArpRequester,
-									IOFSwitchListener, ILayer3InfoService,
+									IOFSwitchListener, IConfigInfoService,
 									IProxyArpService {
 	
 	private final static Logger log = LoggerFactory.getLogger(BgpRoute.class);
@@ -88,7 +88,7 @@
 	private ILinkDiscoveryService linkDiscoveryService;
 	private IRestApiService restApi;
 	
-	private ProxyArpManager proxyArp;
+	private IProxyArpService proxyArp;
 	
 	private IPatriciaTrie<RibEntry> ptree;
 	private IPatriciaTrie<Interface> interfacePtrie;
@@ -230,6 +230,7 @@
 		Collection<Class<? extends IFloodlightService>> l 
 			= new ArrayList<Class<? extends IFloodlightService>>();
 		l.add(IBgpRouteService.class);
+		l.add(IConfigInfoService.class);
 		return l;
 	}
 
@@ -238,7 +239,7 @@
 		Map<Class<? extends IFloodlightService>, IFloodlightService> m 
 			= new HashMap<Class<? extends IFloodlightService>, IFloodlightService>();
 		m.put(IBgpRouteService.class, this);
-		m.put(IProxyArpService.class, this);
+		m.put(IConfigInfoService.class, this);
 		return m;
 	}
 
@@ -269,7 +270,9 @@
 		
 		//TODO We'll initialise this here for now, but it should really be done as
 		//part of the controller core
-		proxyArp = new ProxyArpManager(floodlightProvider, topologyService, this, restApi);
+		//proxyArp = new ProxyArpManager(floodlightProvider, topologyService, this, restApi);
+		//proxyArp = new ProxyArpManager();
+		proxyArp = context.getServiceImpl(IProxyArpService.class);
 		
 		linkUpdates = new ArrayList<LDUpdate>();
 		ScheduledExecutorService executor = Executors.newScheduledThreadPool(1);
@@ -324,9 +327,9 @@
 		topologyService.addListener(this);
 		floodlightProvider.addOFSwitchListener(this);
 		
-		proxyArp.startUp(vlan);
+		//proxyArp.startUp(vlan);
 		
-		floodlightProvider.addOFMessageListener(OFType.PACKET_IN, proxyArp);
+		//floodlightProvider.addOFMessageListener(OFType.PACKET_IN, proxyArp);
 		
 		//Retrieve the RIB from BGPd during startup
 		retrieveRib();
@@ -1238,7 +1241,7 @@
 	}
 	
 	/*
-	 * ILayer3InfoService methods
+	 * IConfigInfoService methods
 	 */
 	
 	@Override
@@ -1277,6 +1280,11 @@
 	public MACAddress getRouterMacAddress() {
 		return bgpdMacAddress;
 	}
+	
+	@Override
+	public short getVlan() {
+		return vlan;
+	}
 
 	/*
 	 * TODO This is a hack to get the REST API to work for ProxyArpManager.
diff --git a/src/main/java/net/onrc/onos/ofcontroller/bgproute/Configuration.java b/src/main/java/net/onrc/onos/ofcontroller/bgproute/Configuration.java
index 7fabc72..4c81d1b 100644
--- a/src/main/java/net/onrc/onos/ofcontroller/bgproute/Configuration.java
+++ b/src/main/java/net/onrc/onos/ofcontroller/bgproute/Configuration.java
@@ -47,7 +47,7 @@
 	public void setBgpdMacAddress(String strMacAddress) {
 		this.bgpdMacAddress = MACAddress.valueOf(strMacAddress);
 	}
-
+	
 	public List<String> getSwitches() {
 		return Collections.unmodifiableList(switches);
 	}
@@ -65,7 +65,7 @@
 	public void setSwitches(List<String> switches) {
 		this.switches = switches;
 	}
-
+	
 	public List<Interface> getInterfaces() {
 		return Collections.unmodifiableList(interfaces);
 	}
diff --git a/src/main/java/net/onrc/onos/ofcontroller/core/IDeviceStorage.java b/src/main/java/net/onrc/onos/ofcontroller/core/IDeviceStorage.java
index 7310d8c..be495b9 100644
--- a/src/main/java/net/onrc/onos/ofcontroller/core/IDeviceStorage.java
+++ b/src/main/java/net/onrc/onos/ofcontroller/core/IDeviceStorage.java
@@ -9,7 +9,7 @@
 	public IDeviceObject updateDevice(IDevice device);
 	public void removeDevice(IDevice device);
 	public IDeviceObject getDeviceByMac(String mac);
-	public IDeviceObject getDeviceByIP(String ip);
+	public IDeviceObject getDeviceByIP(int ipv4Address);
 	public void changeDeviceAttachments(IDevice device);
 	public void changeDeviceIPv4Address(IDevice device);	
 }
diff --git a/src/main/java/net/onrc/onos/ofcontroller/core/INetMapTopologyObjects.java b/src/main/java/net/onrc/onos/ofcontroller/core/INetMapTopologyObjects.java
index 6f13080..6b84d32 100644
--- a/src/main/java/net/onrc/onos/ofcontroller/core/INetMapTopologyObjects.java
+++ b/src/main/java/net/onrc/onos/ofcontroller/core/INetMapTopologyObjects.java
@@ -149,12 +149,6 @@
 		@Property("dl_addr")
 		public void setMACAddress(String macaddr);
 		
-		@JsonProperty("ipv4")
-		@Property("nw_addr")
-		public String getIPAddress();
-		@Property("nw_addr")
-		public void setIPAddress(String ipaddr);
-		
 		@JsonIgnore
 		@Adjacency(label="host",direction = Direction.IN)
 		public Iterable<IPortObject> getAttachedPorts();
@@ -171,6 +165,23 @@
 		@GremlinGroovy("it.in('host').in('on')")
 		public Iterable<ISwitchObject> getSwitch();
 		
+		//
+		// IPv4 Addresses
+		//
+		@JsonProperty("ipv4addresses")
+		@Adjacency(label="hasAddress")
+		public Iterable<IIpv4Address> getIpv4Addresses();
+
+		@JsonIgnore
+		@GremlinGroovy("it.out('hasAddress').has('ipv4', ipv4Address)")
+		public IIpv4Address getIpv4Address(@GremlinParam("ipv4Address") final int ipv4Address);
+		
+		@Adjacency(label="hasAddress")
+		public void addIpv4Address(final IIpv4Address ipv4Address);
+		
+		@Adjacency(label="hasAddress")
+		public void removeIpv4Address(final IIpv4Address ipv4Address);
+		
 /*		@JsonProperty("dpid")
 		@GremlinGroovy("_().in('host').in('on').next().getProperty('dpid')")
 		public Iterable<String> getSwitchDPID();
@@ -183,7 +194,21 @@
 		@GremlinGroovy("_().in('host').in('on').path(){it.number}{it.dpid}")
 		public Iterable<SwitchPort> getAttachmentPoints();*/
 	}
-
+		
+	public interface IIpv4Address extends IBaseObject {
+		
+		@JsonProperty("ipv4")
+		@Property("ipv4_address")
+		public int getIpv4Address();
+		
+		@Property("ipv4_address")
+		public void setIpv4Address(int ipv4Address);
+		
+		@JsonIgnore
+		@GremlinGroovy("it.in('hasAddress')")
+		public IDeviceObject getDevice();
+	}
+	
 public interface IFlowPath extends IBaseObject {
 		@JsonProperty("flowId")
 		@Property("flow_id")
diff --git a/src/main/java/net/onrc/onos/ofcontroller/core/config/DefaultConfiguration.java b/src/main/java/net/onrc/onos/ofcontroller/core/config/DefaultConfiguration.java
new file mode 100644
index 0000000..d9a291f
--- /dev/null
+++ b/src/main/java/net/onrc/onos/ofcontroller/core/config/DefaultConfiguration.java
@@ -0,0 +1,47 @@
+package net.onrc.onos.ofcontroller.core.config;
+
+import java.net.InetAddress;
+
+import net.floodlightcontroller.util.MACAddress;
+import net.onrc.onos.ofcontroller.bgproute.Interface;
+
+import org.openflow.util.HexString;
+
+public class DefaultConfiguration implements IConfigInfoService {
+
+	@Override
+	public boolean isInterfaceAddress(InetAddress address) {
+		return false;
+	}
+
+	@Override
+	public boolean inConnectedNetwork(InetAddress address) {
+		return false;
+	}
+
+	@Override
+	public boolean fromExternalNetwork(long inDpid, short inPort) {
+		return false;
+	}
+
+	@Override
+	public Interface getOutgoingInterface(InetAddress dstIpAddress) {
+		return null;
+	}
+
+	@Override
+	public boolean hasLayer3Configuration() {
+		return false;
+	}
+	
+	@Override
+	public MACAddress getRouterMacAddress() {
+		return MACAddress.valueOf(HexString.fromHexString("000000000001"));
+	}
+
+	@Override
+	public short getVlan() {
+		return 0;
+	}
+
+}
diff --git a/src/main/java/net/onrc/onos/ofcontroller/bgproute/ILayer3InfoService.java b/src/main/java/net/onrc/onos/ofcontroller/core/config/IConfigInfoService.java
similarity index 67%
rename from src/main/java/net/onrc/onos/ofcontroller/bgproute/ILayer3InfoService.java
rename to src/main/java/net/onrc/onos/ofcontroller/core/config/IConfigInfoService.java
index 00ddd68..7bbf483 100644
--- a/src/main/java/net/onrc/onos/ofcontroller/bgproute/ILayer3InfoService.java
+++ b/src/main/java/net/onrc/onos/ofcontroller/core/config/IConfigInfoService.java
@@ -1,15 +1,17 @@
-package net.onrc.onos.ofcontroller.bgproute;
+package net.onrc.onos.ofcontroller.core.config;
 
 import java.net.InetAddress;
 
 import net.floodlightcontroller.util.MACAddress;
+import net.onrc.onos.ofcontroller.bgproute.Interface;
+import net.onrc.onos.ofcontroller.core.module.IOnosService;
 
 /**
  * Provides information about the layer 3 properties of the network.
  * This is based on IP addresses configured on ports in the network.
  *
  */
-public interface ILayer3InfoService {
+public interface IConfigInfoService extends IOnosService {
 	public boolean isInterfaceAddress(InetAddress address);
 	public boolean inConnectedNetwork(InetAddress address);
 	public boolean fromExternalNetwork(long inDpid, short inPort);
@@ -32,4 +34,15 @@
 	public boolean hasLayer3Configuration();
 	
 	public MACAddress getRouterMacAddress();
+	
+	/**
+	* We currently have basic vlan support for the situation when the contr
+	* is running within a single vlan. In this case, packets sent from the 
+	* controller (e.g. ARP) need to be tagged with that vlan.
+	* @return The vlan id configured in the config file, 
+	* or 0 if no vlan is configured.
+	*/
+	public short getVlan();
+
+
 }
diff --git a/src/main/java/net/onrc/onos/ofcontroller/core/internal/DeviceStorageImpl.java b/src/main/java/net/onrc/onos/ofcontroller/core/internal/DeviceStorageImpl.java
index 63eaacb..256008a 100644
--- a/src/main/java/net/onrc/onos/ofcontroller/core/internal/DeviceStorageImpl.java
+++ b/src/main/java/net/onrc/onos/ofcontroller/core/internal/DeviceStorageImpl.java
@@ -1,30 +1,31 @@
 package net.onrc.onos.ofcontroller.core.internal;
 
-import java.util.ArrayList;
+import java.util.Arrays;
 import java.util.List;
+
+import net.floodlightcontroller.devicemanager.IDevice;
+import net.floodlightcontroller.devicemanager.SwitchPort;
+import net.onrc.onos.graph.GraphDBOperation;
+import net.onrc.onos.ofcontroller.core.IDeviceStorage;
+import net.onrc.onos.ofcontroller.core.INetMapTopologyObjects.IDeviceObject;
+import net.onrc.onos.ofcontroller.core.INetMapTopologyObjects.IIpv4Address;
+import net.onrc.onos.ofcontroller.core.INetMapTopologyObjects.IPortObject;
+
 import org.openflow.util.HexString;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
 import com.google.common.collect.Lists;
 import com.thinkaurelius.titan.core.TitanException;
-import net.floodlightcontroller.devicemanager.IDevice;
-import net.floodlightcontroller.devicemanager.SwitchPort;
-import net.floodlightcontroller.packet.IPv4;
-import net.onrc.onos.graph.GraphDBOperation;
-import net.onrc.onos.ofcontroller.core.IDeviceStorage;
-import net.onrc.onos.ofcontroller.core.INetMapTopologyObjects.IDeviceObject;
-import net.onrc.onos.ofcontroller.core.INetMapTopologyObjects.IPortObject;
-import net.onrc.onos.ofcontroller.core.internal.SwitchStorageImpl;
 
 /**
  * This is the class for storing the information of devices into CassandraDB
  * @author Pankaj
  */
 public class DeviceStorageImpl implements IDeviceStorage {
+	protected final static Logger log = LoggerFactory.getLogger(SwitchStorageImpl.class);
 	
 	private GraphDBOperation ope;
-	protected final static Logger log = LoggerFactory.getLogger(SwitchStorageImpl.class);
 
 	/***
 	 * Initialize function. Before you use this class, please call this method
@@ -32,10 +33,10 @@
 	 */
 	@Override
 	public void init(String conf) {
-		try{
+		try {
 			ope = new GraphDBOperation(conf);
-		} catch(Exception e) {
-			log.error(e.getMessage());
+		} catch (TitanException e) {
+			log.error("Couldn't open graph operation", e);
 		}
 	}	
 	
@@ -67,39 +68,31 @@
 		IDeviceObject obj = null;
  		try {
  			if ((obj = ope.searchDevice(device.getMACAddressString())) != null) {
- 				log.debug("Adding device {}: found existing device",device.getMACAddressString());
+ 				log.debug("Adding device {}: found existing device", device.getMACAddressString());
             } else {
             	obj = ope.newDevice();
-                log.debug("Adding device {}: creating new device",device.getMACAddressString());
+                log.debug("Adding device {}: creating new device", device.getMACAddressString());
             }
-	            changeDeviceAttachments(device, obj);
-	
-				String multiIntString = "";
-				for(Integer intValue : device.getIPv4Addresses()) {
-				   if (multiIntString == null || multiIntString.isEmpty()){
-				     multiIntString = IPv4.fromIPv4Address(intValue);
-				     multiIntString = "[" + IPv4.fromIPv4Address(intValue);
-				   }else{
-				        multiIntString += "," + IPv4.fromIPv4Address(intValue);
-				   }
-				}
-	 	            
-	            if(multiIntString.toString() != null && !multiIntString.toString().isEmpty()){
-	            	obj.setIPAddress(multiIntString + "]");
-	            }
-	            
-	 			obj.setMACAddress(device.getMACAddressString());
-	 			obj.setType("device");
-	 			obj.setState("ACTIVE");
-	 			ope.commit();
  			
-	 			log.debug("Adding device {}",device.getMACAddressString());
-		} catch (Exception e) {
+            changeDeviceAttachments(device, obj);
+	            
+            for (Integer intIpv4Address : device.getIPv4Addresses()) {
+            	obj.addIpv4Address(ope.ensureIpv4Address(intIpv4Address));
+            }
+            
+ 			obj.setMACAddress(device.getMACAddressString());
+ 			obj.setType("device");
+ 			obj.setState("ACTIVE");
+ 			ope.commit();
+		
+ 			//log.debug("Adding device {}",device.getMACAddressString());
+		} catch (TitanException e) {
 			ope.rollback();
 			log.error(":addDevice mac:{} failed", device.getMACAddressString());
 			obj = null;
-		}	
- 			return obj;		
+		}
+ 		
+		return obj;		
 	}
 
 	/***
@@ -125,7 +118,7 @@
              	ope.commit();
             	log.error("DeviceStorage:removeDevice mac:{} done", device.getMACAddressString());
             }
-		} catch (Exception e) {
+		} catch (TitanException e) {
 			ope.rollback();
 			log.error("DeviceStorage:removeDevice mac:{} failed", device.getMACAddressString());
 		}
@@ -147,23 +140,15 @@
 	 * @return IDeviceObject you want to get.
 	 */
 	@Override
-	public IDeviceObject getDeviceByIP(String ip) {
-		try
-		{
-			for(IDeviceObject dev : ope.getDevices()){
-				String ips;
-				if((ips = dev.getIPAddress()) != null){
-					String nw_addr_wob = ips.replace("[", "").replace("]", "");
-					ArrayList<String> iplists = Lists.newArrayList(nw_addr_wob.split(","));	
-					if(iplists.contains(ip)){
-						return dev;
-					}
-				}
+	public IDeviceObject getDeviceByIP(int ipv4Address) {
+		try {
+			IIpv4Address ipv4AddressVertex = ope.searchIpv4Address(ipv4Address);
+			if (ipv4AddressVertex != null) {
+				return ipv4AddressVertex.getDevice();
 			}
 			return null;
 		}
-		catch (Exception e)
-		{
+		catch (TitanException e) {
 			log.error("DeviceStorage:getDeviceByIP:{} failed");
 			return null;
 		}
@@ -178,14 +163,14 @@
 		IDeviceObject obj = null;
  		try {
             if ((obj = ope.searchDevice(device.getMACAddressString())) != null) {
-                log.debug("Changing device ports {}: found existing device",device.getMACAddressString());
+                log.debug("Changing device ports {}: found existing device", device.getMACAddressString());
                 changeDeviceAttachments(device, obj);
                 ope.commit();
             } else {
-   				log.debug("failed to search device...now adding {}",device.getMACAddressString());
+   				log.debug("failed to search device...now adding {}", device.getMACAddressString());
    				addDevice(device);
-            }            			
-		} catch (Exception e) {
+            }
+		} catch (TitanException e) {
 			ope.rollback();
 			log.error(":addDevice mac:{} failed", device.getMACAddressString());
 		}	
@@ -199,33 +184,33 @@
 	public void changeDeviceAttachments(IDevice device, IDeviceObject obj) {
 		SwitchPort[] attachmentPoints = device.getAttachmentPoints();
 		List<IPortObject> attachedPorts = Lists.newArrayList(obj.getAttachedPorts());
-		
-        for (SwitchPort ap : attachmentPoints) {
-        	//Check weather there is the port
-          	 IPortObject port = ope.searchPort( HexString.toHexString(ap.getSwitchDPID()),
-												(short) ap.getPort());
-          	 log.debug("New Switch Port is {},{}", HexString.toHexString(ap.getSwitchDPID()),(short) ap.getPort());
-	       	 
-	       	 if(port != null){
-	   			if(attachedPorts.contains(port))
-	       		{
-		       		log.debug("This is the port you already attached {}: do nothing",device.getMACAddressString());
-		       		//This port will be remained, so remove from the removed port lists.
-		       		attachedPorts.remove(port);
-		       	} else {
-	     		   log.debug("Adding device {}: attaching to port",device.getMACAddressString());
-		       		port.setDevice(obj);  
-		        }
-	    	
-		       	log.debug("port number is {}", port.getNumber().toString());
-		        log.debug("port desc is {}", port.getDesc());  
-	       	 }
-        }      		 
-	            
-	    for (IPortObject port: attachedPorts) {
-            log.debug("Detouching the device {}: detouching from port",device.getMACAddressString());
-       		port.removeDevice(obj);
-        }
+
+		for (SwitchPort ap : attachmentPoints) {
+			//Check if there is the port
+			IPortObject port = ope.searchPort(HexString.toHexString(ap.getSwitchDPID()),
+					(short) ap.getPort());
+			log.debug("New Switch Port is {},{}", 
+					HexString.toHexString(ap.getSwitchDPID()), (short) ap.getPort());
+
+			if (port != null){
+				if (attachedPorts.contains(port)) {
+					log.debug("This is the port you already attached {}: do nothing", device.getMACAddressString());
+					//This port will be remained, so remove from the removed port lists.
+					attachedPorts.remove(port);
+				} else {
+					log.debug("Adding device {}: attaching to port", device.getMACAddressString());
+					port.setDevice(obj);  
+				}
+
+				log.debug("port number is {}", port.getNumber().toString());
+				log.debug("port desc is {}", port.getDesc());  
+			}
+		}      		 
+
+		for (IPortObject port: attachedPorts) {
+			log.debug("Detaching the device {}: detaching from port", device.getMACAddressString());
+			port.removeDevice(obj);
+		}
 	}
 
 	/***
@@ -234,22 +219,24 @@
 	 */
 	@Override
 	public void changeDeviceIPv4Address(IDevice device) {
+		log.debug("Changing IP address for {} to {}", device.getMACAddressString(),
+				device.getIPv4Addresses());
 		IDeviceObject obj;
   		try {
   			if ((obj = ope.searchDevice(device.getMACAddressString())) != null) {
-
-  				String multiIntString = "";
-  				for(Integer intValue : device.getIPv4Addresses()){
-  				   if (multiIntString == null || multiIntString.isEmpty()){
-  				     multiIntString = "[" + IPv4.fromIPv4Address(intValue);
-  				   } else {
-  				        multiIntString += "," + IPv4.fromIPv4Address(intValue);
-  				   }
+  				for (int ipv4Address : device.getIPv4Addresses()) {
+  					if (obj.getIpv4Address(ipv4Address) == null) {
+  						IIpv4Address dbIpv4Address = ope.ensureIpv4Address(ipv4Address);
+  						obj.addIpv4Address(dbIpv4Address);
+  					}
   				}
   				
-  	            if(multiIntString != null && !multiIntString.isEmpty()){
-  	            	obj.setIPAddress(multiIntString + "]");
-  	            }
+  				List<Integer> deviceIpv4Addresses = Arrays.asList(device.getIPv4Addresses());
+  				for (IIpv4Address dbIpv4Address : obj.getIpv4Addresses()) {
+  					if (!deviceIpv4Addresses.contains(dbIpv4Address.getIpv4Address())) {
+  						obj.removeIpv4Address(dbIpv4Address);
+  					}
+  				}
   	            
               	ope.commit();
   			} else {
@@ -257,7 +244,7 @@
             }		
   		} catch (TitanException e) {
   			ope.rollback();
-			log.error(":changeDeviceIPv4Address mac:{} failed due to exception {}", device.getMACAddressString(),e);
+			log.error(":changeDeviceIPv4Address mac:{} failed due to exception {}", device.getMACAddressString(), e);
 		}
 	}
 
diff --git a/src/main/java/net/onrc/onos/ofcontroller/core/internal/SwitchStorageImpl.java b/src/main/java/net/onrc/onos/ofcontroller/core/internal/SwitchStorageImpl.java
index ac61b51..1735a36 100644
--- a/src/main/java/net/onrc/onos/ofcontroller/core/internal/SwitchStorageImpl.java
+++ b/src/main/java/net/onrc/onos/ofcontroller/core/internal/SwitchStorageImpl.java
@@ -342,6 +342,11 @@
         }
 	}
 
+	// TODO There's an issue here where a port with that ID could already
+	// exist when we try to add this one (because it's left over from an
+	// old topology). We need to remove an old port with the same ID when
+	// we add the new port. Also it seems that old ports like this are 
+	// never cleaned up and will remain in the DB in the ACTIVE state forever.
 	private IPortObject addPortImpl(ISwitchObject sw, short portNum) {
 		IPortObject p = op.newPort(sw.getDPID(), portNum);
 		p.setState("ACTIVE");
diff --git a/src/main/java/net/onrc/onos/ofcontroller/core/module/IOnosService.java b/src/main/java/net/onrc/onos/ofcontroller/core/module/IOnosService.java
new file mode 100644
index 0000000..5828366
--- /dev/null
+++ b/src/main/java/net/onrc/onos/ofcontroller/core/module/IOnosService.java
@@ -0,0 +1,7 @@
+package net.onrc.onos.ofcontroller.core.module;
+
+import net.floodlightcontroller.core.module.IFloodlightService;
+
+public interface IOnosService extends IFloodlightService {
+
+}
diff --git a/src/main/java/net/onrc/onos/ofcontroller/core/module/OnosModuleLoader.java b/src/main/java/net/onrc/onos/ofcontroller/core/module/OnosModuleLoader.java
new file mode 100644
index 0000000..bd7cf49
--- /dev/null
+++ b/src/main/java/net/onrc/onos/ofcontroller/core/module/OnosModuleLoader.java
@@ -0,0 +1,86 @@
+package net.onrc.onos.ofcontroller.core.module;
+
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+import net.floodlightcontroller.core.IFloodlightProviderService;
+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.devicemanager.IDeviceService;
+import net.floodlightcontroller.restserver.IRestApiService;
+import net.floodlightcontroller.topology.ITopologyService;
+import net.onrc.onos.ofcontroller.core.config.DefaultConfiguration;
+import net.onrc.onos.ofcontroller.core.config.IConfigInfoService;
+import net.onrc.onos.ofcontroller.proxyarp.IProxyArpService;
+import net.onrc.onos.ofcontroller.proxyarp.ProxyArpManager;
+
+public class OnosModuleLoader implements IFloodlightModule {
+	private IFloodlightProviderService floodlightProvider;
+	private ITopologyService topology;
+	private IDeviceService deviceService;
+	private IConfigInfoService config;
+	private IRestApiService restApi;
+
+	private ProxyArpManager arpManager;
+	
+	public OnosModuleLoader() {
+		arpManager = new ProxyArpManager();
+	}
+	
+	@Override
+	public Collection<Class<? extends IFloodlightService>> getModuleServices() {
+		List<Class<? extends IFloodlightService>> services = 
+				new ArrayList<Class<? extends IFloodlightService>>();
+		services.add(IProxyArpService.class);
+		return services;
+	}
+
+	@Override
+	public Map<Class<? extends IFloodlightService>, IFloodlightService> getServiceImpls() {
+		Map<Class<? extends IFloodlightService>, IFloodlightService> impls = 
+				new HashMap<Class<? extends IFloodlightService>, IFloodlightService>();
+		impls.put(IProxyArpService.class, arpManager);
+		return impls;
+	}
+
+	@Override
+	public Collection<Class<? extends IFloodlightService>> getModuleDependencies() {
+		List<Class<? extends IFloodlightService>> dependencies = 
+				new ArrayList<Class<? extends IFloodlightService>>();
+		dependencies.add(IFloodlightProviderService.class);
+		dependencies.add(ITopologyService.class);
+		dependencies.add(IDeviceService.class);
+		//dependencies.add(IConfigInfoService.class);
+		dependencies.add(IRestApiService.class);
+		return dependencies;
+	}
+
+	@Override
+	public void init(FloodlightModuleContext context)
+			throws FloodlightModuleException {
+		floodlightProvider = context.getServiceImpl(IFloodlightProviderService.class);
+		topology = context.getServiceImpl(ITopologyService.class);
+		deviceService = context.getServiceImpl(IDeviceService.class);
+		restApi = context.getServiceImpl(IRestApiService.class);
+		
+		//This could be null because it's not mandatory to have an
+		//IConfigInfoService loaded.
+		config = context.getServiceImpl(IConfigInfoService.class);
+		if (config == null) {
+			config = new DefaultConfiguration();
+		}
+
+		arpManager.init(floodlightProvider, topology, deviceService, config, restApi);
+	}
+
+	@Override
+	public void startUp(FloodlightModuleContext context) {
+		arpManager.startUp();
+	}
+
+}
diff --git a/src/main/java/net/onrc/onos/ofcontroller/proxyarp/IProxyArpService.java b/src/main/java/net/onrc/onos/ofcontroller/proxyarp/IProxyArpService.java
index 97844d3..71546a1 100644
--- a/src/main/java/net/onrc/onos/ofcontroller/proxyarp/IProxyArpService.java
+++ b/src/main/java/net/onrc/onos/ofcontroller/proxyarp/IProxyArpService.java
@@ -3,11 +3,11 @@
 import java.net.InetAddress;
 import java.util.List;
 
-import net.floodlightcontroller.core.module.IFloodlightService;
 import net.floodlightcontroller.util.MACAddress;
+import net.onrc.onos.ofcontroller.core.module.IOnosService;
 
 //Extends IFloodlightService so we can access it from REST API resources
-public interface IProxyArpService extends IFloodlightService{
+public interface IProxyArpService extends IOnosService{
 	/**
 	 * Returns the MAC address if there is a valid entry in the cache.
 	 * Otherwise returns null.
diff --git a/src/main/java/net/onrc/onos/ofcontroller/proxyarp/ProxyArpManager.java b/src/main/java/net/onrc/onos/ofcontroller/proxyarp/ProxyArpManager.java
index 0151212..a5dabc9 100644
--- a/src/main/java/net/onrc/onos/ofcontroller/proxyarp/ProxyArpManager.java
+++ b/src/main/java/net/onrc/onos/ofcontroller/proxyarp/ProxyArpManager.java
@@ -5,6 +5,7 @@
 import java.net.UnknownHostException;
 import java.util.ArrayList;
 import java.util.Collection;
+import java.util.HashSet;
 import java.util.Iterator;
 import java.util.List;
 import java.util.Map;
@@ -16,14 +17,18 @@
 import net.floodlightcontroller.core.IFloodlightProviderService;
 import net.floodlightcontroller.core.IOFMessageListener;
 import net.floodlightcontroller.core.IOFSwitch;
+import net.floodlightcontroller.devicemanager.IDeviceService;
 import net.floodlightcontroller.packet.ARP;
 import net.floodlightcontroller.packet.Ethernet;
 import net.floodlightcontroller.packet.IPv4;
 import net.floodlightcontroller.restserver.IRestApiService;
 import net.floodlightcontroller.topology.ITopologyService;
 import net.floodlightcontroller.util.MACAddress;
-import net.onrc.onos.ofcontroller.bgproute.ILayer3InfoService;
 import net.onrc.onos.ofcontroller.bgproute.Interface;
+import net.onrc.onos.ofcontroller.core.IDeviceStorage;
+import net.onrc.onos.ofcontroller.core.INetMapTopologyObjects.IDeviceObject;
+import net.onrc.onos.ofcontroller.core.config.IConfigInfoService;
+import net.onrc.onos.ofcontroller.core.internal.DeviceStorageImpl;
 
 import org.openflow.protocol.OFMessage;
 import org.openflow.protocol.OFPacketIn;
@@ -39,6 +44,7 @@
 import com.google.common.collect.HashMultimap;
 import com.google.common.collect.Multimaps;
 import com.google.common.collect.SetMultimap;
+import com.google.common.net.InetAddresses;
 
 public class ProxyArpManager implements IProxyArpService, IOFMessageListener {
 	private final static Logger log = LoggerFactory.getLogger(ProxyArpManager.class);
@@ -47,17 +53,20 @@
 	
 	private static final int ARP_REQUEST_TIMEOUT = 2000; //ms
 			
-	private final IFloodlightProviderService floodlightProvider;
-	private final ITopologyService topology;
-	private final ILayer3InfoService layer3;
-	private final IRestApiService restApi;
+	private IFloodlightProviderService floodlightProvider;
+	private ITopologyService topology;
+	private IDeviceService deviceService;
+	private IConfigInfoService configService;
+	private IRestApiService restApi;
+	
+	private IDeviceStorage deviceStorage;
 	
 	private short vlan;
 	private static final short NO_VLAN = 0;
 	
-	private final ArpCache arpCache;
+	private ArpCache arpCache;
 
-	private final SetMultimap<InetAddress, ArpRequest> arpRequests;
+	private SetMultimap<InetAddress, ArpRequest> arpRequests;
 	
 	private static class ArpRequest {
 		private final IArpRequester requester;
@@ -106,12 +115,21 @@
 		}
 	}
 	
+	/*
 	public ProxyArpManager(IFloodlightProviderService floodlightProvider,
-				ITopologyService topology, ILayer3InfoService layer3,
+				ITopologyService topology, IConfigInfoService configService,
 				IRestApiService restApi){
+
+	}
+	*/
+	
+	public void init(IFloodlightProviderService floodlightProvider,
+			ITopologyService topology, IDeviceService deviceService,
+			IConfigInfoService config, IRestApiService restApi){
 		this.floodlightProvider = floodlightProvider;
 		this.topology = topology;
-		this.layer3 = layer3;
+		this.deviceService = deviceService;
+		this.configService = config;
 		this.restApi = restApi;
 		
 		arpCache = new ArpCache();
@@ -120,11 +138,15 @@
 				HashMultimap.<InetAddress, ArpRequest>create());
 	}
 	
-	public void startUp(short vlan) {
-		this.vlan = vlan;
+	public void startUp() {
+		this.vlan = configService.getVlan();
 		log.info("vlan set to {}", this.vlan);
 		
 		restApi.addRestletRoutable(new ArpWebRoutable());
+		floodlightProvider.addOFMessageListener(OFType.PACKET_IN, this);
+		
+		deviceStorage = new DeviceStorageImpl();
+		deviceStorage.init("");
 		
 		Timer arpTimer = new Timer("arp-processing");
 		arpTimer.scheduleAtFixedRate(new TimerTask() {
@@ -188,12 +210,17 @@
 	
 	@Override
 	public String getName() {
-		return "ProxyArpManager";
+		return "proxyarpmanager";
 	}
 
 	@Override
 	public boolean isCallbackOrderingPrereq(OFType type, String name) {
-		return false;
+		if (type == OFType.PACKET_IN) {
+			return "devicemanager".equals(name);
+		}
+		else {
+			return false;
+		}
 	}
 
 	@Override
@@ -218,10 +245,14 @@
 			ARP arp = (ARP) eth.getPayload();
 			
 			if (arp.getOpCode() == ARP.OP_REQUEST) {
+				//TODO check what the DeviceManager does about propagating
+				//or swallowing ARPs. We want to go after DeviceManager in the
+				//chain but we really need it to CONTINUE ARP packets so we can
+				//get them.
 				handleArpRequest(sw, pi, arp);
 			}
 			else if (arp.getOpCode() == ARP.OP_REPLY) {
-				handleArpReply(sw, pi, arp);
+				//handleArpReply(sw, pi, arp);
 			}
 		}
 		
@@ -244,31 +275,56 @@
 			return;
 		}
 
-		if (layer3.fromExternalNetwork(sw.getId(), pi.getInPort())) {
+		if (configService.fromExternalNetwork(sw.getId(), pi.getInPort())) {
 			//If the request came from outside our network, we only care if
 			//it was a request for one of our interfaces.
-			if (layer3.isInterfaceAddress(target)) {
+			if (configService.isInterfaceAddress(target)) {
 				log.trace("ARP request for our interface. Sending reply {} => {}",
-						target.getHostAddress(), layer3.getRouterMacAddress());
+						target.getHostAddress(), configService.getRouterMacAddress());
 				
 				sendArpReply(arp, sw.getId(), pi.getInPort(), 
-						layer3.getRouterMacAddress());
+						configService.getRouterMacAddress());
 			}
 			
 			return;
 		}
 		
-		MACAddress macAddress = arpCache.lookup(target);
+		//MACAddress macAddress = arpCache.lookup(target);
 		
-		if (macAddress == null){
+		//IDevice dstDevice = deviceService.fcStore.get(cntx, IDeviceService.CONTEXT_DST_DEVICE);
+		//Iterator<? extends IDevice> it = deviceService.queryDevices(
+				//null, null, InetAddresses.coerceToInteger(target), null, null);
+		
+		//IDevice targetDevice = null;
+		//if (it.hasNext()) {
+			//targetDevice = it.next();
+		//}
+		IDeviceObject targetDevice = 
+				deviceStorage.getDeviceByIP(InetAddresses.coerceToInteger(target));
+		
+		if (targetDevice != null) {
+			//We have the device in our database, so send a reply
+			MACAddress macAddress = MACAddress.valueOf(targetDevice.getMACAddress());
+			
+			if (log.isTraceEnabled()) {
+				log.trace("Sending reply: {} => {} to host at {}/{}", new Object [] {
+						inetAddressToString(arp.getTargetProtocolAddress()),
+						macAddress.toString(),
+						HexString.toHexString(sw.getId()), pi.getInPort()});
+			}
+			
+			sendArpReply(arp, sw.getId(), pi.getInPort(), macAddress);
+		}
+		
+		/*if (macAddress == null){
 			//MAC address is not in our ARP cache.
 			
 			//Record where the request came from so we know where to send the reply
-			arpRequests.put(target, new ArpRequest(
-					new HostArpRequester(arp, sw.getId(), pi.getInPort()), false));
+			//arpRequests.put(target, new ArpRequest(
+					//new HostArpRequester(arp, sw.getId(), pi.getInPort()), false));
 						
 			//Flood the request out edge ports
-			sendArpRequestToSwitches(target, pi.getPacketData(), sw.getId(), pi.getInPort());
+			//sendArpRequestToSwitches(target, pi.getPacketData(), sw.getId(), pi.getInPort());
 		}
 		else {
 			//We know the address, so send a reply
@@ -280,7 +336,7 @@
 			}
 			
 			sendArpReply(arp, sw.getId(), pi.getInPort(), macAddress);
-		}
+		}*/
 	}
 	
 	private void handleArpReply(IOFSwitch sw, OFPacketIn pi, ARP arp){
@@ -345,7 +401,7 @@
 			.setTargetHardwareAddress(zeroMac)
 			.setTargetProtocolAddress(ipAddress.getAddress());
 
-		MACAddress routerMacAddress = layer3.getRouterMacAddress();
+		MACAddress routerMacAddress = configService.getRouterMacAddress();
 		//TODO hack for now as it's unclear what the MAC address should be
 		byte[] senderMacAddress = genericNonZeroMac;
 		if (routerMacAddress != null) {
@@ -354,7 +410,7 @@
 		arpRequest.setSenderHardwareAddress(senderMacAddress);
 		
 		byte[] senderIPAddress = zeroIpv4;
-		Interface intf = layer3.getOutgoingInterface(ipAddress);
+		Interface intf = configService.getOutgoingInterface(ipAddress);
 		if (intf != null) {
 			senderIPAddress = intf.getIpAddress().getAddress();
 		}
@@ -383,8 +439,8 @@
 	private void sendArpRequestToSwitches(InetAddress dstAddress, byte[] arpRequest,
 			long inSwitch, short inPort) {
 
-		if (layer3.hasLayer3Configuration()) {
-			Interface intf = layer3.getOutgoingInterface(dstAddress);
+		if (configService.hasLayer3Configuration()) {
+			Interface intf = configService.getOutgoingInterface(dstAddress);
 			if (intf != null) {
 				sendArpRequestOutPort(arpRequest, intf.getDpid(), intf.getPort());
 			}
@@ -409,11 +465,12 @@
 			Set<Short> linkPorts = topology.getPortsWithLinks(sw.getId());
 			
 			if (linkPorts == null){
-				//I think this means the switch isn't known to topology yet.
-				//Maybe it only just joined.
-				continue;
+				//I think this means the switch doesn't have any links.
+				//continue;
+				linkPorts = new HashSet<Short>();
 			}
 			
+			
 			OFPacketOut po = new OFPacketOut();
 			po.setInPort(OFPort.OFPP_NONE)
 				.setBufferId(-1)
@@ -571,7 +628,7 @@
 		arpRequests.put(ipAddress, new ArpRequest(requester, retry));
 		
 		//Sanity check to make sure we don't send a request for our own address
-		if (!layer3.isInterfaceAddress(ipAddress)) {
+		if (!configService.isInterfaceAddress(ipAddress)) {
 			sendArpRequestForAddress(ipAddress);
 		}
 	}
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 99ded31..7c4bc1a 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
@@ -24,3 +24,4 @@
 net.onrc.onos.ofcontroller.bgproute.BgpRoute
 net.onrc.onos.registry.controller.ZookeeperRegistry
 net.onrc.onos.registry.controller.StandaloneRegistry
+net.onrc.onos.ofcontroller.core.module.OnosModuleLoader
\ No newline at end of file