@Override public List<String> listDevices() { FVLog.log(LogLevel.DEBUG, null, "API listDevices() by: " + APIUserCred.getUserName()); FlowVisor fv = FlowVisor.getInstance(); // get list from main flowvisor instance List<String> dpids = new ArrayList<String>(); String dpidStr; /* * if (TopologyController.isConfigured()) { for (Long dpid : * TopologyController.getRunningInstance() .listDevices()) { dpidStr = * HexString.toHexString(dpid); if (!dpids.contains(dpidStr)) * dpids.add(dpidStr); else FVLog.log(LogLevel.WARN, TopologyController * .getRunningInstance(), "duplicate dpid detected: " + dpidStr); } } * else { */ // only list a device is we have a features reply for it for (FVEventHandler handler : fv.getHandlersCopy()) { if (handler instanceof FVClassifier) { OFFeaturesReply featuresReply = ((FVClassifier) handler).getSwitchInfo(); if (featuresReply != null) { dpidStr = FlowSpaceUtil.dpidToString(featuresReply.getDatapathId()); if (!dpids.contains(dpidStr)) dpids.add(dpidStr); else FVLog.log(LogLevel.WARN, handler, "duplicate dpid detected: " + dpidStr); } } } // } return dpids; }
@Override public String getSliceStats(String sliceName) throws SliceNotFound, PermissionDeniedException { if (!(doesSliceExist(sliceName))) { throw new SliceNotFound("Slice does not exist: " + sliceName); } FVSlicer fvSlicer = null; for (Iterator<FVEventHandler> it = FlowVisor.getInstance().getHandlersCopy().iterator(); it.hasNext(); ) { FVEventHandler eventHandler = it.next(); if (eventHandler instanceof FVClassifier) { FVClassifier classifier = (FVClassifier) eventHandler; if (!classifier.isIdentified()) // only print switches have have // been identified continue; fvSlicer = classifier.getSlicerByName(sliceName); if (fvSlicer != null) { break; } } } if (fvSlicer == null) return SendRecvDropStats.NO_STATS_AVAILABLE_MSG; return fvSlicer.getStats().combinedString(); }
private SlicerLimits getSliceLimits() throws DPIDNotFound { for (Iterator<FVEventHandler> it = FlowVisor.getInstance().getHandlersCopy().iterator(); it.hasNext(); ) { FVEventHandler eventHandler = it.next(); if (eventHandler instanceof FVClassifier) { FVClassifier classifier = (FVClassifier) eventHandler; return classifier.getSlicerLimits(); } } throw new DPIDNotFound("No classifier found, therefore no limits accessible"); }
/** * Returns a valid fvClassifier * * @param dpid * @return never null * @throws DPIDNotFound */ private FVClassifier lookupClassifier(long dpid) throws DPIDNotFound { for (Iterator<FVEventHandler> it = FlowVisor.getInstance().getHandlersCopy().iterator(); it.hasNext(); ) { FVEventHandler eventHandler = it.next(); if (eventHandler instanceof FVClassifier) { FVClassifier classifier = (FVClassifier) eventHandler; if (dpid == classifier.getDPID()) return classifier; } } throw new DPIDNotFound("No such switch: " + dpid); }
@Override public Map<String, String> getSliceInfo(String sliceName) throws PermissionDeniedException, SliceNotFound { /* * relaxed security -- anyone can read slice info for now String user = * APIUserCred.getUserName(); if (!FVConfig.isSupervisor(user) && * !APIAuth.transitivelyCreated(user, sliceName)) throw new * PermissionDeniedException( * "not superuser or transitive slice creator"); */ if (!(doesSliceExist(sliceName))) { throw new SliceNotFound("Slice does not exist: " + sliceName); } HashMap<String, String> map = new HashMap<String, String>(); synchronized (FVConfig.class) { try { map.put("contact_email", FVConfig.getSliceEmail(sliceName)); map.put("controller_hostname", FVConfig.getSliceHost(sliceName)); map.put("controller_port", String.valueOf(FVConfig.getSlicePort(sliceName))); map.put("creator", FVConfig.getSliceCreator(sliceName)); map.put("drop_policy", FVConfig.getSlicePolicy(sliceName)); } catch (ConfigError e) { FVLog.log(LogLevel.CRIT, null, "malformed slice: " + e); e.printStackTrace(); } } long dpid; int connection = 1; // TODO: come back an architect this so we can walk the list of slicers, // not the list of classifiers, and then slicers for (Iterator<FVEventHandler> it = FlowVisor.getInstance().getHandlersCopy().iterator(); it.hasNext(); ) { FVEventHandler eventHandler = it.next(); if (eventHandler instanceof FVClassifier) { FVClassifier classifier = (FVClassifier) eventHandler; if (!classifier.isIdentified()) // only print switches have have // been identified continue; dpid = classifier.getDPID(); FVSlicer fvSlicer = classifier.getSlicerByName(sliceName); if (fvSlicer != null) { map.put( "connection_" + connection++, FlowSpaceUtil.dpidToString(dpid) + "-->" + fvSlicer.getConnectionName()); } } } return map; }
@Override public Boolean changeSlice(String sliceName, String key, String value) throws MalformedURLException, InvalidSliceName, PermissionDeniedException, InvalidUserInfoKey, DuplicateControllerException { String changerSlice = APIUserCred.getUserName(); if (!APIAuth.transitivelyCreated(changerSlice, sliceName) && !FVConfig.isSupervisor(changerSlice)) throw new PermissionDeniedException( "Slice " + changerSlice + " does not have perms to change the passwd of " + sliceName); /** * this is the list of things a user is allowed to change about themselves. Critically, it * should not include "creator" string as this would allow security issues. */ try { if (key.equals("contact_email")) FVConfig.setSliceContactEmail(sliceName, value); else if (key.equals("controller_hostname")) { // make sure there isn't already a slice with this hostname and port // that this slice uses if (isSecondSliceSharingController(sliceName, value, FVConfig.getSlicePort(sliceName))) { throw new DuplicateControllerException( value, FVConfig.getSlicePort(sliceName), sliceName, "changed"); } FVConfig.setSliceHost(sliceName, value); } else if (key.equals("controller_port")) { // Make sure that there isn't already a slice on this port that uses // the same hostname that this slice uses if (isSecondSliceSharingController( sliceName, FVConfig.getSliceHost(sliceName), Integer.parseInt(value))) { throw new DuplicateControllerException( FVConfig.getSliceHost(sliceName), Integer.parseInt(value), sliceName, "changed"); } FVConfig.setSlicePort(sliceName, Integer.valueOf(value)); } else if (key.equals("drop_policy")) { // Set the drop policy when the controller is done, // either to an exact match of the packet in or to the // flow entry. FVConfig.setSliceDropPolicy(sliceName, value); } else throw new InvalidUserInfoKey( "invalid key: " + key + "-- only contact_email, drop_policy and " + "controller_{hostname,port} can be changed"); FlowVisor.getInstance().checkPointConfig(); } catch (ConfigError e) { // this should probably never happen b/c of above checks throw new InvalidUserInfoKey(e.toString()); } return true; }
@Override public String getSwitchStats(String dpidStr) throws DPIDNotFound, PermissionDeniedException { long dpid = FlowSpaceUtil.parseDPID(dpidStr); for (Iterator<FVEventHandler> it = FlowVisor.getInstance().getHandlersCopy().iterator(); it.hasNext(); ) { FVEventHandler eventHandler = it.next(); if (eventHandler instanceof FVClassifier) { FVClassifier classifier = (FVClassifier) eventHandler; if (classifier.getDPID() == dpid) return classifier.getStats().combinedString(); } } throw new DPIDNotFound("dpid not found: " + dpidStr); }
/** * Change the password for this slice * * <p>A slice is allowed to change its own password and the password of any slice that it has * (transitively) created * * @param sliceName * @param newPasswd */ @Override public Boolean changePasswd(String sliceName, String newPasswd) throws PermissionDeniedException { String changerSlice = APIUserCred.getUserName(); if (!APIAuth.transitivelyCreated(changerSlice, sliceName) && !FVConfig.isSupervisor(changerSlice)) throw new PermissionDeniedException( "Slice " + changerSlice + " does not have perms to change the passwd of " + sliceName); String salt = APIAuth.getSalt(); String crypt = APIAuth.makeCrypt(salt, newPasswd); sliceName = FVConfig.sanitize(sliceName); // set passwd is synchronized FVConfig.setPasswd(sliceName, salt, crypt); FlowVisor.getInstance().checkPointConfig(); return true; }
/** * Tell the classifier to drop packets that look like this * * @param fvClassifier * @param flowEntry * @param hardTimeout * @param idleTimeout */ private void sendDropRule( FVClassifier fvClassifier, FlowEntry flowEntry, String sliceName, short hardTimeout, short idleTimeout) { FVFlowMod flowMod = (FVFlowMod) FlowVisor.getInstance().getFactory().getMessage(OFType.FLOW_MOD); // block this exact flow OFMatch match = new OFMatch(); match.loadFromPacket(this.packetData, this.inPort); // different from previous policty of block by rule // flowMod.setMatch(flowEntry.getRuleMatch()); String drop_policy = null; try { drop_policy = FVConfig.getDropPolicy(sliceName); } catch (ConfigError e) { FVLog.log( LogLevel.ALERT, fvClassifier, "Failed to retrieve drop policy from config." + "\nDefauting to exact drop_policy"); drop_policy = "exact"; } if (drop_policy.equals("exact")) flowMod.setMatch(match); else if (drop_policy.equals("rule")) flowMod.setMatch(flowEntry.getRuleMatch()); else // Should never happen FVLog.log(LogLevel.CRIT, fvClassifier, "Error in configuration!"); flowMod.setCommand(FVFlowMod.OFPFC_ADD); flowMod.setActions(new LinkedList<OFAction>()); // send to zero-length // list, i.e., DROP flowMod.setLengthU(OFFlowMod.MINIMUM_LENGTH); flowMod.setHardTimeout(hardTimeout); flowMod.setIdleTimeout(idleTimeout); flowMod.setPriority((short) 0); // set to lowest priority flowMod.setFlags((short) 1); // send removed msg (1), not the check overlap (2), or // emergency flow cache (4) FVLog.log( LogLevel.WARN, fvClassifier, "inserting drop (hard=" + hardTimeout + ",idle=" + idleTimeout + ") rule for " + flowEntry); fvClassifier.sendMsg(flowMod, fvClassifier); }
@Override public Boolean deleteSlice(String sliceName) throws SliceNotFound, PermissionDeniedException, ConfigError { String changerSlice = APIUserCred.getUserName(); if (!APIAuth.transitivelyCreated(changerSlice, sliceName)) { FVLog.log( LogLevel.WARN, null, "API deletSlice(" + sliceName + ") failed by: " + APIUserCred.getUserName()); throw new PermissionDeniedException( "Slice " + changerSlice + " does not have perms to change the passwd of " + sliceName); } synchronized (FVConfig.class) { FVLog.log( LogLevel.DEBUG, null, "API removeSlice(" + sliceName + ") by: " + APIUserCred.getUserName()); FlowMap flowSpace = FlowSpaceUtil.deleteFlowSpaceBySlice(sliceName); try { // this is also synchronized against FVConfig.class FVConfig.deleteSlice(sliceName); } catch (Exception e) { throw new SliceNotFound("slice does not exist: " + sliceName); } /* * We need to do this because of the linear flowmap, because * it wants the slicers and classifiers to update their * view of the flowspace. * Once linearflowmap is dropped, this should be dropped as * well. * * FIXME */ FlowSpaceImpl.getProxy().notifyChange(flowSpace); // FVConfig.sendUpdates(FVConfig.FLOWSPACE); // signal that FS has changed FlowVisor.getInstance().checkPointConfig(); } return true; }
/* * (non-Javadoc) * * @see org.flowvisor.api.FVUserAPI#getDeviceInfo() */ @Override public Map<String, String> getDeviceInfo(String dpidStr) throws DPIDNotFound { Map<String, String> map = new HashMap<String, String>(); long dpid = HexString.toLong(dpidStr); FVClassifier fvClassifier = null; for (FVEventHandler handler : FlowVisor.getInstance().getHandlersCopy()) { if (handler instanceof FVClassifier) { OFFeaturesReply featuresReply = ((FVClassifier) handler).getSwitchInfo(); if (featuresReply != null && featuresReply.getDatapathId() == dpid) { fvClassifier = (FVClassifier) handler; break; } } } if (fvClassifier == null) throw new DPIDNotFound("dpid does not exist: " + dpidStr + " ::" + String.valueOf(dpid)); OFFeaturesReply config = fvClassifier.getSwitchInfo(); map.put("dpid", FlowSpaceUtil.dpidToString(dpid)); if (config != null) { map.put("nPorts", String.valueOf(config.getPorts().size())); String portList = ""; String portNames = ""; int p; for (Iterator<OFPhysicalPort> it = config.getPorts().iterator(); it.hasNext(); ) { OFPhysicalPort port = it.next(); p = U16.f(port.getPortNumber()); portList += p; portNames += port.getName() + "(" + p + ")"; if (it.hasNext()) { portList += ","; portNames += ","; } } map.put("portList", portList); map.put("portNames", portNames); } else { FVLog.log(LogLevel.WARN, null, "null config for: " + dpidStr); } map.put("remote", String.valueOf(fvClassifier.getConnectionName())); return map; }
@Override public Collection<Map<String, String>> getSwitchFlowDB(String dpidStr) throws DPIDNotFound { boolean found = false; long dpid = FlowSpaceUtil.parseDPID(dpidStr); List<Map<String, String>> ret = new LinkedList<Map<String, String>>(); for (Iterator<FVEventHandler> it = FlowVisor.getInstance().getHandlersCopy().iterator(); it.hasNext(); ) { FVEventHandler eventHandler = it.next(); if (eventHandler instanceof FVClassifier) { FVClassifier classifier = (FVClassifier) eventHandler; if (dpid == classifier.getDPID() || dpid == FlowEntry.ALL_DPIDS) { synchronized (classifier) { for (Iterator<FlowDBEntry> it2 = classifier.getFlowDB().iterator(); it2.hasNext(); ) { ret.add(it2.next().toBracketMap()); } } found = true; } } } if (!found) throw new DPIDNotFound("dpid not found: " + dpidStr); return ret; }
/** * Create a new slice (without flowspace) * * <p>Slices that contain the field separator are rewritten with underscores * * @param sliceName Cannot contain FVConfig.FS == '!' * @param passwd Cleartext! FIXME * @param controller_url Reference controller pseudo-url, e.g., tcp:hostname[:port] * @param slice_email As a contract for the slice * @return success * @throws InvalidSliceName * @throws PermissionDeniedException * @throws DuplicateControllerException */ @Override public Boolean createSlice( String sliceName, String passwd, String controller_url, String drop_policy, String slice_email) throws MalformedControllerURL, InvalidSliceName, InvalidDropPolicy, PermissionDeniedException, DuplicateControllerException { // FIXME: make sure this user has perms to do this OP // for now, all slices can create other slices // FIXME: for now, only handle tcp, not ssl controller url String[] list = controller_url.split(":"); if (!FVConfig.isSupervisor(APIUserCred.getUserName())) throw new PermissionDeniedException("only superusers can create new slices"); if (list.length < 2) throw new MalformedControllerURL( "controller url needs to be of the form " + "proto:hostname[:port], e.g., tcp:yourhost.foo.com:6633, not: " + controller_url); if (!list[0].equals("tcp")) throw new MalformedControllerURL( "Flowvisor currently only supports 'tcp' proto, not: " + list[0]); int controller_port; if (list.length >= 3) controller_port = Integer.valueOf(list[2]); else controller_port = FVConfig.OFP_TCP_PORT; // createSlice is synchronized() if (drop_policy.equals("")) drop_policy = "exact"; else if (!drop_policy.equals("exact") && !drop_policy.equals("rule")) throw new InvalidDropPolicy( "Flowvisor currently supports an 'exact'" + " or a 'rule' based drop policy"); // We need to make sure this slice doesn't already exist List<String> slices = null; synchronized (FVConfig.class) { try { slices = FVConfig.getAllSlices(); } catch (ConfigError e) { e.printStackTrace(); throw new RuntimeException("no SLICES subdir found in config"); } for (Iterator<String> sliceIter = slices.iterator(); sliceIter.hasNext(); ) { String existingSlice = sliceIter.next(); if (sliceName.equals(existingSlice)) { throw new PermissionDeniedException("Cannot create slice with existing name."); } } } FVConfig.createSlice( sliceName, list[1], controller_port, drop_policy, passwd, slice_email, APIUserCred.getUserName()); FlowVisor.getInstance().checkPointConfig(); return true; }