blob: dedf607f4900104d4bee503dd2bd96c1b3f197be [file] [log] [blame]
package net.onrc.onos.ofcontroller.core.internal;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Iterator;
import java.util.List;
import net.floodlightcontroller.devicemanager.IDevice;
import net.floodlightcontroller.devicemanager.SwitchPort;
import net.onrc.onos.graph.GraphDBOperation;
import net.onrc.onos.ofcontroller.core.IDeviceStorage;
import net.onrc.onos.ofcontroller.core.INetMapTopologyObjects.IDeviceObject;
import net.onrc.onos.ofcontroller.core.INetMapTopologyObjects.IIpv4Address;
import net.onrc.onos.ofcontroller.core.INetMapTopologyObjects.IPortObject;
import net.onrc.onos.ofcontroller.core.INetMapTopologyObjects.ISwitchObject;
import net.onrc.onos.ofcontroller.devicemanager.OnosDevice;
import org.openflow.util.HexString;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import com.google.common.collect.Lists;
import com.google.common.net.InetAddresses;
import com.thinkaurelius.titan.core.TitanException;
/**
* This is the class for storing the information of devices into CassandraDB
* @author Pankaj
*/
public class DeviceStorageImpl implements IDeviceStorage {
protected final static Logger log = LoggerFactory.getLogger(DeviceStorageImpl.class);
private GraphDBOperation ope;
/***
* Initialize function. Before you use this class, please call this method
* @param conf configuration file for Cassandra DB
*/
@Override
public void init(String conf) {
try {
ope = new GraphDBOperation(conf);
} catch (TitanException e) {
log.error("Couldn't open graph operation", e);
}
}
/***
* Finalize/close function. After you use this class, please call this method.
* It will close the DB connection.
*/
@Override
public void close() {
ope.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 finalize() {
close();
}
/***
* This function is for adding the device into the DB.
* @param device The device you want to add into the DB.
* @return IDeviceObject which was added in the DB.
*/
@Override
public IDeviceObject addDevice(IDevice device) {
IDeviceObject obj = null;
for (int i = 0; i < 6; i++) {
try {
if (i > 0) {
log.debug("Retrying add device: i is {}", i);
}
if ((obj = ope.searchDevice(device.getMACAddressString())) != null) {
log.debug("Adding device {}: found existing device", device.getMACAddressString());
} else {
obj = ope.newDevice();
log.debug("Adding device {}: creating new device", device.getMACAddressString());
}
if (obj == null) {
return null;
}
changeDeviceAttachments(device, obj);
changeDeviceIpv4Addresses(device, obj);
obj.setMACAddress(device.getMACAddressString());
obj.setType("device");
obj.setState("ACTIVE");
ope.commit();
break;
//log.debug("Adding device {}",device.getMACAddressString());
} catch (TitanException e) {
ope.rollback();
log.error("Adding device {} failed", device.getMACAddressString(), e);
obj = null;
}
}
return obj;
}
/***
* This function is for updating the Device properties.
* @param device The device you want to add into the DB.
* @return IDeviceObject which was added in the DB.
*/
@Override
public IDeviceObject updateDevice(IDevice device) {
return addDevice(device);
}
/***
* This function is for removing the Device from the DB.
* @param device The device you want to delete from the DB.
*/
@Override
public void removeDevice(IDevice device) {
IDeviceObject dev;
if ((dev = ope.searchDevice(device.getMACAddressString())) != null) {
removeDevice(dev);
}
}
public void removeDevice(IDeviceObject deviceObject) {
String deviceMac = deviceObject.getMACAddress();
removeDeviceImpl(deviceObject);
try {
ope.commit();
log.debug("DeviceStorage:removeDevice mac:{} done", deviceMac);
} catch (TitanException e) {
ope.rollback();
log.error("DeviceStorage:removeDevice mac:{} failed", deviceMac);
}
}
public void removeDeviceImpl(IDeviceObject deviceObject) {
for (IIpv4Address ipv4AddressVertex : deviceObject.getIpv4Addresses()) {
ope.removeIpv4Address(ipv4AddressVertex);
}
ope.removeDevice(deviceObject);
}
/***
* This function is for getting the Device from the DB by Mac address of the device.
* @param mac The device mac address you want to get from the DB.
* @return IDeviceObject you want to get.
*/
@Override
public IDeviceObject getDeviceByMac(String mac) {
return ope.searchDevice(mac);
}
/***
* This function is for getting the Device from the DB by IP address of the device.
* @param ip The device ip address you want to get from the DB.
* @return IDeviceObject you want to get.
*/
@Override
public IDeviceObject getDeviceByIP(int ipv4Address) {
try {
IIpv4Address ipv4AddressVertex = ope.searchIpv4Address(ipv4Address);
if (ipv4AddressVertex != null) {
return ipv4AddressVertex.getDevice();
}
return null;
}
catch (TitanException e) {
log.error("DeviceStorage:getDeviceByIP:{} failed");
return null;
}
}
/***
* This function is for changing the Device attachment point.
* @param device The device you want change the attachment point
*/
@Override
public void changeDeviceAttachments(IDevice device) {
IDeviceObject obj = null;
try {
if ((obj = ope.searchDevice(device.getMACAddressString())) != null) {
log.debug("Changing device ports {}: found existing device", device.getMACAddressString());
changeDeviceAttachments(device, obj);
ope.commit();
} else {
log.debug("failed to search device...now adding {}", device.getMACAddressString());
addDevice(device);
}
} catch (TitanException e) {
ope.rollback();
log.error(":addDevice mac:{} failed", device.getMACAddressString());
}
}
/***
* This function is for changing the Device attachment point.
* @param device The new device you want change the attachment point
* @param obj The old device IDeviceObject that is going to change the attachment point.
*/
public void changeDeviceAttachments(IDevice device, IDeviceObject obj) {
SwitchPort[] attachmentPoints = device.getAttachmentPoints();
List<IPortObject> attachedPorts = Lists.newArrayList(obj.getAttachedPorts());
for (SwitchPort ap : attachmentPoints) {
//Check if there is the port
IPortObject port = ope.searchPort(HexString.toHexString(ap.getSwitchDPID()),
(short) ap.getPort());
log.debug("New Switch Port is {},{}",
HexString.toHexString(ap.getSwitchDPID()), (short) ap.getPort());
if (port != null){
if (attachedPorts.contains(port)) {
log.debug("This is the port you already attached {}: do nothing", device.getMACAddressString());
//This port will be remained, so remove from the removed port lists.
attachedPorts.remove(port);
} else {
log.debug("Adding device {}: attaching to port", device.getMACAddressString());
port.setDevice(obj);
}
log.debug("port number is {}", port.getNumber().toString());
log.debug("port desc is {}", port.getDesc());
}
}
for (IPortObject port: attachedPorts) {
log.debug("Detaching the device {}: detaching from port", device.getMACAddressString());
port.removeDevice(obj);
if (!obj.getAttachedPorts().iterator().hasNext()) {
// XXX If there are no more ports attached to the device,
// delete it. Otherwise we have a situation where the
// device remains forever with an IP address attached.
// When we implement device probing we should get rid of this.
removeDevice(obj);
}
}
}
/***
* This function is for changing the Device IPv4 address.
* @param device The new device you want change the ipaddress
*/
@Override
public void changeDeviceIPv4Address(IDevice device) {
log.debug("Changing IP address for {} to {}", device.getMACAddressString(),
device.getIPv4Addresses());
IDeviceObject obj;
try {
if ((obj = ope.searchDevice(device.getMACAddressString())) != null) {
changeDeviceIpv4Addresses(device, obj);
ope.commit();
} else {
log.error(":changeDeviceIPv4Address mac:{} failed", device.getMACAddressString());
}
} catch (TitanException e) {
ope.rollback();
log.error(":changeDeviceIPv4Address mac:{} failed due to exception {}", device.getMACAddressString(), e);
}
}
private void changeDeviceIpv4Addresses(IDevice device, IDeviceObject deviceObject) {
List<String> dbIpv4Addresses = new ArrayList<String>();
List<Integer> intDbIpv4Addresses = new ArrayList<Integer>();
for (IIpv4Address ipv4Vertex : deviceObject.getIpv4Addresses()) {
dbIpv4Addresses.add(InetAddresses.fromInteger(ipv4Vertex.getIpv4Address()).getHostAddress());
intDbIpv4Addresses.add(ipv4Vertex.getIpv4Address());
}
List<String> memIpv4Addresses = new ArrayList<String>();
for (int addr : device.getIPv4Addresses()) {
memIpv4Addresses.add(InetAddresses.fromInteger(addr).getHostAddress());
}
log.debug("Device IP addresses {}, database IP addresses {}",
memIpv4Addresses, dbIpv4Addresses);
for (int ipv4Address : device.getIPv4Addresses()) {
//if (deviceObject.getIpv4Address(ipv4Address) == null) {
if (!intDbIpv4Addresses.contains(ipv4Address)) {
IIpv4Address dbIpv4Address = ope.ensureIpv4Address(ipv4Address);
/*
IDeviceObject oldDevice = dbIpv4Address.getDevice();
if (oldDevice != null) {
oldDevice.removeIpv4Address(dbIpv4Address);
}
*/
log.debug("Adding IP address {}",
InetAddresses.fromInteger(ipv4Address).getHostAddress());
deviceObject.addIpv4Address(dbIpv4Address);
}
}
List<Integer> deviceIpv4Addresses = Arrays.asList(device.getIPv4Addresses());
for (IIpv4Address dbIpv4Address : deviceObject.getIpv4Addresses()) {
if (!deviceIpv4Addresses.contains(dbIpv4Address.getIpv4Address())) {
log.debug("Removing IP address {}",
InetAddresses.fromInteger(dbIpv4Address.getIpv4Address())
.getHostAddress());
deviceObject.removeIpv4Address(dbIpv4Address);
}
}
}
/**
* Takes an {@link OnosDevice} and adds it into the database. There is no
* checking of the database data and removing old data - an
* {@link OnosDevice} basically corresponds to a packet we've just seen,
* and we need to add that information into the database.
*/
@Override
public void addOnosDevice(OnosDevice onosDevice) {
String macAddress = HexString.toHexString(onosDevice.getMacAddress().toBytes());
//if the switch port we try to attach a new device already has a link, then stop adding device
IPortObject portObject1 = ope.searchPort(HexString.toHexString(
onosDevice.getSwitchDPID()), onosDevice.getSwitchPort());
if (portObject1.getLinkedPorts().iterator().hasNext()) {
log.debug("stop adding OnosDevice: {} due to there is a link to: {}",
onosDevice, portObject1.getLinkedPorts().iterator().next().getPortId());
return;
}
log.debug("addOnosDevice: {}", onosDevice);
try {
IDeviceObject device = ope.searchDevice(macAddress);
if (device == null) {
device = ope.newDevice();
device.setType("device");
device.setState("ACTIVE");
device.setMACAddress(macAddress);
}
// Check if the device has the IP address, add it if it doesn't
if (onosDevice.getIpv4Address() != null) {
boolean hasIpAddress = false;
for (IIpv4Address ipv4Address : device.getIpv4Addresses()) {
if (ipv4Address.getIpv4Address() == onosDevice.getIpv4Address().intValue()) {
hasIpAddress = true;
break;
}
}
if (!hasIpAddress) {
IIpv4Address ipv4Address = ope.ensureIpv4Address(onosDevice.getIpv4Address().intValue());
IDeviceObject oldDevice = ipv4Address.getDevice();
if (oldDevice != null && oldDevice.getMACAddress() != macAddress) {
oldDevice.removeIpv4Address(ipv4Address);
}
device.addIpv4Address(ipv4Address);
}
}
// Check if the device has the attachment point, add it if not
// TODO single attachment point for now, extend to multiple later
String switchDpid = HexString.toHexString(onosDevice.getSwitchDPID());
boolean hasAttachmentPoint = false;
Iterator<IPortObject> it = device.getAttachedPorts().iterator();
if (it.hasNext()) {
IPortObject existingPort = it.next();
if (existingPort != null) {
ISwitchObject existingSwitch = existingPort.getSwitch();
if (!existingSwitch.getDPID().equals(switchDpid) ||
existingPort.getNumber() != onosDevice.getSwitchPort()) {
existingPort.removeDevice(device);
}
else {
hasAttachmentPoint = true;
}
}
}
/*
for (IPortObject portObject : device.getAttachedPorts()) {
ISwitchObject switchObject = portObject.getSwitch();
if (switchObject.getDPID().equals(switchDpid)
&& portObject.getNumber() == onosDevice.getSwitchPort()) {
hasAttachmentPoint = true;
break;
}
}
*/
if (!hasAttachmentPoint) {
IPortObject portObject = ope.searchPort(switchDpid, onosDevice.getSwitchPort());
if (portObject != null) {
portObject.setDevice(device);
}
}
ope.commit();
}
catch (TitanException e) {
log.error("addOnosDevice {} failed:", macAddress, e);
ope.rollback();
}
}
}