| package net.onrc.onos.ofcontroller.core.internal; |
| |
| import java.util.ArrayList; |
| import java.util.List; |
| |
| import net.floodlightcontroller.core.IOFSwitch; |
| import net.onrc.onos.graph.GraphDBConnection; |
| import net.onrc.onos.graph.GraphDBOperation; |
| import net.onrc.onos.ofcontroller.core.INetMapTopologyObjects.IDeviceObject; |
| import net.onrc.onos.ofcontroller.core.INetMapTopologyObjects.IPortObject; |
| import net.onrc.onos.ofcontroller.core.INetMapTopologyObjects.ISwitchObject; |
| import net.onrc.onos.ofcontroller.core.ISwitchStorage; |
| |
| import org.openflow.protocol.OFPhysicalPort; |
| import org.openflow.protocol.OFPhysicalPort.OFPortConfig; |
| import org.openflow.protocol.OFPhysicalPort.OFPortState; |
| import org.slf4j.Logger; |
| import org.slf4j.LoggerFactory; |
| |
| /** |
| * This is the class for storing the information of switches into GraphDB |
| */ |
| public class SwitchStorageImpl implements ISwitchStorage { |
| protected GraphDBOperation op; |
| protected final static Logger log = LoggerFactory.getLogger(SwitchStorageImpl.class); |
| |
| /*** |
| * Initialize function. Before you use this class, please call this method |
| * @param conf configuration file for Cassandra DB |
| */ |
| @Override |
| public void init(String conf) { |
| GraphDBConnection conn = GraphDBConnection.getInstance(conf); |
| op = new GraphDBOperation(conn); |
| } |
| |
| /*** |
| * Finalize/close function. After you use this class, please call this method. |
| * It will close the DB connection. |
| */ |
| public void finalize() { |
| close(); |
| } |
| |
| /*** |
| * Finalize/close function. After you use this class, please call this method. |
| * It will close the DB connection. This is for Java garbage collection. |
| */ |
| @Override |
| public void close() { |
| op.close(); |
| } |
| |
| // Method designing policy: |
| // op.commit() and op.rollback() MUST called in public (first-class) methods. |
| // A first-class method MUST NOT call other first-class method. |
| // Routine process should be implemented in private method. |
| // A private method MUST NOT call commit or rollback. |
| |
| /*** |
| * This function is for updating the switch into the DB. |
| * @param dpid The switch dpid you want to update from the DB |
| * @param state The state of the switch like ACTIVE, INACTIVE |
| * @param dmope The DM_OPERATION of the switch |
| */ |
| /* |
| * Jono, 11/8/2013 |
| * We don't need this update method that demultiplexes DM_OPERATIONS, |
| * we can have clients just call the required methods directly. |
| * We especially don't need this update method to re-implement |
| * the functions of other methods. |
| */ |
| @Deprecated |
| @Override |
| public boolean updateSwitch(String dpid, SwitchState state, DM_OPERATION dmope) { |
| boolean success = false; |
| ISwitchObject sw = null; |
| |
| log.info("SwitchStorage:update {} dpid:{}", dmope, dpid); |
| switch(dmope) { |
| case UPDATE: |
| try { |
| sw = op.searchSwitch(dpid); |
| if (sw != null) { |
| setSwitchStateImpl(sw, state); |
| op.commit(); |
| success = true; |
| } |
| } catch (Exception e) { |
| op.rollback(); |
| e.printStackTrace(); |
| log.info("SwitchStorage:update {} dpid:{} failed", dmope, dpid); |
| } |
| break; |
| case INSERT: |
| case CREATE: |
| try { |
| sw = addSwitchImpl(dpid); |
| if (sw != null) { |
| if (state != SwitchState.ACTIVE) { |
| setSwitchStateImpl(sw, state); |
| } |
| op.commit(); |
| success = true; |
| } |
| } catch (Exception e) { |
| op.rollback(); |
| e.printStackTrace(); |
| log.info("SwitchStorage:update {} dpid:{} failed", dmope, dpid); |
| } |
| break; |
| case DELETE: |
| try { |
| sw = op.searchSwitch(dpid); |
| if (sw != null) { |
| deleteSwitchImpl(sw); |
| op.commit(); |
| success = true; |
| } |
| } catch (Exception e) { |
| op.rollback(); |
| e.printStackTrace(); |
| log.info("SwitchStorage:update {} dpid:{} failed", dmope, dpid); |
| } |
| break; |
| default: |
| } |
| |
| return success; |
| } |
| |
| @Override |
| public boolean addSwitch(IOFSwitch sw) { |
| boolean success = false; |
| |
| String dpid = sw.getStringId(); |
| log.info("SwitchStorage:addSwitch(): dpid {} ", dpid); |
| |
| try { |
| ISwitchObject curr = op.searchSwitch(dpid); |
| if (curr != null) { |
| //If existing the switch. set The SW state ACTIVE. |
| log.info("SwitchStorage:addSwitch dpid:{} already exists", dpid); |
| setSwitchStateImpl(curr, SwitchState.ACTIVE); |
| } else { |
| curr = addSwitchImpl(dpid); |
| } |
| |
| for (OFPhysicalPort port: sw.getPorts()) { |
| //addPort(dpid, port); |
| addPortImpl(curr, port); |
| |
| } |
| |
| // XXX for now delete devices when we change a port to prevent |
| // having stale devices. |
| DeviceStorageImpl deviceStorage = new DeviceStorageImpl(); |
| deviceStorage.init(""); |
| for (IPortObject portObject : curr.getPorts()) { |
| for (IDeviceObject deviceObject : portObject.getDevices()) { |
| // The deviceStorage has to remove on the object gained by its own |
| // FramedGraph, it can't use our objects from here |
| deviceStorage.removeDeviceImpl(deviceStorage.getDeviceByMac(deviceObject.getMACAddress())); |
| } |
| } |
| |
| op.commit(); |
| success = true; |
| } catch (Exception e) { |
| op.rollback(); |
| log.error("SwitchStorage:addSwitch dpid:{} failed", dpid, e); |
| } |
| |
| return success; |
| } |
| |
| /*** |
| * This function is for adding the switch into the DB. |
| * @param dpid The switch dpid you want to add into the DB. |
| */ |
| // This method is only called by tests, so we probably don't need it. |
| // If we need both addSwitch interfaces, one should call the other |
| // rather than implementing the same logic twice. |
| @Deprecated |
| @Override |
| public boolean addSwitch(String dpid) { |
| boolean success = false; |
| |
| log.info("SwitchStorage:addSwitch(): dpid {} ", dpid); |
| try { |
| ISwitchObject sw = op.searchSwitch(dpid); |
| if (sw != null) { |
| //If existing the switch. set The SW state ACTIVE. |
| log.info("SwitchStorage:addSwitch dpid:{} already exists", dpid); |
| setSwitchStateImpl(sw, SwitchState.ACTIVE); |
| } else { |
| addSwitchImpl(dpid); |
| } |
| op.commit(); |
| success = true; |
| } catch (Exception e) { |
| op.rollback(); |
| e.printStackTrace(); |
| log.error("SwitchStorage:addSwitch dpid:{} failed", dpid, e); |
| } |
| |
| return success; |
| } |
| |
| /*** |
| * This function is for deleting the switch into the DB. |
| * @param dpid The switch dpid you want to delete from the DB. |
| */ |
| @Override |
| public boolean deleteSwitch(String dpid) { |
| boolean success = false; |
| |
| try { |
| ISwitchObject sw = op.searchSwitch(dpid); |
| if (sw != null) { |
| deleteSwitchImpl(sw); |
| op.commit(); |
| } |
| success = true; |
| } catch (Exception e) { |
| op.rollback(); |
| e.printStackTrace(); |
| log.error("SwitchStorage:deleteSwitch {} failed", dpid); |
| } |
| |
| return success; |
| } |
| |
| public boolean deactivateSwitch(String dpid) { |
| boolean success = false; |
| |
| try { |
| ISwitchObject switchObject = op.searchSwitch(dpid); |
| if (switchObject != null) { |
| setSwitchStateImpl(switchObject, SwitchState.INACTIVE); |
| |
| for (IPortObject portObject : switchObject.getPorts()) { |
| portObject.setState("INACTIVE"); |
| } |
| op.commit(); |
| success = true; |
| } |
| else { |
| log.warn("Switch {} not found when trying to deactivate", dpid); |
| } |
| } catch (Exception e) { |
| // TODO what type of exception is thrown when we can't commit? |
| op.rollback(); |
| log.error("SwitchStorage:deactivateSwitch {} failed", dpid, e); |
| } |
| |
| return success; |
| } |
| |
| public boolean updatePort(String dpid, short portNum, int state, String desc) { |
| boolean success = false; |
| |
| try { |
| ISwitchObject sw = op.searchSwitch(dpid); |
| |
| if (sw != null) { |
| IPortObject p = sw.getPort(portNum); |
| log.info("SwitchStorage:updatePort dpid:{} port:{}", dpid, portNum); |
| if (p != null) { |
| setPortStateImpl(p, state, desc); |
| op.commit(); |
| } |
| success = true; |
| } else { |
| log.error("SwitchStorage:updatePort dpid:{} port:{} : failed switch does not exist", dpid, portNum); |
| } |
| } catch (Exception e) { |
| op.rollback(); |
| e.printStackTrace(); |
| log.error("SwitchStorage:addPort dpid:{} port:{} failed", dpid, portNum); |
| } |
| |
| return success; |
| } |
| |
| /*** |
| * This function is for adding the switch port into the DB. |
| * @param dpid The switch dpid that has the port. |
| * @param phport The port you want to add the switch. |
| */ |
| @Override |
| public boolean addPort(String dpid, OFPhysicalPort phport) { |
| boolean success = false; |
| |
| if(((OFPortConfig.OFPPC_PORT_DOWN.getValue() & phport.getConfig()) > 0) || |
| ((OFPortState.OFPPS_LINK_DOWN.getValue() & phport.getState()) > 0)) { |
| // just dispatch to deletePort() |
| // TODO This is wrong. We need to make sure the port is in the |
| // DB with the correct info and port state. |
| return deletePort(dpid, phport.getPortNumber()); |
| } |
| |
| try { |
| ISwitchObject sw = op.searchSwitch(dpid); |
| |
| if (sw != null) { |
| IPortObject portObject = addPortImpl(sw, phport); |
| |
| // XXX for now delete devices when we change a port to prevent |
| // having stale devices. |
| DeviceStorageImpl deviceStorage = new DeviceStorageImpl(); |
| deviceStorage.init(""); |
| |
| for (IDeviceObject deviceObject : portObject.getDevices()) { |
| deviceStorage.removeDevice(deviceObject); |
| } |
| |
| op.commit(); |
| success = true; |
| } else { |
| log.error("SwitchStorage:addPort dpid:{} port:{} : failed switch does not exist", dpid, phport.getPortNumber()); |
| } |
| } catch (Exception e) { |
| op.rollback(); |
| e.printStackTrace(); |
| log.error("SwitchStorage:addPort dpid:{} port:{} failed", dpid, phport.getPortNumber()); |
| } |
| |
| return success; |
| } |
| |
| /*** |
| * This function is for deleting the switch port from the DB. |
| * @param dpid The switch dpid that has the port. |
| * @param port The port you want to delete the switch. |
| */ |
| @Override |
| public boolean deletePort(String dpid, short port) { |
| boolean success = false; |
| |
| DeviceStorageImpl deviceStorage = new DeviceStorageImpl(); |
| deviceStorage.init(""); |
| |
| try { |
| ISwitchObject sw = op.searchSwitch(dpid); |
| |
| if (sw != null) { |
| IPortObject p = sw.getPort(port); |
| if (p != null) { |
| log.info("SwitchStorage:deletePort dpid:{} port:{} found and set INACTIVE", dpid, port); |
| p.setState("INACTIVE"); |
| |
| // XXX for now delete devices when we change a port to prevent |
| // having stale devices. |
| for (IDeviceObject d : p.getDevices()) { |
| deviceStorage.removeDevice(d); |
| } |
| op.commit(); |
| } |
| } |
| |
| success = true; |
| } catch (Exception e) { |
| op.rollback(); |
| e.printStackTrace(); |
| log.error("SwitchStorage:deletePort dpid:{} port:{} failed", dpid, port); |
| } |
| |
| return success; |
| } |
| |
| /** |
| * Get list of all ports on the switch specified by given DPID. |
| * |
| * @param dpid DPID of desired switch. |
| * @return List of port IDs. Empty list if no port was found. |
| */ |
| @Override |
| public List<Short> getPorts(String dpid) { |
| List<Short> ports = new ArrayList<Short>(); |
| |
| ISwitchObject srcSw = op.searchSwitch(dpid); |
| if (srcSw != null) { |
| for (IPortObject srcPort : srcSw.getPorts()) { |
| ports.add(srcPort.getNumber()); |
| } |
| } |
| |
| return ports; |
| } |
| |
| private ISwitchObject addSwitchImpl(String dpid) { |
| if (dpid != null) { |
| ISwitchObject sw = op.newSwitch(dpid); |
| sw.setState(SwitchState.ACTIVE.toString()); |
| log.info("SwitchStorage:addSwitchImpl dpid:{} added", dpid); |
| return sw; |
| } else { |
| return null; |
| } |
| } |
| |
| private void setSwitchStateImpl(ISwitchObject sw, SwitchState state) { |
| if (sw != null && state != null) { |
| sw.setState(state.toString()); |
| log.info("SwitchStorage:setSwitchStateImpl dpid:{} updated {}", |
| sw.getDPID(), state.toString()); |
| } |
| } |
| |
| private void deleteSwitchImpl(ISwitchObject sw) { |
| if (sw != null) { |
| op.removeSwitch(sw); |
| log.info("SwitchStorage:DeleteSwitchImpl dpid:{} done", |
| sw.getDPID()); |
| } |
| } |
| |
| |
| private IPortObject addPortImpl(ISwitchObject sw, OFPhysicalPort phport) { |
| IPortObject portObject = op.searchPort(sw.getDPID(), phport.getPortNumber()); |
| |
| log.info("SwitchStorage:addPort dpid:{} port:{}", |
| sw.getDPID(), phport.getPortNumber()); |
| |
| if (portObject != null) { |
| setPortStateImpl(portObject, phport.getState(), phport.getName()); |
| portObject.setState("ACTIVE"); |
| |
| // This a convoluted way of checking if the port is attached |
| // or not, but doing it this way avoids using the |
| // ISwitchObject.getPort method which uses GremlinGroovy query |
| // and takes forever. |
| boolean attached = false; |
| for (IPortObject portsOnSwitch : sw.getPorts()) { |
| if (portsOnSwitch.getPortId() == portObject.getPortId()) { |
| attached = true; |
| break; |
| } |
| } |
| |
| if (!attached) { |
| sw.addPort(portObject); |
| } |
| |
| /* |
| if (sw.getPort(phport.getPortNumber()) == null) { |
| // The port exists but the switch has no "on" link to it |
| sw.addPort(portObject); |
| }*/ |
| |
| log.info("SwitchStorage:addPort dpid:{} port:{} exists setting as ACTIVE", |
| sw.getDPID(), phport.getPortNumber()); |
| } else { |
| //addPortImpl(sw, phport.getPortNumber()); |
| portObject = op.newPort(sw.getDPID(), phport.getPortNumber()); |
| portObject.setState("ACTIVE"); |
| setPortStateImpl(portObject, phport.getState(), phport.getName()); |
| sw.addPort(portObject); |
| log.info("SwitchStorage:addPort dpid:{} port:{} done", |
| sw.getDPID(), phport.getPortNumber()); |
| } |
| |
| return portObject; |
| } |
| // TODO There's an issue here where a port with that ID could already |
| // exist when we try to add this one (because it's left over from an |
| // old topology). We need to remove an old port with the same ID when |
| // we add the new port. Also it seems that old ports like this are |
| // never cleaned up and will remain in the DB in the ACTIVE state forever. |
| /*private IPortObject addPortImpl(ISwitchObject sw, short portNum) { |
| IPortObject p = op.newPort(sw.getDPID(), portNum); |
| p.setState("ACTIVE"); |
| sw.addPort(p); |
| log.info("SwitchStorage:addPortImpl dpid:{} port:{} done", |
| sw.getDPID(), portNum); |
| |
| return p; |
| }*/ |
| |
| private void setPortStateImpl(IPortObject port, Integer state, String desc) { |
| if (port != null) { |
| if (state != null) { |
| port.setPortState(state); |
| } |
| if (desc != null) { |
| port.setDesc(desc); |
| } |
| |
| log.info("SwitchStorage:setPortStateImpl port:{} state:{} desc:{} done", |
| new Object[] {port.getPortId(), state, desc}); |
| } |
| } |
| } |