/* * Copyright (c) 2013 Cisco Systems, Inc. and others. All rights reserved. * * This program and the accompanying materials are made available under the * terms of the Eclipse Public License v1.0 which accompanies this distribution, * and is available at http://www.eclipse.org/legal/epl-v10.html */ package org.opendaylight.controller.protocol_plugin.openflow.internal; import java.util.Collections; import java.util.Date; import java.util.Dictionary; import java.util.HashMap; import java.util.HashSet; import java.util.Map; import java.util.Set; import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.ConcurrentMap; import org.apache.felix.dm.Component; import org.opendaylight.controller.protocol_plugin.openflow.IInventoryShimInternalListener; import org.opendaylight.controller.protocol_plugin.openflow.IOFInventoryService; import org.opendaylight.controller.protocol_plugin.openflow.core.IController; import org.opendaylight.controller.protocol_plugin.openflow.core.ISwitch; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.opendaylight.controller.sal.core.ConstructionException; import org.opendaylight.controller.sal.core.Node; import org.opendaylight.controller.sal.core.Node.NodeIDType; import org.opendaylight.controller.sal.core.NodeConnector; import org.opendaylight.controller.sal.core.Property; import org.opendaylight.controller.sal.core.TimeStamp; import org.opendaylight.controller.sal.core.Tables; import org.opendaylight.controller.sal.core.Actions; import org.opendaylight.controller.sal.core.Buffers; import org.opendaylight.controller.sal.core.Capabilities; import org.opendaylight.controller.sal.core.UpdateType; import org.opendaylight.controller.sal.inventory.IPluginInInventoryService; import org.opendaylight.controller.sal.inventory.IPluginOutInventoryService; import org.opendaylight.controller.sal.utils.GlobalConstants; /** * The class describes inventory service protocol plugin. One instance per * container of the network. Each instance gets container specific inventory * events from InventoryServiceShim. It interacts with SAL to pass inventory * data to the upper application. * * */ public class InventoryService implements IInventoryShimInternalListener, IPluginInInventoryService, IOFInventoryService { protected static final Logger logger = LoggerFactory .getLogger(InventoryService.class); private Set pluginOutInventoryServices = Collections .synchronizedSet(new HashSet()); private IController controller = null; private ConcurrentMap> nodeProps; // properties are maintained in default container only private ConcurrentMap> nodeConnectorProps; // properties are maintained in default container only private boolean isDefaultContainer = false; void setController(IController s) { this.controller = s; } void unsetController(IController s) { if (this.controller == s) { this.controller = null; } } /** * Function called by the dependency manager when all the required * dependencies are satisfied * */ @SuppressWarnings("rawtypes") void init(Component c) { logger.trace("INIT called!"); Dictionary props = c.getServiceProperties(); if (props != null) { String containerName = (String) props.get("containerName"); isDefaultContainer = containerName.equals(GlobalConstants.DEFAULT .toString()); } nodeProps = new ConcurrentHashMap>(); nodeConnectorProps = new ConcurrentHashMap>(); } /** * Function called by the dependency manager when at least one dependency * become unsatisfied or when the component is shutting down because for * example bundle is being stopped. * */ void destroy() { logger.trace("DESTROY called!"); } /** * Function called by dependency manager after "init ()" is called and after * the services provided by the class are registered in the service registry * */ void start() { logger.trace("START called!"); } /** * Function called by the dependency manager before the services exported by * the component are unregistered, this will be followed by a "destroy ()" * calls * */ void stop() { logger.trace("STOP called!"); } public void setPluginOutInventoryServices(IPluginOutInventoryService service) { logger.trace("Got a service set request {}", service); if (this.pluginOutInventoryServices != null) { this.pluginOutInventoryServices.add(service); } } public void unsetPluginOutInventoryServices( IPluginOutInventoryService service) { logger.trace("Got a service UNset request"); if (this.pluginOutInventoryServices != null) { this.pluginOutInventoryServices.remove(service); } } protected Node OFSwitchToNode(ISwitch sw) { Node node = null; Object id = sw.getId(); try { node = new Node(NodeIDType.OPENFLOW, id); } catch (ConstructionException e) { e.printStackTrace(); } return node; } /** * Retrieve nodes from openflow */ @Override public ConcurrentMap> getNodeProps() { if (nodeProps == null) return null; Map switches = controller.getSwitches(); for (Map.Entry entry : switches.entrySet()) { ISwitch sw = entry.getValue(); Node node = OFSwitchToNode(sw); Map propMap = null; if (isDefaultContainer) { propMap = new HashMap(); byte tables = sw.getTables(); Tables t = new Tables(tables); if (t != null) { propMap.put(Tables.TablesPropName,t); } int cap = sw.getCapabilities(); Capabilities c = new Capabilities(cap); if (c != null) { propMap.put(Capabilities.CapabilitiesPropName, c); } int act = sw.getActions(); Actions a = new Actions(act); if (a != null) { propMap.put(Actions.ActionsPropName,a); } int buffers = sw.getBuffers(); Buffers b = new Buffers(buffers); if (b != null) { propMap.put(Buffers.BuffersPropName,b); } Date connectedSince = sw.getConnectedDate(); Long connectedSinceTime = (connectedSince == null) ? 0 : connectedSince.getTime(); TimeStamp timeStamp = new TimeStamp(connectedSinceTime, "connectedSince"); propMap.put(TimeStamp.TimeStampPropName, timeStamp); nodeProps.put(node, propMap); } } return nodeProps; } @Override public ConcurrentMap> getNodeConnectorProps( Boolean refresh) { if (nodeConnectorProps == null) return null; if (isDefaultContainer && refresh) { Map switches = controller.getSwitches(); for (ISwitch sw : switches.values()) { Map> ncProps = InventoryServiceHelper .OFSwitchToProps(sw); for (Map.Entry> entry : ncProps .entrySet()) { updateNodeConnector(entry.getKey(), UpdateType.ADDED, entry .getValue()); } } } return nodeConnectorProps; } @Override public void updateNodeConnector(NodeConnector nodeConnector, UpdateType type, Set props) { logger.trace("NodeConnector id " + nodeConnector.getID() + " type " + nodeConnector.getType() + " " + type.getName() + " for Node id " + nodeConnector.getNode().getID()); if (nodeConnectorProps == null) return; synchronized (nodeConnectorProps) { Map propMap = nodeConnectorProps .get(nodeConnector); switch (type) { case ADDED: case CHANGED: if (propMap == null) propMap = new HashMap(); if (props != null) { for (Property prop : props) { propMap.put(prop.getName(), prop); } } nodeConnectorProps.put(nodeConnector, propMap); break; case REMOVED: nodeConnectorProps.remove(nodeConnector); break; default: return; } } // update sal and discovery synchronized (pluginOutInventoryServices) { for (IPluginOutInventoryService service : pluginOutInventoryServices) { service.updateNodeConnector(nodeConnector, type, props); } } } private void addNode(Node node, Set props) { logger.trace("{} added", node); if (nodeProps == null) return; // update local cache Map propMap = new HashMap(); for (Property prop : props) { propMap.put(prop.getName(), prop); } nodeProps.put(node, propMap); // update sal synchronized (pluginOutInventoryServices) { for (IPluginOutInventoryService service : pluginOutInventoryServices) { service.updateNode(node, UpdateType.ADDED, props); } } } private void removeNode(Node node) { logger.trace("{} removed", node); if (nodeProps == null) return; // update local cache nodeProps.remove(node); Set removeSet = new HashSet(); for (NodeConnector nodeConnector : nodeConnectorProps.keySet()) { if (nodeConnector.getNode().equals(node)) { removeSet.add(nodeConnector); } } for (NodeConnector nodeConnector : removeSet) { nodeConnectorProps.remove(nodeConnector); } // update sal synchronized (pluginOutInventoryServices) { for (IPluginOutInventoryService service : pluginOutInventoryServices) { service.updateNode(node, UpdateType.REMOVED, null); } } } /* * Function called by other protocol plugin modules to notify Inventory Service * that a property has changed for the specified switch */ @Override public void updateSwitchProperty(Long switchId, Set propSet) { // update local cache Node node = OFSwitchToNode(controller.getSwitches().get(switchId)); Map propMap = nodeProps.get(node); if (propMap == null) propMap = new HashMap(); for (Property prop : propSet) { propMap.put(prop.getName(), prop); } nodeProps.put(node, propMap); // update sal synchronized (pluginOutInventoryServices) { for (IPluginOutInventoryService service : pluginOutInventoryServices) { service.updateNode(node, UpdateType.CHANGED, propSet); } } } @Override public void updateNode(Node node, UpdateType type, Set props) { switch (type) { case ADDED: addNode(node, props); break; case REMOVED: removeNode(node); break; default: break; } } }