blob: 94e4769cdf8d190b9959be0052eebe9c57e72dd8 [file] [log] [blame]
Pavlin Radoslavov382b22a2013-01-28 09:24:04 -08001package net.floodlightcontroller.routing;
2
3import java.util.ArrayList;
Pavlin Radoslavovd7d8b792013-02-22 10:24:38 -08004import java.util.Collection;
5import java.util.HashMap;
Pavlin Radoslavov382b22a2013-01-28 09:24:04 -08006import java.util.Iterator;
7import java.util.List;
Pavlin Radoslavovd7d8b792013-02-22 10:24:38 -08008import java.util.Map;
Pavlin Radoslavov382b22a2013-01-28 09:24:04 -08009
10import net.floodlightcontroller.core.internal.SwitchStorageImpl;
Pavlin Radoslavovd7d8b792013-02-22 10:24:38 -080011import net.floodlightcontroller.core.module.FloodlightModuleContext;
12import net.floodlightcontroller.core.module.FloodlightModuleException;
13import net.floodlightcontroller.core.module.IFloodlightModule;
14import net.floodlightcontroller.core.module.IFloodlightService;
Pavlin Radoslavov382b22a2013-01-28 09:24:04 -080015import net.floodlightcontroller.core.INetMapTopologyService.ITopoRouteService;
Pavlin Radoslavovf83aa442013-02-26 14:09:01 -080016import net.floodlightcontroller.util.DataPath;
17import net.floodlightcontroller.util.Dpid;
18import net.floodlightcontroller.util.FlowEntry;
19import net.floodlightcontroller.util.Port;
20import net.floodlightcontroller.util.SwitchPort;
Pavlin Radoslavov382b22a2013-01-28 09:24:04 -080021
22import org.openflow.util.HexString;
23
Pavlin Radoslavov382b22a2013-01-28 09:24:04 -080024import com.thinkaurelius.titan.core.TitanGraph;
Pavlin Radoslavov19343432013-03-06 10:43:18 -080025import com.tinkerpop.blueprints.TransactionalGraph.Conclusion;
Pavlin Radoslavov382b22a2013-01-28 09:24:04 -080026import com.tinkerpop.blueprints.Vertex;
Pavlin Radoslavov382b22a2013-01-28 09:24:04 -080027
28import javax.script.ScriptContext;
29import javax.script.ScriptEngine;
30import javax.script.ScriptException;
31import com.tinkerpop.gremlin.groovy.jsr223.GremlinGroovyScriptEngine;
32
Pavlin Radoslavovd7d8b792013-02-22 10:24:38 -080033import org.slf4j.Logger;
34import org.slf4j.LoggerFactory;
35
36public class TopoRouteService implements IFloodlightModule, ITopoRouteService {
37
38 /** The logger. */
Pavlin Radoslavov19343432013-03-06 10:43:18 -080039 private static Logger log =
Pavlin Radoslavovd7d8b792013-02-22 10:24:38 -080040 LoggerFactory.getLogger(TopoRouteService.class);
41
42 @Override
43 public Collection<Class<? extends IFloodlightService>> getModuleServices() {
44 Collection<Class<? extends IFloodlightService>> l =
45 new ArrayList<Class<? extends IFloodlightService>>();
46 l.add(ITopoRouteService.class);
47 return l;
48 }
49
50 @Override
51 public Map<Class<? extends IFloodlightService>, IFloodlightService>
52 getServiceImpls() {
53 Map<Class<? extends IFloodlightService>,
54 IFloodlightService> m =
55 new HashMap<Class<? extends IFloodlightService>,
56 IFloodlightService>();
57 m.put(ITopoRouteService.class, this);
58 return m;
59 }
60
61 @Override
62 public Collection<Class<? extends IFloodlightService>>
63 getModuleDependencies() {
64 Collection<Class<? extends IFloodlightService>> l =
65 new ArrayList<Class<? extends IFloodlightService>>();
66 // TODO: Add the appropriate dependencies
67 // l.add(IRestApiService.class);
68 return l;
69 }
70
71 @Override
72 public void init(FloodlightModuleContext context)
73 throws FloodlightModuleException {
74 // TODO: Add the appropriate initialization
75 }
76
77 @Override
78 public void startUp(FloodlightModuleContext context) {
79 // TODO: Add the approprate setup
80 }
Pavlin Radoslavov382b22a2013-01-28 09:24:04 -080081
Pavlin Radoslavovf34c2902013-02-22 10:33:34 -080082 ThreadLocal<SwitchStorageImpl> store = new ThreadLocal<SwitchStorageImpl>() {
Pavlin Radoslavov382b22a2013-01-28 09:24:04 -080083 @Override
Pavlin Radoslavovf34c2902013-02-22 10:33:34 -080084 protected SwitchStorageImpl initialValue() {
85 SwitchStorageImpl swStore = new SwitchStorageImpl();
86 // NOTE: This is the file path from global properties
87 swStore.init("/tmp/cassandra.titan");
88 return swStore;
89 }
90 };
Pavlin Radoslavov382b22a2013-01-28 09:24:04 -080091
Pavlin Radoslavovf34c2902013-02-22 10:33:34 -080092 SwitchStorageImpl swStore = store.get();
Pavlin Radoslavov382b22a2013-01-28 09:24:04 -080093
Pavlin Radoslavovf34c2902013-02-22 10:33:34 -080094 @Override
Pavlin Radoslavovf83aa442013-02-26 14:09:01 -080095 public DataPath getShortestPath(SwitchPort src, SwitchPort dest) {
96 DataPath result_data_path = new DataPath();
97
98 // Initialize the source and destination in the data path to return
99 result_data_path.setSrcPort(src);
100 result_data_path.setDstPort(dest);
Pavlin Radoslavov382b22a2013-01-28 09:24:04 -0800101
Pavlin Radoslavovf34c2902013-02-22 10:33:34 -0800102 TitanGraph titanGraph = swStore.graph;
Pavlin Radoslavov382b22a2013-01-28 09:24:04 -0800103
Pavlin Radoslavovf83aa442013-02-26 14:09:01 -0800104 String dpid_src = src.dpid().toString();
105 String dpid_dest = dest.dpid().toString();
Pavlin Radoslavov382b22a2013-01-28 09:24:04 -0800106
Pavlin Radoslavovf34c2902013-02-22 10:33:34 -0800107 //
108 // Implement the Shortest Path between two vertices by using
109 // the following Gremlin CLI code:
110 // v_src.as("x").out("on").out("link").in("on").dedup().loop("x"){it.object.dpid != v_dest.dpid}.path(){it.dpid}{it.number}{it.number}
111 // The equivalent code used here is:
112 // results = []; v_src.as("x").out("on").out("link").in("on").dedup().loop("x"){it.object.dpid != v_dest.dpid}.path().fill(results)
113 //
Pavlin Radoslavov382b22a2013-01-28 09:24:04 -0800114
Pavlin Radoslavovf34c2902013-02-22 10:33:34 -0800115 String gremlin = "v_src.as(\"x\").out(\"on\").out(\"link\").in(\"on\").dedup().loop(\"x\"){it.object.dpid != v_dest.dpid}.path().fill(results)";
Pavlin Radoslavov2f686c52013-02-13 11:27:13 -0800116
Pavlin Radoslavovf34c2902013-02-22 10:33:34 -0800117 // Get the source vertex
118 Iterator<Vertex> iter = titanGraph.getVertices("dpid", dpid_src).iterator();
Pavlin Radoslavov19343432013-03-06 10:43:18 -0800119 if (! iter.hasNext()) {
120 // titanGraph.stopTransaction(Conclusion.SUCCESS);
Pavlin Radoslavovf34c2902013-02-22 10:33:34 -0800121 return null; // Source vertex not found
Pavlin Radoslavov19343432013-03-06 10:43:18 -0800122 }
Pavlin Radoslavovf34c2902013-02-22 10:33:34 -0800123 Vertex v_src = iter.next();
Pavlin Radoslavov2f686c52013-02-13 11:27:13 -0800124
Pavlin Radoslavovf34c2902013-02-22 10:33:34 -0800125 // Get the destination vertex
126 iter = titanGraph.getVertices("dpid", dpid_dest).iterator();
Pavlin Radoslavov19343432013-03-06 10:43:18 -0800127 if (! iter.hasNext()) {
128 // titanGraph.stopTransaction(Conclusion.SUCCESS);
Pavlin Radoslavovf34c2902013-02-22 10:33:34 -0800129 return null; // Destination vertex not found
Pavlin Radoslavov19343432013-03-06 10:43:18 -0800130 }
Pavlin Radoslavovf34c2902013-02-22 10:33:34 -0800131 Vertex v_dest = iter.next();
Pavlin Radoslavov382b22a2013-01-28 09:24:04 -0800132
Pavlin Radoslavovf34c2902013-02-22 10:33:34 -0800133 //
134 // Test whether we are computing a path from/to the same DPID.
Pavlin Radoslavovf83aa442013-02-26 14:09:01 -0800135 // If "yes", then just add a single flow entry in the return result.
Pavlin Radoslavovf34c2902013-02-22 10:33:34 -0800136 // NOTE: The return value will change in the future to return
137 // a single hop/entry instead of two. Currently, we need
138 // both entries to capture the source and destination ports.
139 //
140 if (dpid_src.equals(dpid_dest)) {
Pavlin Radoslavovf83aa442013-02-26 14:09:01 -0800141 FlowEntry flowEntry = new FlowEntry();
142 flowEntry.setDpid(src.dpid());
143 flowEntry.setInPort(src.port());
144 flowEntry.setOutPort(dest.port());
145 result_data_path.flowEntries().add(flowEntry);
Pavlin Radoslavov19343432013-03-06 10:43:18 -0800146 // titanGraph.stopTransaction(Conclusion.SUCCESS);
Pavlin Radoslavovf83aa442013-02-26 14:09:01 -0800147 return result_data_path;
Pavlin Radoslavovf34c2902013-02-22 10:33:34 -0800148 }
Pavlin Radoslavov382b22a2013-01-28 09:24:04 -0800149
Pavlin Radoslavovf34c2902013-02-22 10:33:34 -0800150 //
151 // Implement the Gremlin script and run it
152 //
153 ScriptEngine engine = new GremlinGroovyScriptEngine();
Pavlin Radoslavov382b22a2013-01-28 09:24:04 -0800154
Pavlin Radoslavovf34c2902013-02-22 10:33:34 -0800155 ArrayList<ArrayList<Vertex>> results = new ArrayList<ArrayList<Vertex>>();
156 engine.getBindings(ScriptContext.ENGINE_SCOPE).put("g", titanGraph);
157 engine.getBindings(ScriptContext.ENGINE_SCOPE).put("v_src", v_src);
158 engine.getBindings(ScriptContext.ENGINE_SCOPE).put("v_dest", v_dest);
159 engine.getBindings(ScriptContext.ENGINE_SCOPE).put("results", results);
Pavlin Radoslavov382b22a2013-01-28 09:24:04 -0800160
Pavlin Radoslavovf34c2902013-02-22 10:33:34 -0800161 try {
162 engine.eval(gremlin);
163 } catch (ScriptException e) {
164 System.err.println("Caught ScriptException running Gremlin script: " + e.getMessage());
Pavlin Radoslavov19343432013-03-06 10:43:18 -0800165 // titanGraph.stopTransaction(Conclusion.SUCCESS);
Pavlin Radoslavov382b22a2013-01-28 09:24:04 -0800166 return null;
167 }
168
Pavlin Radoslavovf34c2902013-02-22 10:33:34 -0800169 //
Pavlin Radoslavovf83aa442013-02-26 14:09:01 -0800170 // Loop through the result and collect the list
Pavlin Radoslavovf34c2902013-02-22 10:33:34 -0800171 // of <dpid, port> tuples.
172 //
173 long nodeId = 0;
174 short portId = 0;
Pavlin Radoslavovf83aa442013-02-26 14:09:01 -0800175 Port inPort = new Port(src.port().value());
176 Port outPort = new Port();
Pavlin Radoslavovf34c2902013-02-22 10:33:34 -0800177 for (ArrayList<Vertex> lv : results) {
178 int idx = 0;
179 for (Vertex v: lv) {
180 String type = v.getProperty("type").toString();
181 System.out.println("type: " + type);
182 if (type.equals("port")) {
183 String number = v.getProperty("number").toString();
184 System.out.println("number: " + number);
185
186 Object obj = v.getProperty("number");
187 // String class_str = obj.getClass().toString();
188 if (obj instanceof Short) {
189 portId = (Short)obj;
190 } else if (obj instanceof Integer) {
191 Integer int_nodeId = (Integer)obj;
192 portId = int_nodeId.shortValue();
193 // int int_nodeId = (Integer)obj;
194 // portId = (short)int_nodeId.;
195 }
196 } else if (type.equals("switch")) {
197 String dpid = v.getProperty("dpid").toString();
198 nodeId = HexString.toLong(dpid);
199
200 System.out.println("dpid: " + dpid);
201 }
Pavlin Radoslavovf83aa442013-02-26 14:09:01 -0800202 idx++;
203 if (idx == 1) {
Pavlin Radoslavovf34c2902013-02-22 10:33:34 -0800204 continue;
205 }
Pavlin Radoslavovf83aa442013-02-26 14:09:01 -0800206 int mod = idx % 3;
207 if (mod == 0) {
208 // Setup the incoming port
209 inPort = new Port(portId);
210 continue;
Pavlin Radoslavovf34c2902013-02-22 10:33:34 -0800211 }
Pavlin Radoslavovf83aa442013-02-26 14:09:01 -0800212 if (mod == 2) {
213 // Setup the outgoing port, and add the Flow Entry
214 outPort = new Port(portId);
215
216 FlowEntry flowEntry = new FlowEntry();
217 flowEntry.setDpid(new Dpid(nodeId));
218 flowEntry.setInPort(inPort);
219 flowEntry.setOutPort(outPort);
220 result_data_path.flowEntries().add(flowEntry);
221 continue;
222 }
223 }
224
225 if (idx > 0) {
226 // Add the last Flow Entry
227 FlowEntry flowEntry = new FlowEntry();
228 flowEntry.setDpid(new Dpid(nodeId));
229 flowEntry.setInPort(inPort);
230 flowEntry.setOutPort(dest.port());
231 result_data_path.flowEntries().add(flowEntry);
Pavlin Radoslavovf34c2902013-02-22 10:33:34 -0800232 }
Pavlin Radoslavov382b22a2013-01-28 09:24:04 -0800233 }
Pavlin Radoslavov19343432013-03-06 10:43:18 -0800234 // titanGraph.stopTransaction(Conclusion.SUCCESS);
Pavlin Radoslavovf83aa442013-02-26 14:09:01 -0800235 if (result_data_path.flowEntries().size() > 0)
236 return result_data_path;
Pavlin Radoslavovf34c2902013-02-22 10:33:34 -0800237
238 return null;
239 }
240
241 @Override
Pavlin Radoslavovf83aa442013-02-26 14:09:01 -0800242 public Boolean routeExists(SwitchPort src, SwitchPort dest) {
243 DataPath dataPath = getShortestPath(src, dest);
244 if (dataPath != null)
Pavlin Radoslavovf34c2902013-02-22 10:33:34 -0800245 return true;
246 return false;
247 }
Pavlin Radoslavov382b22a2013-01-28 09:24:04 -0800248}