3 * Copyright (c) 2013 Cisco Systems, Inc. and others. All rights reserved.
5 * This program and the accompanying materials are made available under the
6 * terms of the Eclipse Public License v1.0 which accompanies this distribution,
7 * and is available at http://www.eclipse.org/legal/epl-v10.html
10 package org.opendaylight.controller.protocol_plugin.openflow.internal;
12 import java.util.Date;
13 import java.util.HashSet;
14 import java.util.List;
17 import java.util.concurrent.ConcurrentHashMap;
18 import java.util.concurrent.ConcurrentMap;
19 import java.util.concurrent.CopyOnWriteArrayList;
21 import org.opendaylight.controller.protocol_plugin.openflow.IInventoryShimExternalListener;
22 import org.opendaylight.controller.protocol_plugin.openflow.IInventoryShimInternalListener;
23 import org.opendaylight.controller.protocol_plugin.openflow.IOFStatisticsManager;
24 import org.opendaylight.controller.protocol_plugin.openflow.core.IController;
25 import org.opendaylight.controller.protocol_plugin.openflow.core.IMessageListener;
26 import org.opendaylight.controller.protocol_plugin.openflow.core.ISwitch;
27 import org.opendaylight.controller.protocol_plugin.openflow.core.ISwitchStateListener;
28 import org.openflow.protocol.OFMessage;
29 import org.openflow.protocol.OFPortStatus;
30 import org.openflow.protocol.OFPortStatus.OFPortReason;
31 import org.openflow.protocol.OFType;
32 import org.openflow.protocol.statistics.OFDescriptionStatistics;
33 import org.openflow.protocol.statistics.OFStatistics;
34 import org.slf4j.Logger;
35 import org.slf4j.LoggerFactory;
37 import org.opendaylight.controller.sal.core.Actions;
38 import org.opendaylight.controller.sal.core.Buffers;
39 import org.opendaylight.controller.sal.core.Capabilities;
40 import org.opendaylight.controller.sal.core.ConstructionException;
41 import org.opendaylight.controller.sal.core.ContainerFlow;
42 import org.opendaylight.controller.sal.core.IContainerListener;
43 import org.opendaylight.controller.sal.core.Name;
44 import org.opendaylight.controller.sal.core.Node;
45 import org.opendaylight.controller.sal.core.Tables;
46 import org.opendaylight.controller.sal.core.Node.NodeIDType;
47 import org.opendaylight.controller.sal.core.NodeConnector;
48 import org.opendaylight.controller.sal.core.Property;
49 import org.opendaylight.controller.sal.core.TimeStamp;
50 import org.opendaylight.controller.sal.core.UpdateType;
51 import org.opendaylight.controller.sal.utils.GlobalConstants;
54 * The class describes a shim layer that bridges inventory events from Openflow
55 * core to various listeners. The notifications are filtered based on container
60 public class InventoryServiceShim implements IContainerListener,
61 IMessageListener, ISwitchStateListener {
62 protected static final Logger logger = LoggerFactory
63 .getLogger(InventoryServiceShim.class);
64 private IController controller = null;
65 private ConcurrentMap<String, IInventoryShimInternalListener> inventoryShimInternalListeners = new ConcurrentHashMap<String, IInventoryShimInternalListener>();
66 private List<IInventoryShimExternalListener> inventoryShimExternalListeners = new CopyOnWriteArrayList<IInventoryShimExternalListener>();
67 private ConcurrentMap<NodeConnector, List<String>> containerMap = new ConcurrentHashMap<NodeConnector, List<String>>();
68 private IOFStatisticsManager statsMgr;
70 void setController(IController s) {
74 void unsetController(IController s) {
75 if (this.controller == s) {
76 this.controller = null;
80 void setStatisticsManager(IOFStatisticsManager s) {
84 void unsetStatisticsManager(IOFStatisticsManager s) {
85 if (this.statsMgr == s) {
90 void setInventoryShimInternalListener(Map<?, ?> props,
91 IInventoryShimInternalListener s) {
93 logger.error("Didn't receive the service properties");
96 String containerName = (String) props.get("containerName");
97 if (containerName == null) {
98 logger.error("containerName not supplied");
101 if ((this.inventoryShimInternalListeners != null)
102 && !this.inventoryShimInternalListeners.containsKey(s)) {
103 this.inventoryShimInternalListeners.put(containerName, s);
104 logger.trace("Added inventoryShimInternalListener for container:"
109 void unsetInventoryShimInternalListener(Map<?, ?> props,
110 IInventoryShimInternalListener s) {
112 logger.error("Didn't receive the service properties");
115 String containerName = (String) props.get("containerName");
116 if (containerName == null) {
117 logger.error("containerName not supplied");
120 if ((this.inventoryShimInternalListeners != null)
121 && this.inventoryShimInternalListeners.containsKey(s)) {
122 this.inventoryShimInternalListeners.remove(containerName);
124 .trace("Removed inventoryShimInternalListener for container: "
129 void setInventoryShimExternalListener(IInventoryShimExternalListener s) {
130 logger.trace("Set inventoryShimExternalListener");
131 if ((this.inventoryShimExternalListeners != null)
132 && !this.inventoryShimExternalListeners.contains(s)) {
133 this.inventoryShimExternalListeners.add(s);
137 void unsetInventoryShimExternalListener(IInventoryShimExternalListener s) {
138 if ((this.inventoryShimExternalListeners != null)
139 && this.inventoryShimExternalListeners.contains(s)) {
140 this.inventoryShimExternalListeners.remove(s);
145 * Function called by the dependency manager when all the required
146 * dependencies are satisfied
150 this.controller.addMessageListener(OFType.PORT_STATUS, this);
151 this.controller.addSwitchStateListener(this);
155 * Function called after registering the
156 * service in OSGi service registry.
159 /* Start with existing switches */
164 * Function called by the dependency manager when at least one
165 * dependency become unsatisfied or when the component is shutting
166 * down because for example bundle is being stopped.
170 this.controller.removeMessageListener(OFType.PACKET_IN, this);
171 this.controller.removeSwitchStateListener(this);
173 this.inventoryShimInternalListeners.clear();
174 this.containerMap.clear();
175 this.controller = null;
179 public void receive(ISwitch sw, OFMessage msg) {
181 if (msg instanceof OFPortStatus) {
182 handlePortStatusMessage(sw, (OFPortStatus) msg);
184 } catch (ConstructionException e) {
190 protected void handlePortStatusMessage(ISwitch sw, OFPortStatus m)
191 throws ConstructionException {
192 Node node = new Node(NodeIDType.OPENFLOW, sw.getId());
193 NodeConnector nodeConnector = PortConverter.toNodeConnector(m.getDesc()
194 .getPortNumber(), node);
195 UpdateType type = null;
197 if (m.getReason() == (byte) OFPortReason.OFPPR_ADD.ordinal()) {
198 type = UpdateType.ADDED;
199 } else if (m.getReason() == (byte) OFPortReason.OFPPR_DELETE.ordinal()) {
200 type = UpdateType.REMOVED;
201 } else if (m.getReason() == (byte) OFPortReason.OFPPR_MODIFY.ordinal()) {
202 type = UpdateType.CHANGED;
206 // get node connector properties
207 Set<Property> props = InventoryServiceHelper.OFPortToProps(m
209 notifyInventoryShimListener(nodeConnector, type, props);
214 public void switchAdded(ISwitch sw) {
218 // Add all the nodeConnectors of this switch
219 Map<NodeConnector, Set<Property>> ncProps = InventoryServiceHelper
220 .OFSwitchToProps(sw);
221 for (Map.Entry<NodeConnector, Set<Property>> entry : ncProps.entrySet()) {
222 notifyInventoryShimListener(entry.getKey(), UpdateType.ADDED, entry
231 public void switchDeleted(ISwitch sw) {
239 public void containerModeUpdated(UpdateType t) {
244 public void tagUpdated(String containerName, Node n, short oldTag,
245 short newTag, UpdateType t) {
249 public void containerFlowUpdated(String containerName,
250 ContainerFlow previousFlow, ContainerFlow currentFlow, UpdateType t) {
254 public void nodeConnectorUpdated(String containerName, NodeConnector p,
256 if (this.containerMap == null) {
257 logger.error("containerMap is NULL");
260 List<String> containers = this.containerMap.get(p);
261 if (containers == null) {
262 containers = new CopyOnWriteArrayList<String>();
264 boolean updateMap = false;
267 if (!containers.contains(containerName)) {
268 containers.add(containerName);
273 if (containers.contains(containerName)) {
274 containers.remove(containerName);
282 if (containers.isEmpty()) {
283 // Do cleanup to reduce memory footprint if no
284 // elements to be tracked
285 this.containerMap.remove(p);
287 this.containerMap.put(p, containers);
291 // notify InventoryService
292 notifyInventoryShimInternalListener(containerName, p, t, null);
295 private void notifyInventoryShimExternalListener(Node node,
296 UpdateType type, Set<Property> props) {
297 for (IInventoryShimExternalListener s : this.inventoryShimExternalListeners) {
298 s.updateNode(node, type, props);
302 private void notifyInventoryShimExternalListener(
303 NodeConnector nodeConnector, UpdateType type, Set<Property> props) {
304 for (IInventoryShimExternalListener s : this.inventoryShimExternalListeners) {
305 s.updateNodeConnector(nodeConnector, type, props);
309 private void notifyInventoryShimInternalListener(String container,
310 NodeConnector nodeConnector, UpdateType type, Set<Property> props) {
311 IInventoryShimInternalListener inventoryShimInternalListener = inventoryShimInternalListeners
313 if (inventoryShimInternalListener != null) {
314 inventoryShimInternalListener.updateNodeConnector(nodeConnector,
316 logger.trace(type + " " + nodeConnector + " on container "
322 * Notify all internal and external listeners
324 private void notifyInventoryShimListener(NodeConnector nodeConnector,
325 UpdateType type, Set<Property> props) {
326 // Always notify default InventoryService. Store properties in default one.
327 notifyInventoryShimInternalListener(GlobalConstants.DEFAULT.toString(),
328 nodeConnector, type, props);
330 // Now notify other containers
331 List<String> containers = containerMap.get(nodeConnector);
332 if (containers != null) {
333 for (String container : containers) {
334 // no property stored in container components.
335 notifyInventoryShimInternalListener(container, nodeConnector,
340 // Notify DiscoveryService
341 notifyInventoryShimExternalListener(nodeConnector, type, props);
345 * Notify all internal and external listeners
347 private void notifyInventoryShimListener(Node node, UpdateType type,
348 Set<Property> props) {
351 // Notify only the default Inventory Service
352 IInventoryShimInternalListener inventoryShimDefaultListener = inventoryShimInternalListeners
353 .get(GlobalConstants.DEFAULT.toString());
354 if (inventoryShimDefaultListener != null) {
355 inventoryShimDefaultListener.updateNode(node, type, props);
359 // Notify all Inventory Service containers
360 for (IInventoryShimInternalListener inventoryShimInternalListener : inventoryShimInternalListeners
362 inventoryShimInternalListener.updateNode(node, type, null);
369 // Notify external listener
370 notifyInventoryShimExternalListener(node, type, props);
373 private void addNode(ISwitch sw) {
376 node = new Node(NodeIDType.OPENFLOW, sw.getId());
377 } catch (ConstructionException e) {
378 logger.error("{}", e.getMessage());
382 UpdateType type = UpdateType.ADDED;
384 Set<Property> props = new HashSet<Property>();
385 Long sid = (Long) node.getID();
387 Date connectedSince = controller.getSwitches().get(sid)
389 Long connectedSinceTime = (connectedSince == null) ? 0 : connectedSince
391 props.add(new TimeStamp(connectedSinceTime, "connectedSince"));
394 if (statsMgr != null && statsMgr.getOFDescStatistics(sid) != null) {
395 List<OFStatistics> stats = statsMgr.getOFDescStatistics(sid);
396 if (stats.size() > 0) {
397 name = ((OFDescriptionStatistics) stats.get(0))
401 props.add(new Name(name));
403 byte tables = sw.getTables();
404 Tables t = new Tables(tables);
408 int cap = sw.getCapabilities();
409 Capabilities c = new Capabilities(cap);
413 int act = sw.getActions();
414 Actions a = new Actions(act);
418 int buffers = sw.getBuffers();
419 Buffers b = new Buffers(buffers);
423 // Notify all internal and external listeners
424 notifyInventoryShimListener(node, type, props);
427 private void removeNode(ISwitch sw) {
430 node = new Node(NodeIDType.OPENFLOW, sw.getId());
431 } catch (ConstructionException e) {
432 logger.error("{}", e.getMessage());
436 UpdateType type = UpdateType.REMOVED;
438 // Notify all internal and external listeners
439 notifyInventoryShimListener(node, type, null);
442 private void startService() {
443 // Get a snapshot of all the existing switches
444 Map<Long, ISwitch> switches = this.controller.getSwitches();
445 for (ISwitch sw : switches.values()) {