Cherry-pick from https://gerrit.onos.onlab.us/#/c/342/
Cherry-pick from https://gerrit.onos.onlab.us/#/c/322/
Suppress device update for the same device.
Add function to clean devices.
Conflicts:
src/main/java/net/onrc/onos/ofcontroller/devicemanager/OnosDeviceManager.java
NOTE: The above conflict has been resolved by hand.
The conflict was in the number of parameters when
calling deviceStorage.init() inside file OnosDeviceManager.java:
deviceStorage.init("") -> deviceStorage.init("","")
Conflicts:
src/main/java/net/onrc/onos/datagrid/HazelcastDatagrid.java
src/main/java/net/onrc/onos/datagrid/IDatagridService.java
NOTE: The above conflict has been resolved by hand.
Change-Id: I831e391efce9a795370be99238834b6bc7db2bee
diff --git a/src/main/java/net/onrc/onos/ofcontroller/devicemanager/OnosDeviceManager.java b/src/main/java/net/onrc/onos/ofcontroller/devicemanager/OnosDeviceManager.java
index 1b14875..e9ddfa7 100644
--- a/src/main/java/net/onrc/onos/ofcontroller/devicemanager/OnosDeviceManager.java
+++ b/src/main/java/net/onrc/onos/ofcontroller/devicemanager/OnosDeviceManager.java
@@ -4,8 +4,14 @@
import java.util.Collection;
import java.util.Date;
import java.util.HashMap;
+import java.util.HashSet;
import java.util.List;
import java.util.Map;
+import java.util.Set;
+import java.util.concurrent.ConcurrentHashMap;
+import java.util.concurrent.Executors;
+import java.util.concurrent.ScheduledExecutorService;
+import java.util.concurrent.TimeUnit;
import net.floodlightcontroller.core.FloodlightContext;
import net.floodlightcontroller.core.IFloodlightProviderService;
@@ -22,29 +28,51 @@
import net.floodlightcontroller.packet.IPv4;
import net.floodlightcontroller.packet.UDP;
import net.floodlightcontroller.util.MACAddress;
+import net.onrc.onos.datagrid.IDatagridService;
import net.onrc.onos.ofcontroller.core.IDeviceStorage;
import net.onrc.onos.ofcontroller.core.internal.DeviceStorageImpl;
+import net.onrc.onos.ofcontroller.topology.TopologyElement;
+import net.onrc.onos.ofcontroller.topology.TopologyElement.Type;
import org.openflow.protocol.OFMessage;
import org.openflow.protocol.OFPacketIn;
import org.openflow.protocol.OFType;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
public class OnosDeviceManager implements IFloodlightModule, IOFMessageListener,
IOnosDeviceService {
- private IDeviceStorage deviceStorage;
+ protected final static Logger log = LoggerFactory.getLogger(OnosDeviceManager.class);
+ private static final int CLEANUP_SECOND = 60*60;
+ private static final int AGEING_MILLSEC = 60*60*1000;
+ private IDeviceStorage deviceStorage;
private IFloodlightProviderService floodlightProvider;
-
+ private final static ScheduledExecutorService executor = Executors.newSingleThreadScheduledExecutor();
+
+ private IDatagridService datagrid;
+ private Map<Long, OnosDevice> mapDevice = new ConcurrentHashMap<Long, OnosDevice>();
+
+ public enum OnosDeviceUpdateType {
+ ADD, DELETE, UPDATE;
+ }
+
private class OnosDeviceUpdate implements IUpdate {
private OnosDevice device;
+ private OnosDeviceUpdateType type;
- public OnosDeviceUpdate(OnosDevice device) {
+ public OnosDeviceUpdate(OnosDevice device, OnosDeviceUpdateType type) {
this.device = device;
+ this.type = type;
}
@Override
public void dispatch() {
- deviceStorage.addOnosDevice(device);
+ if(type == OnosDeviceUpdateType.ADD) {
+ deviceStorage.addOnosDevice(device);
+ } else if (type == OnosDeviceUpdateType.DELETE){
+ deviceStorage.deleteOnosDevice(device);
+ }
}
}
@@ -81,18 +109,98 @@
}
private Command processPacketIn(IOFSwitch sw, OFPacketIn pi, Ethernet eth) {
-
- // Extract source entity information
+ long dpid =sw.getId();
+ short portId = pi.getInPort();
+ Long mac = eth.getSourceMAC().toLong();
+
OnosDevice srcDevice =
- getSourceDeviceFromPacket(eth, sw.getId(), pi.getInPort());
- if (srcDevice == null)
- return Command.STOP;
+ getSourceDeviceFromPacket(eth, dpid, portId);
+
+ if (srcDevice == null){
+ return Command.STOP;
+ }
- floodlightProvider.publishUpdate(new OnosDeviceUpdate(srcDevice));
+ //We check if it is the same device in datagrid to suppress the device update
+ OnosDevice exDev = null;
+ if((exDev = mapDevice.get(mac)) != null ){
+ if(exDev.equals(srcDevice)) {
+ //There is the same existing device. Update only ActiveSince time.
+ exDev.setLastSeenTimestamp(new Date());
+ if(log.isTraceEnabled()) {
+ log.debug("In the datagrid, there is the same device."
+ + "Only update last seen time. dpid {}, port {}, mac {}, ip {}, lastSeenTime {}",
+ dpid, portId, srcDevice.getMacAddress(), srcDevice.getIpv4Address(), srcDevice.getLastSeenTimestamp().getTime());
+ }
+ return Command.CONTINUE;
+ } else if (srcDevice.getIpv4Address() == null &&
+ exDev.getSwitchDPID() == srcDevice.getSwitchDPID() &&
+ exDev.getSwitchPort() == srcDevice.getSwitchPort() &&
+ exDev.getVlan() == srcDevice.getVlan()) {
+ //Device attachment point and mac address are the same
+ //but the packet does not have an ip address.
+ exDev.setLastSeenTimestamp(new Date());
+ if(log.isTraceEnabled()) {
+ log.debug("In the datagrid, there is the same device with no ip."
+ + "Keep ip and update last seen time. dpid {}, port {}, mac {}, ip {}, lastSeenTime {}",
+ dpid, portId, srcDevice.getMacAddress(), srcDevice.getIpv4Address(), srcDevice.getLastSeenTimestamp().getTime());
+ }
+ return Command.CONTINUE;
+ }
+ }
+ //If the switch port we try to attach a new device already has a link, then stop adding device
+ Collection<TopologyElement> list = datagrid.getAllTopologyElements();
+ for(TopologyElement elem: list) {
+ if(elem.getType() == Type.ELEMENT_LINK) {
+ if((elem.getFromPort() == portId && elem.getFromSwitch() == dpid) ||
+ (elem.getToPort() == portId && elem.getToSwitch() == dpid)) {
+ if(log.isTraceEnabled()) {
+ log.debug("Stop adding OnosDevice {} due to there is a link to: dpid {} port {}",
+ srcDevice.getMacAddress(), dpid, portId);
+ }
+ return Command.CONTINUE;
+ }
+ }
+ }
+
+ addOnosDevice(mac, srcDevice);
+
+ if(log.isTraceEnabled()) {
+ log.debug("Add device info in the set. dpid {}, port {}, mac {}, ip {}, lastSeenTime {}",
+ dpid, portId, srcDevice.getMacAddress(), srcDevice.getIpv4Address(), srcDevice.getLastSeenTimestamp().getTime());
+ }
return Command.CONTINUE;
}
+ //Thread to delete devices periodically.
+ //Remove all devices from the map first and then finally delete devices from the DB.
+ private class CleanDevice implements Runnable {
+ @Override
+ public void run() {
+ log.debug("called CleanDevice");
+ try{
+ Set<OnosDevice> deleteSet = new HashSet<OnosDevice>();
+ for (OnosDevice dev : mapDevice.values() ) {
+ long now = new Date().getTime();
+ if((now - dev.getLastSeenTimestamp().getTime() > AGEING_MILLSEC)) {
+ if(log.isTraceEnabled()) {
+ log.debug("Remove device info in the datagrid. dpid {}, port {}, mac {}, ip {}, lastSeenTime {}, diff {}",
+ dev.getSwitchDPID(), dev.getSwitchPort(), dev.getMacAddress(), dev.getIpv4Address(),
+ dev.getLastSeenTimestamp().getTime(), now - dev.getLastSeenTimestamp().getTime());
+ }
+ deleteSet.add(dev);
+ }
+ }
+
+ for(OnosDevice dev : deleteSet) {
+ deleteOnosDevice(dev);
+ }
+ } catch(Exception e) {
+ log.error("Error:", e);
+ }
+ }
+ }
+
/**
* Get IP address from packet if the packet is either an ARP
* or a DHCP packet
@@ -177,14 +285,50 @@
public void init(FloodlightModuleContext context)
throws FloodlightModuleException {
floodlightProvider = context.getServiceImpl(IFloodlightProviderService.class);
-
+ executor.scheduleAtFixedRate(new CleanDevice(), 30 ,CLEANUP_SECOND, TimeUnit.SECONDS);
deviceStorage = new DeviceStorageImpl();
deviceStorage.init("","");
+
+ datagrid = context.getServiceImpl(IDatagridService.class);
}
@Override
public void startUp(FloodlightModuleContext context) {
floodlightProvider.addOFMessageListener(OFType.PACKET_IN, this);
+ datagrid.registerMapDeviceEventHandler(new MapDevListener());
}
+ @Override
+ public void deleteOnosDevice(OnosDevice dev) {
+ datagrid.sendNotificationDeviceDeleted(dev);
+ floodlightProvider.publishUpdate(new OnosDeviceUpdate(dev, OnosDeviceUpdateType.DELETE));
+ }
+
+ @Override
+ public void addOnosDevice(Long mac, OnosDevice dev) {
+ datagrid.sendNotificationDeviceAdded(mac, dev);
+ floodlightProvider.publishUpdate(new OnosDeviceUpdate(dev, OnosDeviceUpdateType.ADD));
+ }
+
+ //This is listener for datagrid mapDevice change.
+ class MapDevListener implements IDeviceEventHandler {
+
+ @Override
+ public void addDeviceEvent(Long mac, OnosDevice dev) {
+ mapDevice.put(mac, dev);
+ log.debug("addDeviceMap: device mac {}", mac);
+ }
+
+ @Override
+ public void deleteDeviceEvent(Long mac, OnosDevice dev) {
+ mapDevice.remove(mac);
+ log.debug("deleteDeviceMap: device mac {}", mac);
+ }
+
+ @Override
+ public void updateDeviceEvent(Long mac, OnosDevice dev) {
+ mapDevice.put(mac, dev);
+ log.debug("updateDeviceMap: device mac {}", mac);
+ }
+ }
}