| package net.onrc.onos.flow; |
| |
| import java.util.ArrayList; |
| import java.util.Collections; |
| import java.util.HashMap; |
| import java.util.HashSet; |
| import java.util.LinkedList; |
| import java.util.List; |
| import java.util.Map; |
| import java.util.Queue; |
| import java.util.Set; |
| |
| import org.openflow.util.HexString; |
| import org.slf4j.Logger; |
| import org.slf4j.LoggerFactory; |
| |
| import com.tinkerpop.blueprints.Direction; |
| import com.tinkerpop.blueprints.Vertex; |
| |
| import net.floodlightcontroller.core.IOFSwitch; |
| import net.onrc.onos.graph.GraphDBOperation; |
| import net.onrc.onos.graph.LocalTopologyEventListener; |
| import net.onrc.onos.ofcontroller.core.INetMapTopologyObjects.IFlowEntry; |
| import net.onrc.onos.ofcontroller.core.INetMapTopologyObjects.IFlowPath; |
| import net.onrc.onos.ofcontroller.core.INetMapTopologyObjects.IPortObject; |
| import net.onrc.onos.ofcontroller.core.ISwitchStorage.SwitchState; |
| import net.onrc.onos.ofcontroller.util.DataPath; |
| import net.onrc.onos.ofcontroller.util.Dpid; |
| import net.onrc.onos.ofcontroller.util.FlowEntry; |
| import net.onrc.onos.ofcontroller.util.FlowEntryAction; |
| import net.onrc.onos.ofcontroller.util.FlowEntryActions; |
| import net.onrc.onos.ofcontroller.util.FlowEntryMatch; |
| import net.onrc.onos.ofcontroller.util.FlowPath; |
| import net.onrc.onos.ofcontroller.util.Port; |
| import net.onrc.onos.ofcontroller.util.SwitchPort; |
| |
| public class FlowManagerImpl implements IFlowManager { |
| |
| protected final static Logger log = LoggerFactory.getLogger(LocalTopologyEventListener.class); |
| protected GraphDBOperation op; |
| |
| @Override |
| public void createFlow(IPortObject src_port, IPortObject dest_port) { |
| // TODO Auto-generated method stub |
| |
| } |
| |
| @Override |
| public Iterable<FlowPath> getFlows(IPortObject src_port, |
| IPortObject dest_port) { |
| // TODO Auto-generated method stub |
| return null; |
| } |
| |
| @Override |
| public Iterable<FlowPath> getOutFlows(IPortObject port) { |
| // TODO Auto-generated method stub |
| List<FlowPath> flowPaths = new ArrayList<FlowPath> (); |
| Iterable<IFlowEntry> flowEntries = port.getOutFlowEntries(); |
| |
| for(IFlowEntry fe: flowEntries) { |
| IFlowPath flow = fe.getFlow(); |
| FlowPath flowPath = new FlowPath(flow); |
| flowPaths.add(flowPath); |
| } |
| return flowPaths; |
| } |
| |
| @Override |
| public void reconcileFlows(IPortObject src_port) { |
| // TODO Auto-generated method stub |
| |
| log.debug("Reconcile Flows for Port removed: {}:{}",src_port.getSwitch().getDPID(),src_port.getNumber()); |
| Iterable<IFlowEntry> flowEntries = src_port.getOutFlowEntries(); |
| |
| for(IFlowEntry fe: flowEntries) { |
| IFlowPath flow = fe.getFlow(); |
| reconcileFlow(flow); |
| } |
| } |
| |
| private void reconcileFlow(IFlowPath flow) { |
| // TODO Auto-generated method stub |
| String src_dpid = flow.getSrcSwitch(); |
| String dst_dpid = flow.getDstSwitch(); |
| Short src_port = flow.getSrcPort(); |
| Short dst_port = flow.getDstPort(); |
| IPortObject src = null; |
| IPortObject dst = null; |
| src = op.searchPort(src_dpid, src_port); |
| dst = op.searchPort(dst_dpid, dst_port); |
| if (src != null && dst != null) { |
| FlowPath newFlow = this.computeFlowPath(src,dst); |
| installFlow(newFlow); |
| removeFlow(flow); |
| } |
| |
| } |
| |
| private void removeFlow(IFlowPath flow) { |
| // TODO Auto-generated method stub |
| |
| } |
| |
| private void installFlow(FlowPath newFlow) { |
| // TODO Auto-generated method stub |
| |
| } |
| |
| @Override |
| public void reconcileFlow(IPortObject src_port, IPortObject dest_port) { |
| // TODO Auto-generated method stub |
| |
| } |
| |
| @Override |
| public FlowPath computeFlowPath(IPortObject src_port, IPortObject dest_port) { |
| // TODO Auto-generated method stub |
| DataPath dataPath = new DataPath(); |
| |
| // FIXME: Bad idea to use FloodLight data structures (SwitchPort) |
| |
| dataPath.setSrcPort(new SwitchPort(new Dpid(src_port.getSwitch().getDPID()), |
| new Port(src_port.getNumber()))); |
| dataPath.setDstPort(new SwitchPort(new Dpid(src_port.getSwitch().getDPID()), |
| new Port(src_port.getNumber()))); |
| |
| if (src_port.getSwitch().equals(dest_port.getSwitch())) { |
| // on same switch create quick path |
| FlowEntry flowEntry = new FlowEntry(); |
| flowEntry.setDpid(new Dpid(src_port.getSwitch().getDPID())); |
| flowEntry.setInPort(new Port(src_port.getNumber())); |
| flowEntry.setOutPort(new Port(src_port.getNumber())); |
| flowEntry.setFlowEntryMatch(new FlowEntryMatch()); |
| flowEntry.flowEntryMatch().enableInPort(flowEntry.inPort()); |
| |
| // Set the outgoing port output action |
| FlowEntryActions flowEntryActions = flowEntry.flowEntryActions(); |
| FlowEntryAction flowEntryAction = new FlowEntryAction(); |
| flowEntryAction.setActionOutput(flowEntry.outPort()); |
| flowEntryActions.addAction(flowEntryAction); |
| dataPath.flowEntries().add(flowEntry); |
| |
| FlowPath flowPath = new FlowPath(); |
| flowPath.setDataPath(dataPath); |
| |
| return flowPath; |
| } |
| Vertex v_src = src_port.getSwitch().asVertex(); |
| Vertex v_dest = dest_port.getSwitch().asVertex(); |
| |
| // |
| // Implement the Shortest Path computation by using Breath First Search |
| // |
| Set<Vertex> visitedSet = new HashSet<Vertex>(); |
| Queue<Vertex> processingList = new LinkedList<Vertex>(); |
| Map<Vertex, Vertex> previousVertexMap = new HashMap<Vertex, Vertex>(); |
| |
| processingList.add(v_src); |
| visitedSet.add(v_src); |
| Boolean path_found = false; |
| while (! processingList.isEmpty()) { |
| Vertex nextVertex = processingList.poll(); |
| if (v_dest.equals(nextVertex)) { |
| path_found = true; |
| break; |
| } |
| for (Vertex parentPort : nextVertex.getVertices(Direction.OUT, "on")) { |
| for (Vertex childPort : parentPort.getVertices(Direction.OUT, "link")) { |
| for (Vertex child : childPort.getVertices(Direction.IN, "on")) { |
| // Ignore inactive switches |
| String state = child.getProperty("state").toString(); |
| if (! state.equals(SwitchState.ACTIVE.toString())) |
| continue; |
| |
| if (! visitedSet.contains(child)) { |
| previousVertexMap.put(parentPort, nextVertex); |
| previousVertexMap.put(childPort, parentPort); |
| previousVertexMap.put(child, childPort); |
| visitedSet.add(child); |
| processingList.add(child); |
| } |
| } |
| } |
| } |
| } |
| if (! path_found) { |
| return null; // No path found |
| } |
| |
| List<Vertex> resultPath = new LinkedList<Vertex>(); |
| Vertex previousVertex = v_dest; |
| resultPath.add(v_dest); |
| while (! v_src.equals(previousVertex)) { |
| Vertex currentVertex = previousVertexMap.get(previousVertex); |
| resultPath.add(currentVertex); |
| previousVertex = currentVertex; |
| } |
| Collections.reverse(resultPath); |
| |
| // Loop through the result and prepare the return result |
| // as a list of Flow Entries. |
| // |
| long nodeId = 0; |
| short portId = 0; |
| Port inPort = new Port(src_port.getNumber()); |
| Port outPort = new Port(); |
| int idx = 0; |
| for (Vertex v: resultPath) { |
| String type = v.getProperty("type").toString(); |
| // System.out.println("type: " + type); |
| if (type.equals("port")) { |
| //String number = v.getProperty("number").toString(); |
| // System.out.println("number: " + number); |
| |
| Object obj = v.getProperty("number"); |
| // String class_str = obj.getClass().toString(); |
| if (obj instanceof Short) { |
| portId = (Short)obj; |
| } else if (obj instanceof Integer) { |
| Integer int_nodeId = (Integer)obj; |
| portId = int_nodeId.shortValue(); |
| // int int_nodeId = (Integer)obj; |
| // portId = (short)int_nodeId.; |
| } |
| } else if (type.equals("switch")) { |
| String dpid = v.getProperty("dpid").toString(); |
| nodeId = HexString.toLong(dpid); |
| |
| // System.out.println("dpid: " + dpid); |
| } |
| idx++; |
| if (idx == 1) { |
| continue; |
| } |
| int mod = idx % 3; |
| if (mod == 0) { |
| // Setup the incoming port |
| inPort = new Port(portId); |
| continue; |
| } |
| if (mod == 2) { |
| // Setup the outgoing port, and add the Flow Entry |
| outPort = new Port(portId); |
| |
| FlowEntry flowEntry = new FlowEntry(); |
| flowEntry.setDpid(new Dpid(nodeId)); |
| flowEntry.setInPort(inPort); |
| flowEntry.setOutPort(outPort); |
| flowEntry.setFlowEntryMatch(new FlowEntryMatch()); |
| flowEntry.flowEntryMatch().enableInPort(flowEntry.inPort()); |
| |
| // Set the outgoing port output action |
| FlowEntryActions flowEntryActions = flowEntry.flowEntryActions(); |
| FlowEntryAction flowEntryAction = new FlowEntryAction(); |
| flowEntryAction.setActionOutput(flowEntry.outPort()); |
| flowEntryActions.addAction(flowEntryAction); |
| dataPath.flowEntries().add(flowEntry); |
| continue; |
| } |
| } |
| if (idx > 0) { |
| // Add the last Flow Entry |
| FlowEntry flowEntry = new FlowEntry(); |
| flowEntry.setDpid(new Dpid(nodeId)); |
| flowEntry.setInPort(inPort); |
| flowEntry.setOutPort(new Port(dest_port.getNumber())); |
| flowEntry.setFlowEntryMatch(new FlowEntryMatch()); |
| flowEntry.flowEntryMatch().enableInPort(flowEntry.inPort()); |
| |
| // Set the outgoing port output action |
| FlowEntryActions flowEntryActions = flowEntry.flowEntryActions(); |
| FlowEntryAction flowEntryAction = new FlowEntryAction(); |
| flowEntryAction.setActionOutput(flowEntry.outPort()); |
| flowEntryActions.addAction(flowEntryAction); |
| dataPath.flowEntries().add(flowEntry); |
| // TODO (BOC): why is this twice? |
| dataPath.flowEntries().add(flowEntry); |
| } |
| |
| |
| if (dataPath.flowEntries().size() > 0) { |
| FlowPath flowPath = new FlowPath(); |
| flowPath.setDataPath(dataPath); |
| |
| return flowPath; |
| } |
| return null; |
| |
| } |
| |
| @Override |
| public Iterable<FlowEntry> getFlowEntries(FlowPath flow) { |
| // TODO Auto-generated method stub |
| return null; |
| } |
| |
| |
| @Override |
| public boolean installRemoteFlowEntry(FlowPath flowPath, |
| FlowEntry entry) { |
| // TODO Auto-generated method stub |
| return false; |
| } |
| |
| @Override |
| public boolean removeRemoteFlowEntry(FlowPath flowPath, |
| FlowEntry entry) { |
| return false; |
| // TODO Auto-generated method stub |
| |
| } |
| |
| @Override |
| public boolean installFlowEntry(IOFSwitch mySwitch, |
| FlowPath flowPath, |
| FlowEntry flowEntry) { |
| // TODO Auto-generated method stub |
| return false; |
| } |
| |
| @Override |
| public boolean removeFlowEntry(IOFSwitch mySwitch, |
| FlowPath flowPath, |
| FlowEntry flowEntry) { |
| // TODO Auto-generated method stub |
| return false; |
| } |
| |
| |
| } |