import static org.opendaylight.controller.hosttracker.internal.DeviceManagerImpl.DeviceUpdate.Change.CHANGE;
import static org.opendaylight.controller.hosttracker.internal.DeviceManagerImpl.DeviceUpdate.Change.DELETE;
+import java.net.InetAddress;
+import java.net.UnknownHostException;
import java.util.ArrayList;
import java.util.Calendar;
import java.util.Collection;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
+import java.util.Map.Entry;
import java.util.Queue;
import java.util.Set;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.Executors;
+import java.util.concurrent.Future;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.TimeUnit;
import org.opendaylight.controller.hosttracker.IEntityClass;
import org.opendaylight.controller.hosttracker.IEntityClassListener;
import org.opendaylight.controller.hosttracker.IEntityClassifierService;
+import org.opendaylight.controller.hosttracker.IfIptoHost;
+import org.opendaylight.controller.hosttracker.IfNewHostNotify;
import org.opendaylight.controller.hosttracker.SwitchPort;
+import org.opendaylight.controller.hosttracker.hostAware.HostNodeConnector;
+import org.opendaylight.controller.sal.core.ConstructionException;
import org.opendaylight.controller.sal.core.Edge;
+import org.opendaylight.controller.sal.core.Host;
+import org.opendaylight.controller.sal.core.Node;
import org.opendaylight.controller.sal.core.NodeConnector;
import org.opendaylight.controller.sal.core.NodeConnector.NodeConnectorIDType;
+import org.opendaylight.controller.sal.core.Property;
+import org.opendaylight.controller.sal.core.State;
+import org.opendaylight.controller.sal.core.Tier;
+import org.opendaylight.controller.sal.core.UpdateType;
import org.opendaylight.controller.sal.packet.ARP;
import org.opendaylight.controller.sal.packet.Ethernet;
import org.opendaylight.controller.sal.packet.IDataPacketService;
import org.opendaylight.controller.sal.packet.Packet;
import org.opendaylight.controller.sal.packet.PacketResult;
import org.opendaylight.controller.sal.packet.RawPacket;
+import org.opendaylight.controller.sal.packet.address.DataLinkAddress;
+import org.opendaylight.controller.sal.packet.address.EthernetAddress;
import org.opendaylight.controller.sal.topology.TopoEdgeUpdate;
+import org.opendaylight.controller.sal.utils.HexEncode;
import org.opendaylight.controller.sal.utils.ListenerDispatcher;
import org.opendaylight.controller.sal.utils.MultiIterator;
+import org.opendaylight.controller.sal.utils.NetUtils;
import org.opendaylight.controller.sal.utils.SingletonTask;
+import org.opendaylight.controller.sal.utils.Status;
+import org.opendaylight.controller.sal.utils.StatusCode;
+import org.opendaylight.controller.switchmanager.IInventoryListener;
import org.opendaylight.controller.switchmanager.ISwitchManager;
import org.opendaylight.controller.topologymanager.ITopologyManager;
import org.opendaylight.controller.topologymanager.ITopologyManagerAware;
* @author readams
*/
public class DeviceManagerImpl implements IDeviceService, IEntityClassListener,
- IListenDataPacket, ITopologyManagerAware {
+ IListenDataPacket, ITopologyManagerAware, IfIptoHost,
+ IInventoryListener {
protected static Logger logger = LoggerFactory
.getLogger(DeviceManagerImpl.class);
*/
protected ConcurrentHashMap<Long, Device> deviceMap;
+ protected ConcurrentHashMap<NodeConnector, Entity> inactiveStaticDevices;
/**
* Counter used to generate device keys
*/
*/
protected ListenerDispatcher<String, IDeviceListener> deviceListeners;
+ /**
+ * Using the IfNewHostNotify to notify listeners of host changes.
+ */
+ private Set<IfNewHostNotify> newHostNotify = Collections
+ .synchronizedSet(new HashSet<IfNewHostNotify>());
+
/**
* A device update event to be dispatched
*/
long newDomain = 0;
boolean newBD = false;
- if (oldDomain < newDomain)
- return -1;
- else if (oldDomain > newDomain)
+ if (oldDomain < newDomain) {
+ return -1;
+ } else if (oldDomain > newDomain) {
return 1;
-
+ }
// Give preference to OFPP_LOCAL always
if (!oldAP.getPort().getType().equals(NodeConnectorIDType.SWSTACK)
&& newAP.getPort().getType()
// Dependency injection
// ********************
+ void setNewHostNotify(IfNewHostNotify obj) {
+ this.newHostNotify.add(obj);
+ }
+
+ void unsetNewHostNotify(IfNewHostNotify obj) {
+ this.newHostNotify.remove(obj);
+ }
+
void setDataPacketService(IDataPacketService s) {
this.dataPacketService = s;
}
secondaryIndexMap = new HashMap<EnumSet<DeviceField>, DeviceIndex>();
deviceMap = new ConcurrentHashMap<Long, Device>();
+ inactiveStaticDevices = new ConcurrentHashMap<NodeConnector, Entity>();
classStateMap = new ConcurrentHashMap<String, ClassState>();
apComparator = new AttachmentPointComparator();
// IDeviceManagerService
// *********************
+ void setSwitchManager(ISwitchManager s) {
+ logger.debug("SwitchManager set");
+ this.switchManager = s;
+ }
+
+ void unsetSwitchManager(ISwitchManager s) {
+ if (this.switchManager == s) {
+ logger.debug("SwitchManager removed!");
+ this.switchManager = null;
+ }
+ }
+
@Override
public IDevice getDevice(Long deviceKey) {
return deviceMap.get(deviceKey);
if (inPkt == null) {
return PacketResult.IGNORED;
}
- try {
- throw new Exception("Sample");
- } catch (Exception e) {
- logger.error("Sample stack trace", e);
- }
+ // try {
+ // throw new Exception("Sample");
+ // } catch (Exception e) {
+ // logger.error("Sample stack trace", e);
+ // }
Packet formattedPak = this.dataPacketService.decodeDataPacket(inPkt);
Ethernet eth;
logger.info("Primary index {}", primaryIndex);
ArrayList<Long> deleteQueue = null;
LinkedList<DeviceUpdate> deviceUpdates = null;
+ Device oldDevice = null;
Device device = null;
// we may need to restart the learning process if we detect
// modified this Device).
if (!res)
continue;
-
+ oldDevice = device;
device = newDevice;
// update indices
if (!updateIndices(device, deviceKey)) {
if (moved) {
// we count device moved events in
// sendDeviceMovedNotification()
- sendDeviceMovedNotification(device);
+ sendDeviceMovedNotification(device, oldDevice);
if (logger.isTraceEnabled()) {
logger.trace("Device moved: attachment points {},"
+ "entities {}", device.attachmentPoints,
protected void notifyListeners(List<IDeviceListener> listeners,
DeviceUpdate update) {
- if (listeners == null) {
+ // Topology update is for some reason outside of listeners registry
+ // logic
+ Entity[] ents = update.device.getEntities();
+ Entity e = ents[ents.length - 1];
+
+ NodeConnector p = e.getPort();
+ Node node = p.getNode();
+ Host h = null;
+ try {
+
+ byte[] mac = NetUtils.longToByteArray6(e.getMacAddress());
+ DataLinkAddress dla = new EthernetAddress(
+ mac);
+ e.getIpv4Address();
+ InetAddress.getAllByName(e.getIpv4Address().toString());
+ h = new org.opendaylight.controller.sal.core.Host(dla,
+ InetAddress.getByName(e.getIpv4Address().toString()));
+ } catch (ConstructionException ce) {
+ p = null;
+ h = null;
+ } catch (UnknownHostException ue) {
+ p = null;
+ h = null;
+ }
+
+ if (topology != null && p != null && h != null) {
+ if (update.change.equals(DeviceUpdate.Change.ADD)) {
+ Tier tier = new Tier(1);
+ switchManager.setNodeProp(node, tier);
+ topology.updateHostLink(p, h, UpdateType.ADDED, null);
+ } else {
+ // No need to reset the tiering if no other hosts are currently
+ // connected
+ // If this switch was discovered to be an access switch, it
+ // still is even if the host is down
+ Tier tier = new Tier(0);
+ switchManager.setNodeProp(node, tier);
+ topology.updateHostLink(p, h, UpdateType.REMOVED, null);
+ }
+ }
+
+ if (listeners == null && newHostNotify.isEmpty()) {
return;
}
+ /**
+ * TODO: IfNewHostNotify is needed for current controller API. Adding
+ * logic so that existing apps (like SimpleForwardingManager) work.
+ * IDeviceListener adds additional methods and uses IListener's callback
+ * ordering. The two interfaces need to be merged.
+ */
+
+ for (IfNewHostNotify notify : newHostNotify) {
+ switch (update.change) {
+ case ADD:
+ notify.notifyHTClient(update.device.toHostNodeConnector());
+ break;
+ case DELETE:
+ notify.notifyHTClientHostRemoved(update.device
+ .toHostNodeConnector());
+ break;
+ case CHANGE:
+ }
+ }
+
+ /**
+ * TODO: Remove this section as IDeviceListener functionality gets
+ * merged with IfNewHostNotify
+ */
for (IDeviceListener listener : listeners) {
switch (update.change) {
case ADD:
}
}
+ /**
+ * Send update notifications to listeners. IfNewHostNotify listeners need to
+ * remove old device and add new device.
+ *
+ * @param device
+ * @param oldDevice
+ */
+ protected void sendDeviceMovedNotification(Device device, Device oldDevice) {
+ for (IfNewHostNotify notify : newHostNotify) {
+ notify.notifyHTClientHostRemoved(oldDevice.toHostNodeConnector());
+ notify.notifyHTClient(device.toHostNodeConnector());
+ }
+ sendDeviceMovedNotification(device);
+ }
+
/**
* this method will reclassify and reconcile a device - possibilities are -
* create new device(s), remove entities from this device. If the device
return mac;
}
- /**
+ /**
* Accepts an IPv4 address in a byte array and returns the corresponding
* 32-bit integer value.
*
*/
}
+ @Override
+ public HostNodeConnector hostFind(InetAddress networkAddress) {
+ // TODO Auto-generated method stub
+ return null;
+ }
+
+ @Override
+ public HostNodeConnector hostQuery(InetAddress networkAddress) {
+ // TODO Auto-generated method stub
+ return null;
+ }
+
+ @Override
+ public Future<HostNodeConnector> discoverHost(InetAddress networkAddress) {
+ // TODO Auto-generated method stub
+ return null;
+ }
+
+ @Override
+ public List<List<String>> getHostNetworkHierarchy(InetAddress hostAddress) {
+ // TODO Auto-generated method stub
+ return null;
+ }
+
+ @Override
+ public Set<HostNodeConnector> getAllHosts() {
+ Collection<Device> devices = Collections
+ .unmodifiableCollection(deviceMap.values());
+ Iterator<Device> i = devices.iterator();
+ Set<HostNodeConnector> nc = new HashSet<HostNodeConnector>();
+ while (i.hasNext()) {
+ Device device = i.next();
+ nc.add(device.toHostNodeConnector());
+ }
+ return nc;
+ }
+
+ @Override
+ public Set<HostNodeConnector> getActiveStaticHosts() {
+ Collection<Device> devices = Collections
+ .unmodifiableCollection(deviceMap.values());
+ Iterator<Device> i = devices.iterator();
+ Set<HostNodeConnector> nc = new HashSet<HostNodeConnector>();
+ while (i.hasNext()) {
+ Device device = i.next();
+ if (device.isStaticHost())
+ nc.add(device.toHostNodeConnector());
+ }
+ return nc;
+ }
+
+ @Override
+ public Set<HostNodeConnector> getInactiveStaticHosts() {
+ Collection<Entity> devices = Collections
+ .unmodifiableCollection(inactiveStaticDevices.values());
+ Iterator<Entity> i = devices.iterator();
+ Set<HostNodeConnector> nc = new HashSet<HostNodeConnector>();
+ while (i.hasNext()) {
+ Entity ent = i.next();
+ nc.add(ent.toHostNodeConnector());
+
+ }
+ return nc;
+ }
+
+ @Override
+ public Status addStaticHost(String networkAddress, String dataLayerAddress,
+ NodeConnector nc, String vlan) {
+ Long mac = HexEncode.stringToLong(dataLayerAddress);
+ try {
+ InetAddress addr = InetAddress.getByName(networkAddress);
+ int ip = toIPv4Address(addr.getAddress());
+ Entity e = new Entity(mac, Short.valueOf(vlan), ip, nc, new Date());
+
+ if (switchManager.isNodeConnectorEnabled(e.getPort())) {
+ Device d = this.learnDeviceByEntity(e);
+ d.setStaticHost(true);
+ } else {
+ logger.debug(
+ "Switch or switchport is not up, adding host {} to inactive list",
+ addr.getHostName());
+ inactiveStaticDevices.put(e.getPort(), e);
+ }
+ return new Status(StatusCode.SUCCESS);
+ } catch (UnknownHostException e) {
+ return new Status(StatusCode.INTERNALERROR);
+ }
+ }
+
+ @Override
+ public Status removeStaticHost(String networkAddress) {
+ Integer addr;
+ try {
+ addr = toIPv4Address(InetAddress.getByName(networkAddress)
+ .getAddress());
+ } catch (UnknownHostException e) {
+ return new Status(StatusCode.NOTFOUND, "Host does not exist");
+ }
+ Iterator<Device> di = this.getDeviceIteratorForQuery(null, null, addr,
+ null);
+ List<IDeviceListener> listeners = deviceListeners.getOrderedListeners();
+ while (di.hasNext()) {
+ Device d = di.next();
+ if (d.isStaticHost()) {
+ deleteDevice(d);
+ for (IfNewHostNotify notify : newHostNotify)
+ notify.notifyHTClientHostRemoved(d.toHostNodeConnector());
+ for (IDeviceListener listener : listeners)
+ listener.deviceRemoved(d);
+ }
+ }
+ //go through inactive entites.
+ Set<HostNodeConnector> inactive = this.getInactiveStaticHosts();
+ for(HostNodeConnector nc : inactive){
+ Integer ip =toIPv4Address(nc.getNetworkAddress().getAddress());
+ if(ip.equals(addr)){
+ this.inactiveStaticDevices.remove(nc.getnodeConnector());
+ }
+ }
+
+
+ return new Status(StatusCode.SUCCESS);
+ }
+
+ @Override
+ public void notifyNode(Node node, UpdateType type,
+ Map<String, Property> propMap) {
+ if (node == null)
+ return;
+ List<IDeviceListener> listeners = deviceListeners.getOrderedListeners();
+ switch (type) {
+ case REMOVED:
+ logger.debug("Received removed node {}", node);
+ for (Entry<Long, Device> d : deviceMap.entrySet()) {
+ Device device = d.getValue();
+ HostNodeConnector host = device.toHostNodeConnector();
+ if (host.getnodeconnectorNode().equals(node)) {
+ logger.debug("Node: {} is down, remove from Hosts_DB", node);
+ deleteDevice(device);
+ for (IfNewHostNotify notify : newHostNotify)
+ notify.notifyHTClientHostRemoved(host);
+ for (IDeviceListener listener : listeners)
+ listener.deviceRemoved(device);
+ }
+ }
+ break;
+ default:
+ break;
+ }
+ }
+
+ @Override
+ public void notifyNodeConnector(NodeConnector nodeConnector,
+ UpdateType type, Map<String, Property> propMap) {
+ if (nodeConnector == null)
+ return;
+ List<IDeviceListener> listeners = deviceListeners.getOrderedListeners();
+ boolean up = false;
+ switch (type) {
+ case ADDED:
+ up = true;
+ break;
+ case REMOVED:
+ break;
+ case CHANGED:
+ State state = (State) propMap.get(State.StatePropName);
+ if ((state != null) && (state.getValue() == State.EDGE_UP)) {
+ up = true;
+ }
+ break;
+ default:
+ return;
+ }
+
+ if (up) {
+ logger.debug("handleNodeConnectorStatusUp {}", nodeConnector);
+
+ Entity ent = inactiveStaticDevices.get(nodeConnector);
+ Device device = this.learnDeviceByEntity(ent);
+ if(device!=null){
+ HostNodeConnector host = device.toHostNodeConnector();
+ if (host != null) {
+ inactiveStaticDevices.remove(nodeConnector);
+ for (IfNewHostNotify notify : newHostNotify)
+ notify.notifyHTClient(host);
+ for (IDeviceListener listener : listeners)
+ listener.deviceAdded(device);
+ } else {
+ logger.debug("handleNodeConnectorStatusDown {}", nodeConnector);
+ }
+ }
+ }else{
+ // remove all devices on the node that went down.
+ for (Entry<Long, Device> entry : deviceMap.entrySet()) {
+ Device device = entry.getValue();
+ HostNodeConnector host = device.toHostNodeConnector();
+ if (host.getnodeConnector().equals(nodeConnector)) {
+ deleteDevice(device);
+ for (IfNewHostNotify notify : newHostNotify)
+ notify.notifyHTClientHostRemoved(host);
+ for (IDeviceListener listener : listeners)
+ listener.deviceRemoved(device);
+ }
+ }
+
+ }
+ }
+
+
/**
* For testing: consolidate the store NOW
*/