Link Storage graph implementation using Titan graph apis.
ONOS.sh a shell script to run Floodlight.
diff --git a/onos.sh b/onos.sh
new file mode 100755
index 0000000..4814e34
--- /dev/null
+++ b/onos.sh
@@ -0,0 +1,55 @@
+#!/bin/sh
+
+# Set paths
+FL_HOME=`dirname $0`
+FL_JAR="${FL_HOME}/target/floodlight.jar"
+FL_LOGBACK="${FL_HOME}/logback.xml"
+
+# Set JVM options
+JVM_OPTS=""
+#JVM_OPTS="$JVM_OPTS -server -d64"
+#JVM_OPTS="$JVM_OPTS -Xmx2g -Xms2g -Xmn800m"
+#JVM_OPTS="$JVM_OPTS -XX:+UseParallelGC -XX:+AggressiveOpts -XX:+UseFastAccessorMethods"
+#JVM_OPTS="$JVM_OPTS -XX:MaxInlineSize=8192 -XX:FreqInlineSize=8192"
+#JVM_OPTS="$JVM_OPTS -XX:CompileThreshold=1500 -XX:PreBlockSpin=8"
+#JVM_OPTS="$JVM_OPTS -Dpython.security.respectJavaAccessibility=false"
+
+# Set classpath to include titan libs
+CLASSPATH=`echo ${FL_HOME}/lib/*.jar ${FL_HOME}/lib/titan/*.jar | sed 's/ /:/g'`
+
+
+# Create a logback file if required
+cat <<EOF_LOGBACK >${FL_LOGBACK}
+<configuration scan="true" debug="true">
+  <appender name="STDOUT" class="ch.qos.logback.core.ConsoleAppender">
+    <encoder>
+      <pattern>%level [%logger:%thread] %msg%n</pattern>
+    </encoder>
+  </appender>
+
+  <appender name="FILE" class="ch.qos.logback.core.FileAppender">
+    <file>onos.log</file>
+    <encoder>
+      <pattern>%date %level [%thread] %logger{10} [%file:%line] %msg%n</pattern>
+    </encoder>
+  </appender>
+
+  <logger name="org" level="WARN"/>
+  <logger name="LogService" level="WARN"/> <!-- Restlet access logging -->
+  <logger name="net.floodlightcontroller.logging" level="WARN"/>
+
+  <root level="DEBUG">
+    <appender-ref ref="STDOUT" />
+    <appender-ref ref="FILE" />
+  </root>
+</configuration>
+EOF_LOGBACK
+
+# Delete and recreate /tmp/netmap
+rm -r /tmp/netmap
+mkdir /tmp/netmap
+
+# Run floodlight
+echo "Starting ONOS controller ..."
+echo 
+java ${JVM_OPTS} -Dlogback.configurationFile=${FL_LOGBACK} -Xbootclasspath/a:$CLASSPATH -jar ${FL_JAR} -cf ./onos.properties
diff --git a/src/main/java/net/floodlightcontroller/linkdiscovery/internal/LinkStorageImpl.java b/src/main/java/net/floodlightcontroller/linkdiscovery/internal/LinkStorageImpl.java
new file mode 100644
index 0000000..af99506
--- /dev/null
+++ b/src/main/java/net/floodlightcontroller/linkdiscovery/internal/LinkStorageImpl.java
@@ -0,0 +1,137 @@
+package net.floodlightcontroller.linkdiscovery.internal;
+
+import java.util.*;
+
+import org.openflow.util.HexString;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import net.floodlightcontroller.linkdiscovery.LinkInfo;
+import net.floodlightcontroller.routing.Link;
+import net.floodlightcontroller.linkdiscovery.ILinkStorage;
+
+import org.apache.commons.configuration.BaseConfiguration;
+import org.apache.commons.configuration.Configuration;
+import com.thinkaurelius.titan.core.TitanException;
+import com.thinkaurelius.titan.core.TitanFactory;
+import com.thinkaurelius.titan.core.TitanGraph;
+import com.tinkerpop.blueprints.Direction;
+import com.tinkerpop.blueprints.TransactionalGraph.Conclusion;
+import com.tinkerpop.blueprints.Vertex;
+
+public class LinkStorageImpl implements ILinkStorage {
+	public TitanGraph graph;
+	protected static Logger log = LoggerFactory.getLogger(LinkStorageImpl.class);
+	
+	@Override
+	public void update(Link link, DM_OPERATION op) {
+		update (link, (LinkInfo)null, op);
+	}
+
+	@Override
+	public void update(List<Link> links, DM_OPERATION op) {
+		log.debug("LinkStorage:update(): {} {}", op, links);
+
+		for (Link lt: links) {
+			update(lt, op);
+		}
+	}
+
+	@Override
+	public void update(Link link, LinkInfo linkinfo, DM_OPERATION op) {
+		log.debug("LinkStorage:update(): {} {}", op, link);
+		
+		switch (op) {
+		case UPDATE:
+		case CREATE:
+		case INSERT:
+			addLink(link, linkinfo);
+			break;
+		case DELETE:
+			break;
+		}
+	}
+
+	protected void addLink(Link lt, LinkInfo linkinfo) {
+		Vertex vswSrc, vswDst;
+		Vertex vportSrc = null, vportDst = null;
+	
+		log.debug("addLink(): {} {} getSrc {}", new Object[]{lt, linkinfo, lt.getSrc()});
+		
+        try {
+            // get source port vertex
+        	String dpid = HexString.toHexString(lt.getSrc());
+        	short port = lt.getSrcPort();
+            if ((vswSrc = graph.getVertices("dpid", dpid).iterator().next()) != null) {
+            	log.debug("addLink(): sw exits {} {}", dpid, vswSrc);
+            	if (vswSrc.query().direction(Direction.OUT).labels("on").has("number",port).vertices().iterator().hasNext()) {
+            		vportSrc = vswSrc.query().direction(Direction.OUT).labels("on").has("number",port).vertices().iterator().next();
+            		log.debug("addLink(): port found {} {}", port, vportSrc);
+            	} else {
+            		log.error("addLink(): sw {} port {} not found", dpid, port);
+            	}
+            }
+            
+            // get dest port vertex
+            dpid = HexString.toHexString(lt.getDst());
+            port = lt.getDstPort();
+            if ((vswDst = graph.getVertices("dpid",dpid).iterator().next()) != null) {
+            	log.debug("addLink(): sw exits {} {}", dpid, vswDst);
+            	if (vswDst.query().direction(Direction.OUT).labels("on").has("number",port).vertices().iterator().hasNext()) {
+            		vportDst = vswDst.query().direction(Direction.OUT).labels("on").has("number",port).vertices().iterator().next();
+            		log.debug("addLink(): port found {} {}", port, vportDst);
+            	} else {
+            		log.error ("addLink(): sw {} port {} not found", dpid, port);
+            	}
+            }
+            
+            if (vportSrc != null && vportDst != null) {
+        		graph.addEdge(null, vportSrc, vportDst, "link");
+        		graph.stopTransaction(Conclusion.SUCCESS);
+        		log.debug("addLink(): link added {} src {} dst {}", new Object[]{lt, vportSrc, vportDst});
+            } else {
+            	log.error("addLink(): failed {} src {} dst {}", new Object[]{lt, vportSrc, vportDst});
+            	graph.stopTransaction(Conclusion.FAILURE);
+            }
+        } catch (TitanException e) {
+            /*
+             * retry till we succeed?
+             */
+        	log.error("addLink(): {} failed", lt);
+        }
+	}
+	
+	@Override
+	public List<Link> getLinks(Long dpid, int port) {
+		// TODO Auto-generated method stub
+		return null;
+	}
+
+	@Override
+	public void deleteLinks(Long dpid, int port) {
+		// TODO Auto-generated method stub
+
+	}
+
+	@Override
+	public void init(String conf) {
+		//TODO extract the DB location from conf
+		Configuration db = new BaseConfiguration();
+		
+		// Local storage gets locked for single process
+		db.setProperty("storage.backend","cassandra");
+		db.setProperty("storage.hostname","127.0.0.1");
+        graph = TitanFactory.open(db);
+        
+        // FIXME: 
+        Set<String> s = graph.getIndexedKeys(Vertex.class);
+        if (!s.contains("dpid")) {
+           graph.createKeyIndex("dpid", Vertex.class);
+           graph.stopTransaction(Conclusion.SUCCESS);
+        }
+        if (!s.contains("type")) {
+        	graph.createKeyIndex("type", Vertex.class);
+        	graph.stopTransaction(Conclusion.SUCCESS);
+        }
+	}
+}