blob: cb535b2088a07e5c200b3e37d8e8be9444e3f797 [file] [log] [blame]
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.DBOperation;
import net.onrc.onos.graph.GraphDBManager;
import net.onrc.onos.ofcontroller.core.ISwitchStorage;
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 DBOperation 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(final String dbStore, final String conf) {
op = GraphDBManager.getDBOperation("ramcloud", "/tmp/ramcloudconf");
//op = GraphDBManager.getDBOperation(dbStore, conf);
}
/***
* Finalize/close function. After you use this class, please call this method.
* It will close the DB connection.
*/
@Override
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;
}
@Override
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;
}
@Override
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().equals( 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});
}
}
}