blob: f979cc7ff6147a4aa15ad0bd45191b7e703aca1e [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 Radoslavov382b22a2013-01-28 09:24:04 -080025import com.tinkerpop.blueprints.Vertex;
Pavlin Radoslavov382b22a2013-01-28 09:24:04 -080026
27import javax.script.ScriptContext;
28import javax.script.ScriptEngine;
29import javax.script.ScriptException;
30import com.tinkerpop.gremlin.groovy.jsr223.GremlinGroovyScriptEngine;
31
Pavlin Radoslavovd7d8b792013-02-22 10:24:38 -080032import org.slf4j.Logger;
33import org.slf4j.LoggerFactory;
34
35public class TopoRouteService implements IFloodlightModule, ITopoRouteService {
36
37 /** The logger. */
38 private static Logger logger =
39 LoggerFactory.getLogger(TopoRouteService.class);
40
41 @Override
42 public Collection<Class<? extends IFloodlightService>> getModuleServices() {
43 Collection<Class<? extends IFloodlightService>> l =
44 new ArrayList<Class<? extends IFloodlightService>>();
45 l.add(ITopoRouteService.class);
46 return l;
47 }
48
49 @Override
50 public Map<Class<? extends IFloodlightService>, IFloodlightService>
51 getServiceImpls() {
52 Map<Class<? extends IFloodlightService>,
53 IFloodlightService> m =
54 new HashMap<Class<? extends IFloodlightService>,
55 IFloodlightService>();
56 m.put(ITopoRouteService.class, this);
57 return m;
58 }
59
60 @Override
61 public Collection<Class<? extends IFloodlightService>>
62 getModuleDependencies() {
63 Collection<Class<? extends IFloodlightService>> l =
64 new ArrayList<Class<? extends IFloodlightService>>();
65 // TODO: Add the appropriate dependencies
66 // l.add(IRestApiService.class);
67 return l;
68 }
69
70 @Override
71 public void init(FloodlightModuleContext context)
72 throws FloodlightModuleException {
73 // TODO: Add the appropriate initialization
74 }
75
76 @Override
77 public void startUp(FloodlightModuleContext context) {
78 // TODO: Add the approprate setup
79 }
Pavlin Radoslavov382b22a2013-01-28 09:24:04 -080080
Pavlin Radoslavovf34c2902013-02-22 10:33:34 -080081 ThreadLocal<SwitchStorageImpl> store = new ThreadLocal<SwitchStorageImpl>() {
Pavlin Radoslavov382b22a2013-01-28 09:24:04 -080082 @Override
Pavlin Radoslavovf34c2902013-02-22 10:33:34 -080083 protected SwitchStorageImpl initialValue() {
84 SwitchStorageImpl swStore = new SwitchStorageImpl();
85 // NOTE: This is the file path from global properties
86 swStore.init("/tmp/cassandra.titan");
87 return swStore;
88 }
89 };
Pavlin Radoslavov382b22a2013-01-28 09:24:04 -080090
Pavlin Radoslavovf34c2902013-02-22 10:33:34 -080091 SwitchStorageImpl swStore = store.get();
Pavlin Radoslavov382b22a2013-01-28 09:24:04 -080092
Pavlin Radoslavovf34c2902013-02-22 10:33:34 -080093 @Override
Pavlin Radoslavovf83aa442013-02-26 14:09:01 -080094 public DataPath getShortestPath(SwitchPort src, SwitchPort dest) {
95 DataPath result_data_path = new DataPath();
96
97 // Initialize the source and destination in the data path to return
98 result_data_path.setSrcPort(src);
99 result_data_path.setDstPort(dest);
Pavlin Radoslavov382b22a2013-01-28 09:24:04 -0800100
Pavlin Radoslavovf34c2902013-02-22 10:33:34 -0800101 TitanGraph titanGraph = swStore.graph;
Pavlin Radoslavov382b22a2013-01-28 09:24:04 -0800102
Pavlin Radoslavovf83aa442013-02-26 14:09:01 -0800103 String dpid_src = src.dpid().toString();
104 String dpid_dest = dest.dpid().toString();
Pavlin Radoslavov382b22a2013-01-28 09:24:04 -0800105
Pavlin Radoslavovf34c2902013-02-22 10:33:34 -0800106 //
107 // Implement the Shortest Path between two vertices by using
108 // the following Gremlin CLI code:
109 // 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}
110 // The equivalent code used here is:
111 // results = []; v_src.as("x").out("on").out("link").in("on").dedup().loop("x"){it.object.dpid != v_dest.dpid}.path().fill(results)
112 //
Pavlin Radoslavov382b22a2013-01-28 09:24:04 -0800113
Pavlin Radoslavovf34c2902013-02-22 10:33:34 -0800114 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 -0800115
Pavlin Radoslavovf34c2902013-02-22 10:33:34 -0800116 // Get the source vertex
117 Iterator<Vertex> iter = titanGraph.getVertices("dpid", dpid_src).iterator();
118 if (! iter.hasNext())
119 return null; // Source vertex not found
120 Vertex v_src = iter.next();
Pavlin Radoslavov2f686c52013-02-13 11:27:13 -0800121
Pavlin Radoslavovf34c2902013-02-22 10:33:34 -0800122 // Get the destination vertex
123 iter = titanGraph.getVertices("dpid", dpid_dest).iterator();
124 if (! iter.hasNext())
125 return null; // Destination vertex not found
126 Vertex v_dest = iter.next();
Pavlin Radoslavov382b22a2013-01-28 09:24:04 -0800127
Pavlin Radoslavovf34c2902013-02-22 10:33:34 -0800128 //
129 // Test whether we are computing a path from/to the same DPID.
Pavlin Radoslavovf83aa442013-02-26 14:09:01 -0800130 // If "yes", then just add a single flow entry in the return result.
Pavlin Radoslavovf34c2902013-02-22 10:33:34 -0800131 // NOTE: The return value will change in the future to return
132 // a single hop/entry instead of two. Currently, we need
133 // both entries to capture the source and destination ports.
134 //
135 if (dpid_src.equals(dpid_dest)) {
Pavlin Radoslavovf83aa442013-02-26 14:09:01 -0800136 FlowEntry flowEntry = new FlowEntry();
137 flowEntry.setDpid(src.dpid());
138 flowEntry.setInPort(src.port());
139 flowEntry.setOutPort(dest.port());
140 result_data_path.flowEntries().add(flowEntry);
141 return result_data_path;
Pavlin Radoslavovf34c2902013-02-22 10:33:34 -0800142 }
Pavlin Radoslavov382b22a2013-01-28 09:24:04 -0800143
Pavlin Radoslavovf34c2902013-02-22 10:33:34 -0800144 //
145 // Implement the Gremlin script and run it
146 //
147 ScriptEngine engine = new GremlinGroovyScriptEngine();
Pavlin Radoslavov382b22a2013-01-28 09:24:04 -0800148
Pavlin Radoslavovf34c2902013-02-22 10:33:34 -0800149 ArrayList<ArrayList<Vertex>> results = new ArrayList<ArrayList<Vertex>>();
150 engine.getBindings(ScriptContext.ENGINE_SCOPE).put("g", titanGraph);
151 engine.getBindings(ScriptContext.ENGINE_SCOPE).put("v_src", v_src);
152 engine.getBindings(ScriptContext.ENGINE_SCOPE).put("v_dest", v_dest);
153 engine.getBindings(ScriptContext.ENGINE_SCOPE).put("results", results);
Pavlin Radoslavov382b22a2013-01-28 09:24:04 -0800154
Pavlin Radoslavovf34c2902013-02-22 10:33:34 -0800155 try {
156 engine.eval(gremlin);
157 } catch (ScriptException e) {
158 System.err.println("Caught ScriptException running Gremlin script: " + e.getMessage());
Pavlin Radoslavov382b22a2013-01-28 09:24:04 -0800159 return null;
160 }
161
Pavlin Radoslavovf34c2902013-02-22 10:33:34 -0800162 //
Pavlin Radoslavovf83aa442013-02-26 14:09:01 -0800163 // Loop through the result and collect the list
Pavlin Radoslavovf34c2902013-02-22 10:33:34 -0800164 // of <dpid, port> tuples.
165 //
166 long nodeId = 0;
167 short portId = 0;
Pavlin Radoslavovf83aa442013-02-26 14:09:01 -0800168 Port inPort = new Port(src.port().value());
169 Port outPort = new Port();
Pavlin Radoslavovf34c2902013-02-22 10:33:34 -0800170 for (ArrayList<Vertex> lv : results) {
171 int idx = 0;
172 for (Vertex v: lv) {
173 String type = v.getProperty("type").toString();
174 System.out.println("type: " + type);
175 if (type.equals("port")) {
176 String number = v.getProperty("number").toString();
177 System.out.println("number: " + number);
178
179 Object obj = v.getProperty("number");
180 // String class_str = obj.getClass().toString();
181 if (obj instanceof Short) {
182 portId = (Short)obj;
183 } else if (obj instanceof Integer) {
184 Integer int_nodeId = (Integer)obj;
185 portId = int_nodeId.shortValue();
186 // int int_nodeId = (Integer)obj;
187 // portId = (short)int_nodeId.;
188 }
189 } else if (type.equals("switch")) {
190 String dpid = v.getProperty("dpid").toString();
191 nodeId = HexString.toLong(dpid);
192
193 System.out.println("dpid: " + dpid);
194 }
Pavlin Radoslavovf83aa442013-02-26 14:09:01 -0800195 idx++;
196 if (idx == 1) {
Pavlin Radoslavovf34c2902013-02-22 10:33:34 -0800197 continue;
198 }
Pavlin Radoslavovf83aa442013-02-26 14:09:01 -0800199 int mod = idx % 3;
200 if (mod == 0) {
201 // Setup the incoming port
202 inPort = new Port(portId);
203 continue;
Pavlin Radoslavovf34c2902013-02-22 10:33:34 -0800204 }
Pavlin Radoslavovf83aa442013-02-26 14:09:01 -0800205 if (mod == 2) {
206 // Setup the outgoing port, and add the Flow Entry
207 outPort = new Port(portId);
208
209 FlowEntry flowEntry = new FlowEntry();
210 flowEntry.setDpid(new Dpid(nodeId));
211 flowEntry.setInPort(inPort);
212 flowEntry.setOutPort(outPort);
213 result_data_path.flowEntries().add(flowEntry);
214 continue;
215 }
216 }
217
218 if (idx > 0) {
219 // Add the last Flow Entry
220 FlowEntry flowEntry = new FlowEntry();
221 flowEntry.setDpid(new Dpid(nodeId));
222 flowEntry.setInPort(inPort);
223 flowEntry.setOutPort(dest.port());
224 result_data_path.flowEntries().add(flowEntry);
Pavlin Radoslavovf34c2902013-02-22 10:33:34 -0800225 }
Pavlin Radoslavov382b22a2013-01-28 09:24:04 -0800226 }
Pavlin Radoslavovf83aa442013-02-26 14:09:01 -0800227 if (result_data_path.flowEntries().size() > 0)
228 return result_data_path;
Pavlin Radoslavovf34c2902013-02-22 10:33:34 -0800229
230 return null;
231 }
232
233 @Override
Pavlin Radoslavovf83aa442013-02-26 14:09:01 -0800234 public Boolean routeExists(SwitchPort src, SwitchPort dest) {
235 DataPath dataPath = getShortestPath(src, dest);
236 if (dataPath != null)
Pavlin Radoslavovf34c2902013-02-22 10:33:34 -0800237 return true;
238 return false;
239 }
Pavlin Radoslavov382b22a2013-01-28 09:24:04 -0800240}