Added functionality to delete links and to add links to remote switches that have a link to a local switch.
diff --git a/src/main/java/net/floodlightcontroller/core/IOFSwitch.java b/src/main/java/net/floodlightcontroller/core/IOFSwitch.java
index d63624c..df609e7 100644
--- a/src/main/java/net/floodlightcontroller/core/IOFSwitch.java
+++ b/src/main/java/net/floodlightcontroller/core/IOFSwitch.java
@@ -338,6 +338,12 @@
Object removeAttribute(String name);
/**
+ * Setup an unconnected switch with the info required.
+ * @param dpid of the switch
+ */
+ public void setupRemoteSwitch(Long dpid);
+
+ /**
* Clear all flowmods on this switch
*/
public void clearAllFlowMods();
diff --git a/src/main/java/net/floodlightcontroller/core/internal/OFSwitchImpl.java b/src/main/java/net/floodlightcontroller/core/internal/OFSwitchImpl.java
index dff00fd..bf5aaf7 100644
--- a/src/main/java/net/floodlightcontroller/core/internal/OFSwitchImpl.java
+++ b/src/main/java/net/floodlightcontroller/core/internal/OFSwitchImpl.java
@@ -268,7 +268,7 @@
public void disconnectOutputStream() {
channel.close();
}
-
+
@Override
@JsonIgnore
public void setFeaturesReply(OFFeaturesReply featuresReply) {
@@ -854,4 +854,11 @@
public byte getTables() {
return tables;
}
+
+
+ @Override
+ public void setupRemoteSwitch(Long dpid) {
+ this.datapathId = dpid;
+ this.stringId = HexString.toHexString(this.datapathId);
+ }
}
diff --git a/src/main/java/net/floodlightcontroller/linkdiscovery/ILinkStorage.java b/src/main/java/net/floodlightcontroller/linkdiscovery/ILinkStorage.java
index 6d66a49..a764227 100644
--- a/src/main/java/net/floodlightcontroller/linkdiscovery/ILinkStorage.java
+++ b/src/main/java/net/floodlightcontroller/linkdiscovery/ILinkStorage.java
@@ -11,26 +11,37 @@
* Link creation
*/
public void update(Link link, DM_OPERATION op);
+ public void update(Link link, LinkInfo linkinfo, DM_OPERATION op);
public void update(List<Link> List, DM_OPERATION op);
-
+
/*
* Add Linkinfo
*/
- public void update(Link link, LinkInfo linkinfo, DM_OPERATION op);
+ public void addOrUpdateLink (Link link, LinkInfo linkinfo, DM_OPERATION op);
/*
- * Get Links from Storage
- * If dpid and port both are specified specific link is retrieved
- * If only dpid is set all links associated with Switch are retrieved
+ * Delete a single link
*/
- public List<Link> getLinks(Long dpid, int port);
+ public void deleteLink(Link link);
/*
* Delete links associated with dpid and port
* If only dpid is used, All links associated for switch are removed
* Useful for port up/down and also switch join/remove events
*/
- public void deleteLinks(Long dpid, int port);
+ public void deleteLinksOnPort(Long dpid, short port);
+
+ /*
+ * Delete a list of links
+ */
+ public void deleteLinks(List<Link> links);
+
+ /*
+ * Get Links from Storage
+ * If dpid and port both are specified specific link is retrieved
+ * If only dpid is set all links associated with Switch are retrieved
+ */
+ public List<Link> getLinks(Long dpid, short port);
/*
* Init with Storage conf
diff --git a/src/main/java/net/floodlightcontroller/linkdiscovery/internal/LinkDiscoveryManager.java b/src/main/java/net/floodlightcontroller/linkdiscovery/internal/LinkDiscoveryManager.java
index 8ad31c2..0247544 100644
--- a/src/main/java/net/floodlightcontroller/linkdiscovery/internal/LinkDiscoveryManager.java
+++ b/src/main/java/net/floodlightcontroller/linkdiscovery/internal/LinkDiscoveryManager.java
@@ -47,10 +47,12 @@
import net.floodlightcontroller.core.IInfoProvider;
import net.floodlightcontroller.core.IOFMessageListener;
import net.floodlightcontroller.core.IOFSwitch;
+import net.floodlightcontroller.core.internal.OFSwitchImpl;
import net.floodlightcontroller.core.IOFSwitchListener;
import net.floodlightcontroller.core.annotations.LogMessageCategory;
import net.floodlightcontroller.core.annotations.LogMessageDoc;
import net.floodlightcontroller.core.annotations.LogMessageDocs;
+//import net.floodlightcontroller.core.internal.SwitchStorageImpl;
import net.floodlightcontroller.core.module.FloodlightModuleContext;
import net.floodlightcontroller.core.module.FloodlightModuleException;
import net.floodlightcontroller.core.module.IFloodlightModule;
@@ -192,6 +194,7 @@
// Storage
protected LinkStorageImpl linkStore;
+ // protected SwitchStorageImpl swStore;
/**
* Flag to indicate if automatic port fast is enabled or not.
@@ -200,6 +203,12 @@
boolean autoPortFastFeature = false;
/**
+ * Map of remote switches that are not connected to this controller. This
+ * is used to learn remote switches in a distributed controller.
+ */
+ protected Map<Long, IOFSwitch> remoteSwitches;
+
+ /**
* Map from link to the most recent time it was verified functioning
*/
protected Map<Link, LinkInfo> links;
@@ -509,6 +518,34 @@
}
/**
+ * Learn remote switches when running as a distributed controller
+ */
+ protected IOFSwitch addRemoteSwitch(long sw, short port) {
+ IOFSwitch remotesw = null;
+
+ // add a switch if we have not seen it before
+ if (!remoteSwitches.containsKey(sw)) {
+ remotesw = new OFSwitchImpl();
+ remotesw.setupRemoteSwitch(sw);
+ remoteSwitches.put(remotesw.getId(), remotesw);
+ log.debug("addRemoteSwitch(): added fake remote sw {}", remotesw);
+ }
+
+ // add the port if we have not seen it before
+ if (remotesw.getPort(port) != null) {
+ OFPhysicalPort remoteport = new OFPhysicalPort();
+ remoteport.setPortNumber(port);
+ remoteport.setName("fake_" + port);
+ remoteport.setConfig(0);
+ remoteport.setState(0);
+ remotesw.setPort(remoteport);
+ log.debug("addRemoteSwitch(): added fake remote port {} to sw {}", remoteport, remotesw);
+ }
+
+ return remotesw;
+ }
+
+ /**
* Send link discovery message out of a given switch port.
* The discovery message may be a standard LLDP or a modified
* LLDP, where the dst mac address is set to :ff.
@@ -769,6 +806,11 @@
lldptlv.getValue()[2] == (byte)0xe1 && lldptlv.getValue()[3] == 0x0) {
ByteBuffer dpidBB = ByteBuffer.wrap(lldptlv.getValue());
remoteSwitch = floodlightProvider.getSwitches().get(dpidBB.getLong(4));
+ if (remoteSwitch == null) {
+ // floodlight LLDP coming from a remote switch connected to a different controller
+ // add it to our cache of unconnected remote switches
+ remoteSwitch = addRemoteSwitch(dpidBB.getLong(4), remotePort);
+ }
} else if (lldptlv.getType() == 12 && lldptlv.getLength() == 8){
otherId = ByteBuffer.wrap(lldptlv.getValue()).getLong();
if (myId == otherId)
@@ -1161,7 +1203,7 @@
// remove link from storage.
removeLinkFromStorage(lt);
- // Write link to network map
+ // remote link from network map
linkStore.update(lt, DM_OPERATION.DELETE);
// TODO Whenever link is removed, it has to checked if
@@ -1211,6 +1253,7 @@
((byte)OFPortReason.OFPPR_MODIFY.ordinal() ==
ps.getReason() && !portEnabled(ps.getDesc()))) {
deleteLinksOnPort(npt, "Port Status Changed");
+ //swStore.deletePort(HexString.toHexString(npt.getNodeId()), npt.getPortId());
LDUpdate update = new LDUpdate(sw, port, UpdateOperation.PORT_DOWN);
updates.add(update);
linkDeleted = true;
@@ -1871,6 +1914,11 @@
this.linkStore = new LinkStorageImpl();
this.linkStore.init("/tmp/cassandra.titan");
+ // Initialieze the switch storage connector to the network map. We may need to delete switches.
+ // TODO find a better place to delete switches and ports from network map
+ // this.swStore = new SwitchStorageImpl();
+ // this.swStore.init("/tmp/cassandra.titan");
+
ScheduledExecutorService ses = threadPool.getScheduledExecutor();
// To be started by the first switch connection
diff --git a/src/main/java/net/floodlightcontroller/linkdiscovery/internal/LinkStorageImpl.java b/src/main/java/net/floodlightcontroller/linkdiscovery/internal/LinkStorageImpl.java
index 16770bd..9c0ee4e 100644
--- a/src/main/java/net/floodlightcontroller/linkdiscovery/internal/LinkStorageImpl.java
+++ b/src/main/java/net/floodlightcontroller/linkdiscovery/internal/LinkStorageImpl.java
@@ -18,126 +18,169 @@
import com.tinkerpop.blueprints.Direction;
import com.tinkerpop.blueprints.TransactionalGraph.Conclusion;
import com.tinkerpop.blueprints.Vertex;
+import com.tinkerpop.blueprints.Edge;
import com.tinkerpop.gremlin.java.GremlinPipeline;
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);
+ 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);
+ update(lt, (LinkInfo)null, 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);
+ addOrUpdateLink(link, linkinfo, op);
break;
case DELETE:
+ deleteLink(link);
break;
}
}
- protected void addLink(Link lt, LinkInfo linkinfo) {
- Vertex vswSrc, vswDst;
+ private Vertex getPortVertex(String dpid, short port) {
+ Vertex vsw, vport = null;
+ if ((vsw = graph.getVertices("dpid", dpid).iterator().next()) != null) {
+ GremlinPipeline<Vertex, Vertex> pipe = new GremlinPipeline<Vertex, Vertex>();
+ pipe.start(vsw).out("on").has("number", port);
+ if (pipe.hasNext()) {
+ vport = pipe.next();
+ }
+ }
+ return vport;
+ }
+
+ public void addOrUpdateLink(Link lt, LinkInfo linkinfo, DM_OPERATION op) {
Vertex vportSrc = null, vportDst = null;
- log.info("addLink(): {} {} getSrc {}", new Object[]{lt, linkinfo, lt.getSrc()});
+ log.debug("addOrUpdateLink(): op {} {} {}", new Object[]{op, lt, linkinfo});
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 exists {} {}", dpid, vswSrc);
- GremlinPipeline<Vertex, Vertex> pipe = new GremlinPipeline<Vertex, Vertex>();
-
- //if (vswSrc.query().direction(Direction.OUT).labels("on").has("number",port).vertices().iterator().hasNext()) {
- pipe.start(vswSrc).out("on").has("number", port);
- //pipe.start(vswSrc).out("on");
- //log.debug("pipe count {}", pipe.count());
- if (pipe.hasNext()) {
- //vportSrc = vswSrc.query().direction(Direction.OUT).labels("on").has("number",port).vertices().iterator().next();
- vportSrc = pipe.next();
- log.debug("addLink(): port found {} {}", port, vportSrc);
- } else {
- log.error("addLink(): sw {} port {} not found", dpid, port);
- }
- }
+ vportSrc = getPortVertex(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 exists {} {}", dpid, vswDst);
- GremlinPipeline<Vertex, Vertex> pipe = new GremlinPipeline<Vertex, Vertex>();
- pipe.start(vswDst).out("on").has("number", port);
- //if (vswDst.query().direction(Direction.OUT).labels("on").has("number",port).vertices().iterator().hasNext()) {
- if (pipe.hasNext()){
- //vportDst = vswDst.query().direction(Direction.OUT).labels("on").has("number",port).vertices().iterator().next();
- vportDst = pipe.next();
- log.debug("addLink(): port found {} {}", port, vportDst);
- } else {
- log.error ("addLink(): sw {} port {} not found", dpid, port);
- }
- }
-
+ vportDst = getPortVertex(dpid, port);
+
if (vportSrc != null && vportDst != null) {
- //TODO: If Edge already exists should we remove and add again?
+
+ // check if the link exists
List<Vertex> currLinks = new ArrayList<Vertex>();
for (Vertex V : vportSrc.query().direction(Direction.OUT).labels("link").vertices()) {
currLinks.add(V);
}
if (currLinks.contains(vportDst)) {
- // if (vportSrc.query().direction(Direction.OUT).labels("link").vertices().iterator().hasNext() &&
- // vportSrc.query().direction(Direction.OUT).labels("link").) {
- //FIXME: Succeed silently for now
- log.debug("addLink(): Failure: link exists {} src {} dst {}", new Object[]{lt, vportSrc, vportDst});
+ // TODO: update linkinfo
+ if (op.equals(DM_OPERATION.INSERT) || op.equals(DM_OPERATION.CREATE)) {
+ log.debug("addOrUpdateLink(): Failure: link exists {} {} src {} dst {}",
+ new Object[]{op, lt, vportSrc, vportDst});
+ }
} else {
graph.addEdge(null, vportSrc, vportDst, "link");
graph.stopTransaction(Conclusion.SUCCESS);
+ log.debug("addOrUpdateLink(): link added {} {} src {} dst {}", new Object[]{op, lt, vportSrc, vportDst});
}
- log.debug("addLink(): link added {} src {} dst {}", new Object[]{lt, vportSrc, vportDst});
} else {
- log.error("addLink(): failed {} src {} dst {}", new Object[]{lt, vportSrc, vportDst});
+ log.error("addOrUpdateLink(): failed {} {} src {} dst {}", new Object[]{op, lt, vportSrc, vportDst});
graph.stopTransaction(Conclusion.FAILURE);
}
} catch (TitanException e) {
/*
* retry till we succeed?
*/
- log.error("addLink(): {} failed", lt);
+ log.error("addOrUpdateLink(): failed {} {}", new Object[]{op, lt});
}
}
@Override
- public List<Link> getLinks(Long dpid, int port) {
- // TODO Auto-generated method stub
- return null;
+ public void deleteLinks(List<Link> links) {
+
+ for (Link lt : links) {
+ deleteLink(lt);
+ }
}
+
@Override
- public void deleteLinks(Long dpid, int port) {
- // TODO Auto-generated method stub
-
+ public void deleteLink(Link lt) {
+ Vertex vportSrc = null, vportDst = null;
+ int count = 0;
+
+ log.debug("deleteLink(): {}", lt);
+
+ try {
+ // get source port vertex
+ String dpid = HexString.toHexString(lt.getSrc());
+ short port = lt.getSrcPort();
+ vportSrc = getPortVertex(dpid, port);
+
+ // get dst port vertex
+ dpid = HexString.toHexString(lt.getDst());
+ port = lt.getDstPort();
+ vportDst = getPortVertex(dpid, port);
+
+ if (vportSrc != null && vportDst != null) {
+ for (Edge e : vportSrc.getEdges(Direction.OUT)) {
+ log.debug("deleteLink(): {} {}", e.getLabel(), e.getVertex(Direction.IN));
+ // if (e.getLabel().equals("link") && e.getVertex(Direction.OUT).equals(vportDst)) {
+ if (e.getLabel().equals("link")) {
+ graph.removeEdge(e);
+ count++;
+ }
+ }
+ graph.stopTransaction(Conclusion.SUCCESS);
+ log.debug("deleteLink(): {} {} src {} dst {}", new Object[]{
+ (count > 0) ? "deleted " + count : "failure", lt, vportSrc, vportDst});
+
+ } else {
+ log.error("deleteLink(): failed src port vertex not found {} src {} dst {}", new Object[]{lt, vportSrc, vportDst});
+ graph.stopTransaction(Conclusion.FAILURE);
+ }
+
+ } catch (TitanException e) {
+ /*
+ * retry till we succeed?
+ */
+ log.error("deleteLink(): {} failed", lt);
+ }
}
+ // TODO: Fix me
+ @Override
+ public List<Link> getLinks(Long dpid, short port) {
+ Vertex vportSrc, vportDst;
+ List<Link> links = null;
+ Link lt;
+
+ vportSrc = getPortVertex(HexString.toHexString(dpid), port);
+ if (vportSrc != null) {
+ for (Edge e : vportSrc.getEdges(Direction.OUT)) {
+ if (e.getLabel().equals("link")) {
+ break;
+ }
+ }
+ }
+ return null;
+ }
+
@Override
public void init(String conf) {
//TODO extract the DB location from conf
@@ -155,4 +198,11 @@
graph.stopTransaction(Conclusion.SUCCESS);
}
}
+
+ @Override
+ public void deleteLinksOnPort(Long dpid, short port) {
+ // TODO Auto-generated method stub
+
+ }
+
}
diff --git a/src/test/java/net/floodlightcontroller/linkdiscovery/internal/LinkStorageImplTest.java b/src/test/java/net/floodlightcontroller/linkdiscovery/internal/LinkStorageImplTest.java
index 1d0bd95..0324a51 100644
--- a/src/test/java/net/floodlightcontroller/linkdiscovery/internal/LinkStorageImplTest.java
+++ b/src/test/java/net/floodlightcontroller/linkdiscovery/internal/LinkStorageImplTest.java
@@ -96,7 +96,7 @@
@Test
public void testGetLinks(){
//TODO Make sure this works when the implementation is written
- List<Link> list = linkStorage.getLinks(Long.decode("0x0000000000000a01"), 2);
+ List<Link> list = linkStorage.getLinks(Long.decode("0x0000000000000a01"), (short)2);
assertEquals(list.size(), 1);
@@ -131,7 +131,7 @@
public void testDeleteLinks(){
//TODO Make sure this works when the implementation is written
- linkStorage.deleteLinks(Long.decode("0x0000000000000a01"), 2);
+ linkStorage.deleteLinksOnPort(Long.decode("0x0000000000000a01"), (short)2);
//Test if it was deleted correctly with the Gremlin API
GremlinPipeline<Vertex, Vertex> pipe = new GremlinPipeline<Vertex, Vertex>();
diff --git a/src/test/java/net/floodlightcontroller/util/OFMessageDamperMockSwitch.java b/src/test/java/net/floodlightcontroller/util/OFMessageDamperMockSwitch.java
index 59e0a51..ffabf6f 100644
--- a/src/test/java/net/floodlightcontroller/util/OFMessageDamperMockSwitch.java
+++ b/src/test/java/net/floodlightcontroller/util/OFMessageDamperMockSwitch.java
@@ -346,4 +346,10 @@
return 0;
}
+ @Override
+ public void setupRemoteSwitch(Long dpid) {
+ // TODO Auto-generated method stub
+
+ }
+
}
\ No newline at end of file