Merge "Clustering support for existing design (FRM,IM,SM) - add retry mechanisms...
[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 import java.util.ArrayList;
14 import java.util.Collections;
15 import java.util.List;
16 import org.opendaylight.controller.md.sal.binding.api.DataBroker;
17 import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.NodeId;
18 import org.opendaylight.controller.md.sal.common.api.clustering.Entity;
19 import org.opendaylight.controller.md.sal.common.api.clustering.EntityOwnershipChange;
20 import org.opendaylight.controller.md.sal.common.api.clustering.EntityOwnershipService;
21 import org.opendaylight.controller.md.sal.common.api.clustering.EntityOwnershipState;
22 import org.opendaylight.controller.md.sal.common.api.clustering.EntityOwnershipListener;
23 import org.opendaylight.controller.md.sal.common.api.clustering.EntityOwnershipListenerRegistration;
24 import org.opendaylight.controller.sal.binding.api.NotificationProviderService;
25 import org.opendaylight.openflowplugin.applications.statistics.manager.StatNodeRegistration;
26 import org.opendaylight.openflowplugin.applications.statistics.manager.StatPermCollector.StatCapabTypes;
27 import org.opendaylight.openflowplugin.applications.statistics.manager.StatisticsManager;
28 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.FeatureCapability;
29 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.FlowCapableNode;
30 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.FlowCapableNodeUpdated;
31 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.FlowFeatureCapabilityFlowStats;
32 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.FlowFeatureCapabilityGroupStats;
33 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.FlowFeatureCapabilityPortStats;
34 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.FlowFeatureCapabilityQueueStats;
35 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.FlowFeatureCapabilityTableStats;
36 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.flow.node.SwitchFeatures;
37 import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.NodeConnectorRemoved;
38 import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.NodeConnectorUpdated;
39 import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.NodeRef;
40 import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.NodeRemoved;
41 import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.NodeUpdated;
42 import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.nodes.Node;
43 import org.opendaylight.yangtools.concepts.ListenerRegistration;
44 import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
45 import org.slf4j.Logger;
46 import org.slf4j.LoggerFactory;
47
48 /**
49  * statistics-manager
50  * org.opendaylight.openflowplugin.applications.statistics.manager.impl
51  *
52  * @author <a href="mailto:vdemcak@cisco.com">Vaclav Demcak</a>
53  *
54  * Created: Aug 28, 2014
55  */
56 public class StatNodeRegistrationImpl implements StatNodeRegistration,EntityOwnershipListener {
57
58     private static final Logger LOG = LoggerFactory.getLogger(StatNodeRegistrationImpl.class);
59
60     private final StatisticsManager manager;
61     private ListenerRegistration<?> notifListenerRegistration;
62     //private DataBroker db;
63     private EntityOwnershipListenerRegistration ofListenerRegistration = null;
64
65     public StatNodeRegistrationImpl(final StatisticsManager manager, final DataBroker db,
66             final NotificationProviderService notificationService) {
67         this.manager = Preconditions.checkNotNull(manager, "StatisticManager can not be null!");
68         //this.db = Preconditions.checkNotNull(db, "DataBroker can not be null!");
69         Preconditions.checkArgument(notificationService != null, "NotificationProviderService can not be null!");
70         notifListenerRegistration = notificationService.registerNotificationListener(this);
71
72         if(manager.getOwnershipService() != null) {
73             ofListenerRegistration = manager.getOwnershipService().registerListener("openflow", this);
74         }
75     }
76
77     @Override
78     public void close() throws Exception {
79
80         if (notifListenerRegistration != null) {
81             try {
82                 notifListenerRegistration.close();
83             }
84             catch (final Exception e) {
85                 LOG.warn("Error by stop FlowCapableNode Notification StatNodeRegistration. Exception {}", e);
86             }
87             notifListenerRegistration = null;
88         }
89
90         if (ofListenerRegistration!= null) {
91             try {
92                 ofListenerRegistration.close();
93             } catch (final Exception e) {
94                 LOG.warn("Error by stop FlowCapableNode EntityOwnershipListener.", e);
95             }
96             ofListenerRegistration = null;
97         }
98     }
99
100     @Override
101     public void connectFlowCapableNode(final InstanceIdentifier<SwitchFeatures> keyIdent,
102             final SwitchFeatures data, final InstanceIdentifier<Node> nodeIdent) {
103         Preconditions.checkNotNull(keyIdent, "InstanceIdentifier can not be null!");
104         Preconditions.checkNotNull(data, "SwitchFeatures data for {} can not be null!", keyIdent);
105         Preconditions.checkArgument(( ! keyIdent.isWildcarded()), "InstanceIdentifier is WildCarded!");
106
107         LOG.trace("STAT-MANAGER - connecting flow capable node {}", nodeIdent);
108         final List<StatCapabTypes> statCapabTypes = new ArrayList<>();
109         Short maxCapTables = Short.valueOf("1");
110
111         final List<Class<? extends FeatureCapability>> capabilities = data.getCapabilities() != null
112                 ? data.getCapabilities() : Collections.<Class<? extends FeatureCapability>> emptyList();
113         for (final Class<? extends FeatureCapability> capability : capabilities) {
114             if (FlowFeatureCapabilityTableStats.class.equals(capability)) {
115                 statCapabTypes.add(StatCapabTypes.TABLE_STATS);
116             } else if (FlowFeatureCapabilityFlowStats.class.equals(capability)) {
117                 statCapabTypes.add(StatCapabTypes.FLOW_STATS);
118             } else if (FlowFeatureCapabilityGroupStats.class.equals(capability)) {
119                 statCapabTypes.add(StatCapabTypes.GROUP_STATS);
120             } else if (FlowFeatureCapabilityPortStats.class.equals(capability)) {
121                 statCapabTypes.add(StatCapabTypes.PORT_STATS);
122             } else if (FlowFeatureCapabilityQueueStats.class.equals(capability)) {
123                 statCapabTypes.add(StatCapabTypes.QUEUE_STATS);
124             }
125         }
126         maxCapTables = data.getMaxTables();
127
128         final Optional<Short> maxTables = Optional.<Short> of(maxCapTables);
129         manager.connectedNodeRegistration(nodeIdent, Collections.unmodifiableList(statCapabTypes), maxTables.get());
130     }
131
132     @Override
133     public void disconnectFlowCapableNode(final InstanceIdentifier<Node> nodeIdent) {
134         Preconditions.checkArgument(nodeIdent != null, "InstanceIdentifier can not be NULL!");
135         Preconditions.checkArgument(( ! nodeIdent.isWildcarded()),
136                 "InstanceIdentifier {} is WildCarded!", nodeIdent);
137         LOG.trace("STAT-MANAGER - disconnect flow capable node {}", nodeIdent);
138         manager.disconnectedNodeUnregistration(nodeIdent);
139     }
140
141     private boolean preConfigurationCheck(final InstanceIdentifier<Node> nodeIdent) {
142         Preconditions.checkNotNull(nodeIdent, "Node Instance Identifier can not be null!");
143         NodeId nodeId = InstanceIdentifier.keyOf(nodeIdent).getId();
144         final Entity entity = new Entity("openflow", nodeId.getValue());
145         EntityOwnershipService ownershipService = manager.getOwnershipService();
146         if(ownershipService == null) {
147             LOG.error("preConfigurationCheck: EntityOwnershipService is null");
148             return false;
149         }
150         Optional<EntityOwnershipState> entityOwnershipStateOptional = ownershipService.getOwnershipState(entity);
151         if(!entityOwnershipStateOptional.isPresent()) { //abset - assume this ofp is owning entity
152             LOG.warn("preConfigurationCheck: Entity state of {} is absent - acting as a non-owner",nodeId.getValue());
153             return false;
154         }
155         final EntityOwnershipState entityOwnershipState = entityOwnershipStateOptional.get();
156         if(!(entityOwnershipState.hasOwner() && entityOwnershipState.isOwner())) {
157             LOG.info("preConfigurationCheck: Controller is not the owner of {}",nodeId.getValue());
158             return false;
159         }
160         return true;
161     }
162
163     @Override
164     public void onNodeConnectorRemoved(final NodeConnectorRemoved notification) {
165         // NOOP
166     }
167
168     @Override
169     public void onNodeConnectorUpdated(final NodeConnectorUpdated notification) {
170         // NOOP
171     }
172
173     @Override
174     public void onNodeRemoved(final NodeRemoved notification) {
175         Preconditions.checkNotNull(notification);
176         final NodeRef nodeRef = notification.getNodeRef();
177         final InstanceIdentifier<?> nodeRefIdent = nodeRef.getValue();
178         final InstanceIdentifier<Node> nodeIdent =
179                 nodeRefIdent.firstIdentifierOf(Node.class);
180         if (nodeIdent != null) {
181             LOG.debug("Received onNodeRemoved for node:{} ", nodeIdent);
182             disconnectFlowCapableNode(nodeIdent);
183         }
184     }
185
186     @Override
187     public void onNodeUpdated(final NodeUpdated notification) {
188         Preconditions.checkNotNull(notification);
189         final FlowCapableNodeUpdated newFlowNode =
190                 notification.getAugmentation(FlowCapableNodeUpdated.class);
191         LOG.info("Received onNodeUpdated for node {} ", newFlowNode);
192         if (newFlowNode != null && newFlowNode.getSwitchFeatures() != null) {
193             final NodeRef nodeRef = notification.getNodeRef();
194             final InstanceIdentifier<?> nodeRefIdent = nodeRef.getValue();
195             final InstanceIdentifier<Node> nodeIdent =
196                     nodeRefIdent.firstIdentifierOf(Node.class);
197
198             final InstanceIdentifier<SwitchFeatures> swichFeaturesIdent =
199                     nodeIdent.augmentation(FlowCapableNode.class).child(SwitchFeatures.class);
200             final SwitchFeatures switchFeatures = newFlowNode.getSwitchFeatures();
201             connectFlowCapableNode(swichFeaturesIdent, switchFeatures, nodeIdent);
202
203             //Send group/meter request to get addition details not present in switch feature response.
204             if(preConfigurationCheck(nodeIdent)) {
205                 LOG.info("onNodeUpdated: Send group/meter feature request to the device {}",nodeIdent);
206                 manager.getRpcMsgManager().getGroupFeaturesStat(nodeRef);
207                 manager.getRpcMsgManager().getMeterFeaturesStat(nodeRef);
208             }
209         }
210     }
211
212     @Override
213     public void ownershipChanged(EntityOwnershipChange ownershipChange) {
214         //I believe the only scenario we need to handle here is
215         // isOwner=false && hasOwner=false. E.g switch is connected to only
216         // one controller and that goes down, all other controller will get
217         // notification about ownership change with the flag set as above.
218         // In this scenario, topology manager should remove the node from
219         // operational data store, so no explict action is required here.
220     }
221
222 }