Merge "Bug 4957 Role lifecycle support for TxChainManager in DeviceContext"
[openflowplugin.git] / applications / statistics-manager / src / main / java / org / opendaylight / openflowplugin / applications / statistics / manager / impl / StatNodeRegistrationImpl.java
1 /**
2  * Copyright (c) 2014 Cisco Systems, Inc. and others.  All rights reserved.
3  *
4  * This program and the accompanying materials are made available under the
5  * terms of the Eclipse Public License v1.0 which accompanies this distribution,
6  * and is available at http://www.eclipse.org/legal/epl-v10.html
7  */
8
9 package org.opendaylight.openflowplugin.applications.statistics.manager.impl;
10
11 import com.google.common.base.Optional;
12 import com.google.common.base.Preconditions;
13
14 import java.math.BigInteger;
15 import java.util.ArrayList;
16 import java.util.Collections;
17 import java.util.List;
18 import java.util.Map;
19 import java.util.concurrent.ConcurrentHashMap;
20
21 import org.opendaylight.controller.md.sal.binding.api.DataBroker;
22 import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.NodeId;
23 import org.opendaylight.controller.md.sal.common.api.clustering.Entity;
24 import org.opendaylight.controller.md.sal.common.api.clustering.EntityOwnershipChange;
25 import org.opendaylight.controller.md.sal.common.api.clustering.EntityOwnershipService;
26 import org.opendaylight.controller.md.sal.common.api.clustering.EntityOwnershipState;
27 import org.opendaylight.controller.md.sal.common.api.clustering.EntityOwnershipListener;
28 import org.opendaylight.controller.md.sal.common.api.clustering.EntityOwnershipListenerRegistration;
29 import org.opendaylight.controller.sal.binding.api.NotificationProviderService;
30 import org.opendaylight.openflowplugin.applications.statistics.manager.StatNodeRegistration;
31 import org.opendaylight.openflowplugin.applications.statistics.manager.StatPermCollector.StatCapabTypes;
32 import org.opendaylight.openflowplugin.applications.statistics.manager.StatisticsManager;
33 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.FeatureCapability;
34 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.FlowCapableNode;
35 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.FlowCapableNodeUpdated;
36 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.FlowFeatureCapabilityFlowStats;
37 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.FlowFeatureCapabilityGroupStats;
38 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.FlowFeatureCapabilityPortStats;
39 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.FlowFeatureCapabilityQueueStats;
40 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.FlowFeatureCapabilityTableStats;
41 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.flow.node.SwitchFeatures;
42 import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.NodeConnectorRemoved;
43 import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.NodeConnectorUpdated;
44 import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.NodeRef;
45 import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.NodeRemoved;
46 import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.NodeUpdated;
47 import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.nodes.Node;
48 import org.opendaylight.yangtools.concepts.ListenerRegistration;
49 import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
50 import org.opendaylight.yangtools.yang.common.QName;
51 import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier;
52 import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier.NodeIdentifierWithPredicates;
53 import org.slf4j.Logger;
54 import org.slf4j.LoggerFactory;
55
56 /**
57  * statistics-manager
58  * org.opendaylight.openflowplugin.applications.statistics.manager.impl
59  *
60  * @author <a href="mailto:vdemcak@cisco.com">Vaclav Demcak</a>
61  *
62  * Created: Aug 28, 2014
63  */
64 public class StatNodeRegistrationImpl implements StatNodeRegistration,EntityOwnershipListener {
65
66     private static final Logger LOG = LoggerFactory.getLogger(StatNodeRegistrationImpl.class);
67
68     private static final QName ENTITY_QNAME =
69             org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.controller.md.sal.core.general.entity.rev150820.Entity.QNAME;
70     private static final QName ENTITY_NAME = QName.create(ENTITY_QNAME, "name");
71
72     private final StatisticsManager manager;
73     private ListenerRegistration<?> notifListenerRegistration;
74     //private DataBroker db;
75     private EntityOwnershipListenerRegistration ofListenerRegistration = null;
76     private final Map<NodeId, Boolean> nodeOwnershipState = new ConcurrentHashMap();
77
78
79     public StatNodeRegistrationImpl(final StatisticsManager manager, final DataBroker db,
80             final NotificationProviderService notificationService) {
81         this.manager = Preconditions.checkNotNull(manager, "StatisticManager can not be null!");
82         //this.db = Preconditions.checkNotNull(db, "DataBroker can not be null!");
83         Preconditions.checkArgument(notificationService != null, "NotificationProviderService can not be null!");
84         notifListenerRegistration = notificationService.registerNotificationListener(this);
85
86         if(manager.getOwnershipService() != null) {
87             ofListenerRegistration = manager.getOwnershipService().registerListener("openflow", this);
88         }
89     }
90
91     @Override
92     public void close() throws Exception {
93
94         if (notifListenerRegistration != null) {
95             try {
96                 notifListenerRegistration.close();
97             }
98             catch (final Exception e) {
99                 LOG.warn("Error by stop FlowCapableNode Notification StatNodeRegistration. Exception {}", e);
100             }
101             notifListenerRegistration = null;
102         }
103
104         if (ofListenerRegistration!= null) {
105             try {
106                 ofListenerRegistration.close();
107             } catch (final Exception e) {
108                 LOG.warn("Error by stop FlowCapableNode EntityOwnershipListener.", e);
109             }
110             ofListenerRegistration = null;
111         }
112     }
113
114     @Override
115     public void connectFlowCapableNode(final InstanceIdentifier<SwitchFeatures> keyIdent,
116             final SwitchFeatures data, final InstanceIdentifier<Node> nodeIdent) {
117         Preconditions.checkNotNull(keyIdent, "InstanceIdentifier can not be null!");
118         Preconditions.checkNotNull(data, "SwitchFeatures data for {} can not be null!", keyIdent);
119         Preconditions.checkArgument(( ! keyIdent.isWildcarded()), "InstanceIdentifier is WildCarded!");
120
121         LOG.trace("STAT-MANAGER - connecting flow capable node {}", nodeIdent);
122         final List<StatCapabTypes> statCapabTypes = new ArrayList<>();
123         Short maxCapTables = Short.valueOf("1");
124
125         final List<Class<? extends FeatureCapability>> capabilities = data.getCapabilities() != null
126                 ? data.getCapabilities() : Collections.<Class<? extends FeatureCapability>> emptyList();
127         for (final Class<? extends FeatureCapability> capability : capabilities) {
128             if (FlowFeatureCapabilityTableStats.class.equals(capability)) {
129                 statCapabTypes.add(StatCapabTypes.TABLE_STATS);
130             } else if (FlowFeatureCapabilityFlowStats.class.equals(capability)) {
131                 statCapabTypes.add(StatCapabTypes.FLOW_STATS);
132             } else if (FlowFeatureCapabilityGroupStats.class.equals(capability)) {
133                 statCapabTypes.add(StatCapabTypes.GROUP_STATS);
134             } else if (FlowFeatureCapabilityPortStats.class.equals(capability)) {
135                 statCapabTypes.add(StatCapabTypes.PORT_STATS);
136             } else if (FlowFeatureCapabilityQueueStats.class.equals(capability)) {
137                 statCapabTypes.add(StatCapabTypes.QUEUE_STATS);
138             }
139         }
140         maxCapTables = data.getMaxTables();
141
142         final Optional<Short> maxTables = Optional.<Short> of(maxCapTables);
143         manager.connectedNodeRegistration(nodeIdent, Collections.unmodifiableList(statCapabTypes), maxTables.get());
144     }
145
146     @Override
147     public void disconnectFlowCapableNode(final InstanceIdentifier<Node> nodeIdent) {
148         Preconditions.checkArgument(nodeIdent != null, "InstanceIdentifier can not be NULL!");
149         Preconditions.checkArgument(( ! nodeIdent.isWildcarded()),
150                 "InstanceIdentifier {} is WildCarded!", nodeIdent);
151         LOG.trace("STAT-MANAGER - disconnect flow capable node {}", nodeIdent);
152         manager.disconnectedNodeUnregistration(nodeIdent);
153     }
154
155     private boolean preConfigurationCheck(final NodeId nodeId) {
156         Preconditions.checkNotNull(nodeId, "Node Instance Identifier can not be null!");
157         final Entity entity = getEntity(nodeId);
158         EntityOwnershipService ownershipService = manager.getOwnershipService();
159         if(ownershipService == null) {
160             LOG.error("preConfigurationCheck: EntityOwnershipService is null");
161             return false;
162         }
163         Optional<EntityOwnershipState> entityOwnershipStateOptional = ownershipService.getOwnershipState(entity);
164         if(!entityOwnershipStateOptional.isPresent()) { //abset - assume this ofp is owning entity
165             LOG.warn("preConfigurationCheck: Entity state of {} is absent - acting as a non-owner",nodeId.getValue());
166             return false;
167         }
168         final EntityOwnershipState entityOwnershipState = entityOwnershipStateOptional.get();
169         if(!(entityOwnershipState.hasOwner() && entityOwnershipState.isOwner())) {
170             LOG.info("preConfigurationCheck: Controller is not the owner of {}",nodeId.getValue());
171             return false;
172         }
173         return true;
174     }
175
176     @Override
177     public void onNodeConnectorRemoved(final NodeConnectorRemoved notification) {
178         // NOOP
179     }
180
181     @Override
182     public void onNodeConnectorUpdated(final NodeConnectorUpdated notification) {
183         // NOOP
184     }
185
186     @Override
187     public void onNodeRemoved(final NodeRemoved notification) {
188         Preconditions.checkNotNull(notification);
189         final NodeRef nodeRef = notification.getNodeRef();
190         final InstanceIdentifier<?> nodeRefIdent = nodeRef.getValue();
191         final InstanceIdentifier<Node> nodeIdent =
192                 nodeRefIdent.firstIdentifierOf(Node.class);
193         if (nodeIdent != null) {
194             LOG.debug("Received onNodeRemoved for node:{} ", nodeIdent);
195             removeOwnership(InstanceIdentifier.keyOf(nodeIdent).getId());
196             disconnectFlowCapableNode(nodeIdent);
197         }
198     }
199
200     @Override
201     public void onNodeUpdated(final NodeUpdated notification) {
202         Preconditions.checkNotNull(notification);
203         final FlowCapableNodeUpdated newFlowNode =
204                 notification.getAugmentation(FlowCapableNodeUpdated.class);
205         LOG.info("Received onNodeUpdated for node {} ", newFlowNode);
206         if (newFlowNode != null && newFlowNode.getSwitchFeatures() != null) {
207             final NodeRef nodeRef = notification.getNodeRef();
208             final InstanceIdentifier<?> nodeRefIdent = nodeRef.getValue();
209             final InstanceIdentifier<Node> nodeIdent =
210                     nodeRefIdent.firstIdentifierOf(Node.class);
211
212             final InstanceIdentifier<SwitchFeatures> swichFeaturesIdent =
213                     nodeIdent.augmentation(FlowCapableNode.class).child(SwitchFeatures.class);
214             final SwitchFeatures switchFeatures = newFlowNode.getSwitchFeatures();
215             connectFlowCapableNode(swichFeaturesIdent, switchFeatures, nodeIdent);
216
217             //Send group/meter request to get addition details not present in switch feature response.
218             NodeId nodeId = InstanceIdentifier.keyOf(nodeIdent).getId();
219             boolean ownershipState = preConfigurationCheck(nodeId);
220             setNodeOwnership(nodeId, ownershipState);
221             if(ownershipState) {
222                 LOG.info("onNodeUpdated: Send group/meter feature request to the device {}",nodeIdent);
223                 manager.getRpcMsgManager().getGroupFeaturesStat(nodeRef);
224                 manager.getRpcMsgManager().getMeterFeaturesStat(nodeRef);
225             }
226         }
227     }
228
229     @Override
230     public boolean isFlowCapableNodeOwner(NodeId node) {
231         if(this.nodeOwnershipState.containsKey(node)){
232             return this.nodeOwnershipState.get(node).booleanValue();
233         }
234         return false;
235     }
236
237
238     @Override
239     public void ownershipChanged(EntityOwnershipChange ownershipChange) {
240
241         YangInstanceIdentifier yId = ownershipChange.getEntity().getId();
242         NodeIdentifierWithPredicates niWPredicates = (NodeIdentifierWithPredicates)yId.getLastPathArgument();
243         Map<QName, Object> keyValMap = niWPredicates.getKeyValues();
244         String nodeIdStr = (String)(keyValMap.get(ENTITY_NAME));
245         BigInteger dpId = new BigInteger(nodeIdStr.split(":")[1]);
246         NodeId nodeId = new NodeId(nodeIdStr);
247         setNodeOwnership(nodeId, ownershipChange.isOwner());
248     }
249
250     private void setNodeOwnership(NodeId node, boolean ownership) {
251         this.nodeOwnershipState.put(node,ownership);
252     }
253
254     private void removeOwnership(NodeId node) {
255         this.nodeOwnershipState.remove(node);
256     }
257
258     private Entity getEntity(NodeId nodeId) {
259         return new Entity("openflow", nodeId.getValue());
260     }
261
262 }