package org.opennaas.extensions.vrf.dijkstraroute.capability; import java.io.IOException; import java.util.ArrayList; import java.util.LinkedList; import java.util.List; import java.util.logging.Level; import java.util.logging.Logger; import javax.ws.rs.core.MediaType; import javax.ws.rs.core.Response; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; import org.apache.cxf.jaxrs.client.WebClient; import org.apache.cxf.jaxrs.ext.form.Form; import org.codehaus.jackson.map.ObjectMapper; import org.opennaas.core.resources.ActivatorException; import org.opennaas.core.resources.IResource; import org.opennaas.core.resources.IResourceIdentifier; import org.opennaas.core.resources.IResourceManager; import org.opennaas.core.resources.ResourceException; import org.opennaas.extensions.openflowswitch.capability.IOpenflowForwardingCapability; import org.opennaas.extensions.openflowswitch.model.FloodlightOFFlow; import org.opennaas.extensions.openflowswitch.model.OFFlow; import org.opennaas.extensions.openflowswitch.model.OpenDaylightOFFlow; import org.opennaas.extensions.sdnnetwork.capability.ofprovision.IOFProvisioningNetworkCapability; import org.opennaas.extensions.vrf.dijkstraroute.model.dijkstra.DijkstraAlgorithm; import org.opennaas.extensions.vrf.model.L2Forward; import org.opennaas.extensions.vrf.model.VRFRoute; import org.opennaas.extensions.vrf.model.topology.Edge; import org.opennaas.extensions.vrf.model.topology.Graph; import org.opennaas.extensions.vrf.model.topology.TopologyInfo; import org.opennaas.extensions.vrf.model.topology.Vertex; import org.opennaas.extensions.vrf.utils.Utils; import org.opennaas.extensions.vrf.utils.UtilsTopology; /** * * @author Josep Batallé (josep.batalle@i2cat.net) * */ public class DijkstraRoutingCapability implements IDijkstraRoutingCapability { Log log = LogFactory.getLog(DijkstraRoutingCapability.class); private List<Vertex> nodes = new ArrayList<Vertex>(); private List<Edge> edges = new ArrayList<Edge>(); private final int staticDijkstraCost = 1; private final String username = "admin"; private final String password = "123456"; private String topologyFilename = "data/dynamicTopology.json"; @Override public Response getDynamicRoute(String source, String target, String DPID, int inPort) { source = Utils.intIPv4toString(Integer.parseInt(source)); target = Utils.intIPv4toString(Integer.parseInt(target)); log.error("Request route " + source + " dst: " + target + " DPID: "+DPID); TopologyInfo topInfo = UtilsTopology.createAdjacencyMatrix(topologyFilename, staticDijkstraCost); edges = topInfo.getEdges(); nodes = topInfo.getNodes(); Vertex src = getVertex(source); Vertex dst = getVertex(target); Graph graph = new Graph(nodes, edges); DijkstraAlgorithm dijkstra = new DijkstraAlgorithm(graph); dijkstra.execute(src);//calculate the adjacent matrix from the requested source vertex LinkedList<Vertex> path = dijkstra.getPath(dst); log.error("Path: " + path); List<VRFRoute> listRoutes; if (path != null) {//if path null??? listRoutes = creatingRoutes(path, source, target); } else { return Response.ok("Path null. This route is not possible.").build(); } int outPutPortSrcSw = getOutPortSrcSw(path, DPID); Response response = proactiveRouting(listRoutes); List<OFFlow> listOF = ((List<OFFlow>) response.getEntity()); if (listOF.isEmpty()) { return Response.status(404).type("text/plain").entity("Route Not found.").build(); } StringBuilder listFlows = Utils.createJSONPath(source, null, listOF, target); return Response.ok(outPutPortSrcSw + ":" + listFlows).build(); //path format ; [192.168.1.1, 00:00:00:00:00:00:00:01, 00:00:00:00:00:00:00:03, 192.168.2.51] } private Response proactiveRouting(List<VRFRoute> routeSubnetList) { log.info("Proactive Routing. Searching the last Switch of the Route..."); List<OFFlow> listFlow = new ArrayList<OFFlow>(); //Conversion List of VRFRoute to List of FloodlightFlow if (routeSubnetList.size() > 0) { for (VRFRoute r : routeSubnetList) { insertRoutetoStaticBundle(r); log.error("Route " + r.getSourceAddress() + " " + r.getDestinationAddress() + " " + r.getSwitchInfo().getDPID() + " " + r.getSwitchInfo().getInputPort() + " " + r.getSwitchInfo().getOutputPort()); listFlow.add(Utils.VRFRouteToOFFlow(r, "2048")); listFlow.add(Utils.VRFRouteToOFFlow(r, "2054")); } } /*VTN String srcDPID = listFlow.get(0).getDPID(); String inPort = listFlow.get(0).getMatch().getIngressPort(); String dstDPID = listFlow.get(listFlow.size() - 1).getDPID(); String outPort = listFlow.get(listFlow.size() - 1).getActions().get(0).getValue(); log.error("SrcDPID " + srcDPID + " " + inPort + " " + dstDPID + " " + outPort); Response response; try { String initialSw = getProtocolType(srcDPID); String targetSw = getProtocolType(dstDPID); if (initialSw.equals("opendaylight")) { response = callVTN(srcDPID, inPort);//changed } if (targetSw.equals("opendaylight")) { response = callVTN(dstDPID, outPort); } } catch (ActivatorException ex) { Logger.getLogger(DijkstraRoutingCapability.class.getName()).log(Level.SEVERE, null, ex); } catch (ResourceException ex) { Logger.getLogger(DijkstraRoutingCapability.class.getName()).log(Level.SEVERE, null, ex); } */ // provision each link and mark the last one for (int i = 0; i < listFlow.size(); i++) { log.error("Flow " + listFlow.get(i).getMatch().getSrcIp() + " " + listFlow.get(i).getMatch().getDstIp() + " " + listFlow.get(i).getDPID() + " " + listFlow.get(i).getMatch().getIngressPort()+ " " + listFlow.get(i).getActions().get(0).getType() + ": " + listFlow.get(i).getActions().get(0).getValue()); insertFlow(listFlow.get(i)); } return Response.ok(listFlow).build(); } /** * Insert OFFlow to OpenFlow Switch * * @param flow * @return */ private Response insertFlow(OFFlow flow) { log.info("Dynamic Provision OpenFlow Flow Link"); String protocol; IResource resource; try { protocol = getProtocolType(flow.getDPID()); resource = getResourceByName(flow.getDPID()); if (resource == null) { return Response.serverError().entity("Does not exist a OFSwitch resource mapped with this switch Id").build(); } IOpenflowForwardingCapability forwardingCapability = (IOpenflowForwardingCapability) resource.getCapabilityByInterface(IOpenflowForwardingCapability.class); if (protocol.equals("opendaylight")) { if (!flow.getMatch().getEtherType().equals("2054") && !flow.getMatch().getEtherType().equals("0x0806")){ OpenDaylightOFFlow odlFlow = org.opennaas.extensions.openflowswitch.utils.Utils.OFFlowToODL(flow); forwardingCapability.createOpenflowForwardingRule(odlFlow); } } else if (protocol.equals("floodlight")) { FloodlightOFFlow fldFlow = org.opennaas.extensions.openflowswitch.utils.Utils.OFFlowToFLD(flow); forwardingCapability.createOpenflowForwardingRule(fldFlow); } } catch (ActivatorException ex) { Logger.getLogger(DijkstraRoutingCapability.class.getName()).log(Level.SEVERE, null, ex); } catch (ResourceException ex) { Logger.getLogger(DijkstraRoutingCapability.class.getName()).log(Level.SEVERE, null, ex); } return Response.ok().build(); } private IResource getResourceByName(String dpid) throws ActivatorException, ResourceException { IResourceManager resourceManager = org.opennaas.extensions.sdnnetwork.Activator.getResourceManagerService(); IResource sdnNetResource = resourceManager.listResourcesByType("sdnnetwork").get(0); IOFProvisioningNetworkCapability sdnCapab = (IOFProvisioningNetworkCapability) sdnNetResource.getCapabilityByInterface(IOFProvisioningNetworkCapability.class); String resourceName; List<IResource> listResources = resourceManager.listResourcesByType("openflowswitch"); String resourceSdnNetworkId = sdnCapab.getMapDeviceResource(dpid); if (resourceSdnNetworkId == null) { log.error("This Switch ID is not mapped to any ofswitch resource."); return null; } for (IResource r : listResources) { if (r.getResourceDescriptor().getId().equals(resourceSdnNetworkId)) { resourceName = r.getResourceDescriptor().getInformation().getName(); log.debug("Switch name is: " + resourceName); } } /*hardcode*/ resourceName = "s" + dpid.substring(dpid.length() - 1);//00:00:00:00:00:00:00:02 --> s2 if(resourceName.equals("s7")){//PSNC switches resourceName = dpid.substring(19, dpid.length() - 3);//00:00:00:00:00:00:00:02 --> s2 if(resourceName.equals("6")){ resourceName = "s1"; }else if(resourceName.equals("8")){ resourceName = "s2"; } } IResourceIdentifier resourceId = resourceManager.getIdentifierFromResourceName("openflowswitch", resourceName); if (resourceId == null) { log.error("IResource id is null."); return null; } return resourceManager.getResource(resourceId); } private int getOutPortSrcSw(LinkedList<Vertex> path, String DPID) { for(int i=0; i<path.size(); i++){ if(path.get(i).getDPID().equals(DPID)){ return extractPort(path.get(i), path.get(i+1), 1); } } return extractPort(path.get(1), path.get(2), 1); } private List<VRFRoute> creatingRoutes(LinkedList<Vertex> path, String sourceIP, String targetIP) { List<VRFRoute> listRoutes = new ArrayList<VRFRoute>(); Vertex source = path.get(0); String dpid; for (int j = 1; j < path.size() - 1; j++) { Vertex actual = path.get(j); Vertex nextVertex = path.get(j + 1); if (path.get(j).getType() == 0) {//is a switch int inputPort = extractPort(source, actual, 0); dpid = actual.getDPID(); int outputPort = extractPort(actual, nextVertex, 1); L2Forward sw = new L2Forward("2", inputPort, outputPort, dpid); VRFRoute newRoute = new VRFRoute(sourceIP, targetIP, sw); newRoute.setType("dynamic"); listRoutes.add(newRoute); sw = new L2Forward("2", outputPort, inputPort, dpid); newRoute = new VRFRoute(targetIP, sourceIP, sw); newRoute.setType("dynamic"); listRoutes.add(newRoute); source = path.get(j); } } return listRoutes; } /** * Given a source vertex and target vertex, this function returns the port. * * @param source * @param actual * @param type Is used in order to differentiate when we need the dst * port(first execution) or de source port * @return */ private int extractPort(Vertex source, Vertex actual, int type) { int port = 0; for (int i = 0; i < edges.size(); i++) { //from the newVertex try to find the next hop if (edges.get(i).getSource().equals(source) && edges.get(i).getDestination().equals(actual)) { // log.error("S" + i + " " + source + " to " + actual + " Src: " + edges.get(i).getSrcPort() + " Dst: " + edges.get(i).getDstPort()); if (edges.get(i).getSrcPort() == 0) { port = edges.get(i).getDstPort(); } else if (edges.get(i).getDstPort() == 0) { port = edges.get(i).getSrcPort(); } else { if (type == 0) { port = edges.get(i).getDstPort(); } else { port = edges.get(i).getSrcPort(); } } break; } } // log.error("Return Port: " + port); return port; } private Vertex getVertex(String dpid) { for (Vertex v : nodes) { if (v.getDPID().equals(dpid)) { return v; } } return null; } /** * Call a rest service to insert a StaticRoute * * @param route * @return true if the environment has been created */ public String insertRoutetoStaticBundle(VRFRoute route) { log.info("Calling insert Route Table service"); String response = null; String url = "http://localhost:8888/opennaas/vrf/staticrouting/dynamic-route"; Form fm = new Form(); fm.set("route", (VRFRoute) route); WebClient client = WebClient.create(url); String base64encodedUsernameAndPassword = Utils.base64Encode(username + ":" + password); client.header("Authorization", "Basic " + base64encodedUsernameAndPassword); ObjectMapper mapper = new ObjectMapper(); try { response = mapper.writeValueAsString(route); } catch (IOException ex) { Logger.getLogger(DijkstraRoutingCapability.class.getName()).log(Level.SEVERE, null, ex); } response = client.accept(MediaType.TEXT_PLAIN).type(MediaType.APPLICATION_JSON).put(response, String.class); log.error("Insert to other Bundle Response: " + response); return response; } @Override public Response getTopologyFilename() { return Response.ok(topologyFilename).build(); } @Override public Response setTopologyFilename(String topologyFilename) { this.topologyFilename = topologyFilename; return Response.ok("FileName " + topologyFilename + "selected.").build(); } public Response uploadDynamicTopology() { Response response = null; /** * NOT IMPLEMENTED YEET!!!!!!!!!!!! * */ return response; } private String getProtocolType(String dpid) throws ActivatorException, ResourceException { String protocol; IResourceManager resourceManager = org.opennaas.extensions.sdnnetwork.Activator.getResourceManagerService(); String resourceName; IResource resource = getResourceByName(dpid);//switchId resourceName = "s" + dpid.substring(dpid.length() - 1);//00:00:00:00:00:00:00:02 --> s2 if(resourceName.equals("s7")){//PSNC switches resourceName = dpid.substring(19, dpid.length() - 3);//00:00:00:00:00:00:00:02 --> s2 if(resourceName.equals("6")){ resourceName = "s1"; }else if(resourceName.equals("8")){ resourceName = "s2"; } } IResourceIdentifier resourceId = resourceManager.getIdentifierFromResourceName("openflowswitch", resourceName); IResource resourceDesc = resourceManager.getResourceById(resourceId.getId()); protocol = resourceDesc.getResourceDescriptor().getInformation().getDescription(); if (protocol == null) { protocol = "floodlight"; }else{ } return protocol; } public Response callVTN(String DPID, String Port) { log.error("Calling VTN from Dynamic (Dijkstra) Routing."); if (DPID == null || Port == null) { log.error("DstDPID: " + DPID + " outPort: " + Port); return Response.status(400).entity("DstDPID or outPut port is null").build(); } String url = "http://localhost:8888/opennaas/vtn/ipreq/" + DPID + "/" + Port; String base64encodedUsernameAndPassword = Utils.base64Encode(username + ":" + password); WebClient client = WebClient.create(url); client.header("Authorization", "Basic " + base64encodedUsernameAndPassword); client.accept(MediaType.TEXT_PLAIN); Response response = client.get(); log.error("VTN Coordinator response: " + response.getStatus()); return response; } }