blob: 1f212212b19d155a0c27693d42ee618de21da9dc [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 Radoslavovbfae5e02013-03-19 23:06:36 -070027import com.tinkerpop.gremlin.java.GremlinPipeline;
28import com.tinkerpop.pipes.PipeFunction;
29import com.tinkerpop.pipes.branch.LoopPipe.LoopBundle;
Pavlin Radoslavov382b22a2013-01-28 09:24:04 -080030
31import javax.script.ScriptContext;
32import javax.script.ScriptEngine;
33import javax.script.ScriptException;
34import com.tinkerpop.gremlin.groovy.jsr223.GremlinGroovyScriptEngine;
35
Pavlin Radoslavovd7d8b792013-02-22 10:24:38 -080036import org.slf4j.Logger;
37import org.slf4j.LoggerFactory;
38
39public class TopoRouteService implements IFloodlightModule, ITopoRouteService {
40
41 /** The logger. */
Pavlin Radoslavov19343432013-03-06 10:43:18 -080042 private static Logger log =
Pavlin Radoslavovd7d8b792013-02-22 10:24:38 -080043 LoggerFactory.getLogger(TopoRouteService.class);
44
45 @Override
46 public Collection<Class<? extends IFloodlightService>> getModuleServices() {
47 Collection<Class<? extends IFloodlightService>> l =
48 new ArrayList<Class<? extends IFloodlightService>>();
49 l.add(ITopoRouteService.class);
50 return l;
51 }
52
53 @Override
54 public Map<Class<? extends IFloodlightService>, IFloodlightService>
55 getServiceImpls() {
56 Map<Class<? extends IFloodlightService>,
57 IFloodlightService> m =
58 new HashMap<Class<? extends IFloodlightService>,
59 IFloodlightService>();
60 m.put(ITopoRouteService.class, this);
61 return m;
62 }
63
64 @Override
65 public Collection<Class<? extends IFloodlightService>>
66 getModuleDependencies() {
67 Collection<Class<? extends IFloodlightService>> l =
68 new ArrayList<Class<? extends IFloodlightService>>();
69 // TODO: Add the appropriate dependencies
70 // l.add(IRestApiService.class);
71 return l;
72 }
73
74 @Override
75 public void init(FloodlightModuleContext context)
76 throws FloodlightModuleException {
77 // TODO: Add the appropriate initialization
78 }
79
80 @Override
81 public void startUp(FloodlightModuleContext context) {
82 // TODO: Add the approprate setup
83 }
Pavlin Radoslavov382b22a2013-01-28 09:24:04 -080084
Pavlin Radoslavovf34c2902013-02-22 10:33:34 -080085 ThreadLocal<SwitchStorageImpl> store = new ThreadLocal<SwitchStorageImpl>() {
Pavlin Radoslavov382b22a2013-01-28 09:24:04 -080086 @Override
Pavlin Radoslavovf34c2902013-02-22 10:33:34 -080087 protected SwitchStorageImpl initialValue() {
88 SwitchStorageImpl swStore = new SwitchStorageImpl();
89 // NOTE: This is the file path from global properties
90 swStore.init("/tmp/cassandra.titan");
91 return swStore;
92 }
93 };
Pavlin Radoslavov382b22a2013-01-28 09:24:04 -080094
Pavlin Radoslavovf34c2902013-02-22 10:33:34 -080095 SwitchStorageImpl swStore = store.get();
Pavlin Radoslavov382b22a2013-01-28 09:24:04 -080096
Pavlin Radoslavovbfae5e02013-03-19 23:06:36 -070097 static class ShortestPathLoopFunction implements PipeFunction<LoopBundle<Vertex>, Boolean> {
98 String dpid;
99 public ShortestPathLoopFunction(String dpid) {
100 super();
101 this.dpid = dpid;
102 }
103 public Boolean compute(LoopBundle<Vertex> bundle) {
104 Boolean output = false;
105 if (! bundle.getObject().getProperty("dpid").equals(dpid)) {
106 output = true;
107 }
108 return output;
109 }
110 }
111
Pavlin Radoslavovf34c2902013-02-22 10:33:34 -0800112 @Override
Pavlin Radoslavovf83aa442013-02-26 14:09:01 -0800113 public DataPath getShortestPath(SwitchPort src, SwitchPort dest) {
114 DataPath result_data_path = new DataPath();
115
116 // Initialize the source and destination in the data path to return
117 result_data_path.setSrcPort(src);
118 result_data_path.setDstPort(dest);
Pavlin Radoslavov382b22a2013-01-28 09:24:04 -0800119
Pavlin Radoslavovf34c2902013-02-22 10:33:34 -0800120 TitanGraph titanGraph = swStore.graph;
Pavlin Radoslavov382b22a2013-01-28 09:24:04 -0800121
Pavlin Radoslavovf83aa442013-02-26 14:09:01 -0800122 String dpid_src = src.dpid().toString();
123 String dpid_dest = dest.dpid().toString();
Pavlin Radoslavov382b22a2013-01-28 09:24:04 -0800124
Pavlin Radoslavovf34c2902013-02-22 10:33:34 -0800125 //
126 // Implement the Shortest Path between two vertices by using
127 // the following Gremlin CLI code:
128 // 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}
129 // The equivalent code used here is:
130 // results = []; v_src.as("x").out("on").out("link").in("on").dedup().loop("x"){it.object.dpid != v_dest.dpid}.path().fill(results)
131 //
Pavlin Radoslavov382b22a2013-01-28 09:24:04 -0800132
Pavlin Radoslavovf34c2902013-02-22 10:33:34 -0800133 // Get the source vertex
134 Iterator<Vertex> iter = titanGraph.getVertices("dpid", dpid_src).iterator();
Pavlin Radoslavov19343432013-03-06 10:43:18 -0800135 if (! iter.hasNext()) {
136 // titanGraph.stopTransaction(Conclusion.SUCCESS);
Pavlin Radoslavovf34c2902013-02-22 10:33:34 -0800137 return null; // Source vertex not found
Pavlin Radoslavov19343432013-03-06 10:43:18 -0800138 }
Pavlin Radoslavovf34c2902013-02-22 10:33:34 -0800139 Vertex v_src = iter.next();
Pavlin Radoslavov2f686c52013-02-13 11:27:13 -0800140
Pavlin Radoslavovf34c2902013-02-22 10:33:34 -0800141 // Get the destination vertex
142 iter = titanGraph.getVertices("dpid", dpid_dest).iterator();
Pavlin Radoslavov19343432013-03-06 10:43:18 -0800143 if (! iter.hasNext()) {
144 // titanGraph.stopTransaction(Conclusion.SUCCESS);
Pavlin Radoslavovf34c2902013-02-22 10:33:34 -0800145 return null; // Destination vertex not found
Pavlin Radoslavov19343432013-03-06 10:43:18 -0800146 }
Pavlin Radoslavovf34c2902013-02-22 10:33:34 -0800147 Vertex v_dest = iter.next();
Pavlin Radoslavov382b22a2013-01-28 09:24:04 -0800148
Pavlin Radoslavovf34c2902013-02-22 10:33:34 -0800149 //
150 // Test whether we are computing a path from/to the same DPID.
Pavlin Radoslavovf83aa442013-02-26 14:09:01 -0800151 // If "yes", then just add a single flow entry in the return result.
Pavlin Radoslavovf34c2902013-02-22 10:33:34 -0800152 // NOTE: The return value will change in the future to return
153 // a single hop/entry instead of two. Currently, we need
154 // both entries to capture the source and destination ports.
155 //
156 if (dpid_src.equals(dpid_dest)) {
Pavlin Radoslavovf83aa442013-02-26 14:09:01 -0800157 FlowEntry flowEntry = new FlowEntry();
158 flowEntry.setDpid(src.dpid());
159 flowEntry.setInPort(src.port());
160 flowEntry.setOutPort(dest.port());
161 result_data_path.flowEntries().add(flowEntry);
Pavlin Radoslavov19343432013-03-06 10:43:18 -0800162 // titanGraph.stopTransaction(Conclusion.SUCCESS);
Pavlin Radoslavovf83aa442013-02-26 14:09:01 -0800163 return result_data_path;
Pavlin Radoslavovf34c2902013-02-22 10:33:34 -0800164 }
Pavlin Radoslavov382b22a2013-01-28 09:24:04 -0800165
Pavlin Radoslavovbfae5e02013-03-19 23:06:36 -0700166 ShortestPathLoopFunction whileFunction = new ShortestPathLoopFunction(dpid_dest);
167 GremlinPipeline<Vertex, Vertex> pipe = new GremlinPipeline<Vertex, Vertex>();
168 Collection<List> results = new ArrayList<List>();
169 GremlinPipeline<Vertex, List> path;
170 path = pipe.start(v_src).as("x").out("on").out("link").in("on").dedup().loop("x", whileFunction).path();
171 path.fill(results);
Pavlin Radoslavov382b22a2013-01-28 09:24:04 -0800172
Pavlin Radoslavovf34c2902013-02-22 10:33:34 -0800173 //
Pavlin Radoslavovf83aa442013-02-26 14:09:01 -0800174 // Loop through the result and collect the list
Pavlin Radoslavovf34c2902013-02-22 10:33:34 -0800175 // of <dpid, port> tuples.
176 //
177 long nodeId = 0;
178 short portId = 0;
Pavlin Radoslavovf83aa442013-02-26 14:09:01 -0800179 Port inPort = new Port(src.port().value());
180 Port outPort = new Port();
Pavlin Radoslavovbfae5e02013-03-19 23:06:36 -0700181 for (List l : results) {
Pavlin Radoslavovf34c2902013-02-22 10:33:34 -0800182 int idx = 0;
Pavlin Radoslavovbfae5e02013-03-19 23:06:36 -0700183 for (Object o: l) {
184 Vertex v = (Vertex)(o);
Pavlin Radoslavovf34c2902013-02-22 10:33:34 -0800185 String type = v.getProperty("type").toString();
Pavlin Radoslavovbfae5e02013-03-19 23:06:36 -0700186 // System.out.println("type: " + type);
Pavlin Radoslavovf34c2902013-02-22 10:33:34 -0800187 if (type.equals("port")) {
188 String number = v.getProperty("number").toString();
Pavlin Radoslavovbfae5e02013-03-19 23:06:36 -0700189 // System.out.println("number: " + number);
Pavlin Radoslavovf34c2902013-02-22 10:33:34 -0800190
191 Object obj = v.getProperty("number");
192 // String class_str = obj.getClass().toString();
193 if (obj instanceof Short) {
194 portId = (Short)obj;
195 } else if (obj instanceof Integer) {
196 Integer int_nodeId = (Integer)obj;
197 portId = int_nodeId.shortValue();
198 // int int_nodeId = (Integer)obj;
199 // portId = (short)int_nodeId.;
200 }
201 } else if (type.equals("switch")) {
202 String dpid = v.getProperty("dpid").toString();
203 nodeId = HexString.toLong(dpid);
204
Pavlin Radoslavovbfae5e02013-03-19 23:06:36 -0700205 // System.out.println("dpid: " + dpid);
Pavlin Radoslavovf34c2902013-02-22 10:33:34 -0800206 }
Pavlin Radoslavovf83aa442013-02-26 14:09:01 -0800207 idx++;
208 if (idx == 1) {
Pavlin Radoslavovf34c2902013-02-22 10:33:34 -0800209 continue;
210 }
Pavlin Radoslavovf83aa442013-02-26 14:09:01 -0800211 int mod = idx % 3;
212 if (mod == 0) {
213 // Setup the incoming port
214 inPort = new Port(portId);
215 continue;
Pavlin Radoslavovf34c2902013-02-22 10:33:34 -0800216 }
Pavlin Radoslavovf83aa442013-02-26 14:09:01 -0800217 if (mod == 2) {
218 // Setup the outgoing port, and add the Flow Entry
219 outPort = new Port(portId);
220
221 FlowEntry flowEntry = new FlowEntry();
222 flowEntry.setDpid(new Dpid(nodeId));
223 flowEntry.setInPort(inPort);
224 flowEntry.setOutPort(outPort);
225 result_data_path.flowEntries().add(flowEntry);
226 continue;
227 }
228 }
229
230 if (idx > 0) {
231 // Add the last Flow Entry
232 FlowEntry flowEntry = new FlowEntry();
233 flowEntry.setDpid(new Dpid(nodeId));
234 flowEntry.setInPort(inPort);
235 flowEntry.setOutPort(dest.port());
236 result_data_path.flowEntries().add(flowEntry);
Pavlin Radoslavovf34c2902013-02-22 10:33:34 -0800237 }
Pavlin Radoslavov382b22a2013-01-28 09:24:04 -0800238 }
Pavlin Radoslavov19343432013-03-06 10:43:18 -0800239 // titanGraph.stopTransaction(Conclusion.SUCCESS);
Pavlin Radoslavovf83aa442013-02-26 14:09:01 -0800240 if (result_data_path.flowEntries().size() > 0)
241 return result_data_path;
Pavlin Radoslavovf34c2902013-02-22 10:33:34 -0800242
243 return null;
244 }
245
246 @Override
Pavlin Radoslavovf83aa442013-02-26 14:09:01 -0800247 public Boolean routeExists(SwitchPort src, SwitchPort dest) {
248 DataPath dataPath = getShortestPath(src, dest);
249 if (dataPath != null)
Pavlin Radoslavovf34c2902013-02-22 10:33:34 -0800250 return true;
251 return false;
252 }
Pavlin Radoslavov382b22a2013-01-28 09:24:04 -0800253}