Merge "Bug 6193 - Change in length of DatapathId of a switch"
[openflowplugin.git] / openflowplugin-impl / src / main / java / org / opendaylight / openflowplugin / impl / connection / ConnectionContextImpl.java
1 /**
2  * Copyright (c) 2015 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.impl.connection;
10
11 import com.google.common.base.Preconditions;
12 import java.math.BigInteger;
13 import java.net.InetSocketAddress;
14 import java.util.concurrent.Callable;
15 import java.util.concurrent.ExecutionException;
16 import java.util.concurrent.Executors;
17 import java.util.concurrent.Future;
18 import java.util.concurrent.TimeUnit;
19 import java.util.concurrent.TimeoutException;
20 import org.opendaylight.openflowjava.protocol.api.connection.ConnectionAdapter;
21 import org.opendaylight.openflowjava.protocol.api.connection.OutboundQueue;
22 import org.opendaylight.openflowjava.protocol.api.connection.OutboundQueueHandlerRegistration;
23 import org.opendaylight.openflowplugin.api.openflow.connection.ConnectionContext;
24 import org.opendaylight.openflowplugin.api.openflow.connection.HandshakeContext;
25 import org.opendaylight.openflowplugin.api.openflow.connection.OutboundQueueProvider;
26 import org.opendaylight.openflowplugin.api.openflow.device.DeviceInfo;
27 import org.opendaylight.openflowplugin.api.openflow.device.handlers.DeviceDisconnectedHandler;
28 import org.opendaylight.openflowplugin.impl.statistics.ofpspecific.SessionStatistics;
29 import org.opendaylight.openflowplugin.impl.util.DeviceStateUtil;
30 import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.NodeId;
31 import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.nodes.Node;
32 import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.nodes.NodeKey;
33 import org.opendaylight.yang.gen.v1.urn.opendaylight.openflow.protocol.rev130731.FeaturesReply;
34 import org.opendaylight.yangtools.yang.binding.KeyedInstanceIdentifier;
35 import org.slf4j.Logger;
36 import org.slf4j.LoggerFactory;
37
38 /**
39  *
40  */
41 public class ConnectionContextImpl implements ConnectionContext {
42
43     private final ConnectionAdapter connectionAdapter;
44     private volatile CONNECTION_STATE connectionState;
45     private FeaturesReply featuresReply;
46     private NodeId nodeId;
47     private DeviceDisconnectedHandler deviceDisconnectedHandler;
48     private static final Logger LOG = LoggerFactory.getLogger(ConnectionContextImpl.class);
49     private OutboundQueueProvider outboundQueueProvider;
50     private OutboundQueueHandlerRegistration<OutboundQueueProvider> outboundQueueHandlerRegistration;
51     private HandshakeContext handshakeContext;
52     private DeviceInfo deviceInfo;
53
54     /**
55      * @param connectionAdapter
56      */
57     public ConnectionContextImpl(final ConnectionAdapter connectionAdapter) {
58         this.connectionAdapter = connectionAdapter;
59     }
60
61     @Override
62     public ConnectionAdapter getConnectionAdapter() {
63         return connectionAdapter;
64     }
65
66     @Override
67     public OutboundQueue getOutboundQueueProvider() {
68         return this.outboundQueueProvider;
69     }
70
71     @Override
72     public void setOutboundQueueProvider(final OutboundQueueProvider outboundQueueProvider) {
73         this.outboundQueueProvider = outboundQueueProvider;
74     }
75
76     @Override
77     public CONNECTION_STATE getConnectionState() {
78         return connectionState;
79     }
80
81     @Override
82     public NodeId getNodeId() {
83         return nodeId;
84     }
85
86     @Override
87     public void setNodeId(final NodeId nodeId) {
88         this.nodeId = nodeId;
89     }
90
91     @Override
92     public FeaturesReply getFeatures() {
93         return featuresReply;
94     }
95
96     @Override
97     public void setDeviceDisconnectedHandler(final DeviceDisconnectedHandler deviceDisconnectedHandler) {
98         this.deviceDisconnectedHandler = deviceDisconnectedHandler;
99     }
100
101     @Override
102     public void setFeatures(final FeaturesReply featuresReply) {
103         this.featuresReply = featuresReply;
104     }
105
106     @Override
107     public void closeConnection(final boolean propagate) {
108         if (null == nodeId){
109             SessionStatistics.countEvent(connectionAdapter.getRemoteAddress().toString(), SessionStatistics.ConnectionStatus.CONNECTION_DISCONNECTED_BY_OFP);
110         } else {
111             SessionStatistics.countEvent(nodeId.toString(), SessionStatistics.ConnectionStatus.CONNECTION_DISCONNECTED_BY_OFP);
112         }
113         final BigInteger datapathId = featuresReply != null ? featuresReply.getDatapathId() : BigInteger.ZERO;
114         LOG.debug("Actively closing connection: {}, datapathId: {}",
115                 connectionAdapter.getRemoteAddress(), datapathId);
116         connectionState = ConnectionContext.CONNECTION_STATE.RIP;
117
118         Future<Void> future = Executors.newSingleThreadExecutor().submit(new Callable<Void>() {
119             @Override
120             public Void call() throws Exception {
121                 unregisterOutboundQueue();
122                 return null;
123             }
124         });
125         try {
126             future.get(1, TimeUnit.SECONDS);
127             LOG.info("Unregister outbound queue successful.");
128         } catch (InterruptedException | TimeoutException | ExecutionException e) {
129             LOG.warn("Unregister outbound queue throws exception for node {} ", nodeId);
130             LOG.trace("Unregister outbound queue throws exception for node {} ", nodeId, e);
131         }
132
133         closeHandshakeContext();
134
135         if (getConnectionAdapter().isAlive()) {
136             getConnectionAdapter().disconnect();
137         }
138
139         if (propagate) {
140             LOG.debug("Propagating device disconnect for node {}", nodeId);
141             propagateDeviceDisconnectedEvent();
142         } else {
143             LOG.debug("Close connection without propagating for node {}", nodeId);
144         }
145     }
146
147     private void closeHandshakeContext() {
148         LOG.debug("Trying closing handshake context for node {}", nodeId);
149         if (handshakeContext != null) {
150             try {
151                 handshakeContext.close();
152             } catch (Exception e) {
153                 LOG.error("handshake context closing failed:{} ", e);
154             } finally {
155                 handshakeContext = null;
156             }
157         }
158     }
159
160     @Override
161     public void onConnectionClosed() {
162         if (null == nodeId){
163             SessionStatistics.countEvent(connectionAdapter.getRemoteAddress().toString(), SessionStatistics.ConnectionStatus.CONNECTION_DISCONNECTED_BY_DEVICE);
164         } else {
165             SessionStatistics.countEvent(nodeId.toString(), SessionStatistics.ConnectionStatus.CONNECTION_DISCONNECTED_BY_DEVICE);
166         }
167         connectionState = ConnectionContext.CONNECTION_STATE.RIP;
168
169         final InetSocketAddress remoteAddress = connectionAdapter.getRemoteAddress();
170         final Short auxiliaryId;
171         if (null != getFeatures() && null != getFeatures().getAuxiliaryId()) {
172             auxiliaryId = getFeatures().getAuxiliaryId();
173         } else {
174             auxiliaryId = 0;
175         }
176
177         LOG.debug("disconnecting: node={}|auxId={}|connection state = {}",
178                 remoteAddress,
179                 auxiliaryId,
180                 getConnectionState());
181
182         unregisterOutboundQueue();
183         closeHandshakeContext();
184         propagateDeviceDisconnectedEvent();
185     }
186
187     private void propagateDeviceDisconnectedEvent() {
188         if (null != deviceDisconnectedHandler) {
189             final BigInteger datapathId = featuresReply != null ? featuresReply.getDatapathId() : BigInteger.ZERO;
190             LOG.debug("Propagating connection closed event: {}, datapathId:{}.",
191                     connectionAdapter.getRemoteAddress(), datapathId);
192             deviceDisconnectedHandler.onDeviceDisconnected(this);
193         }
194     }
195
196     @Override
197     public void setOutboundQueueHandleRegistration(OutboundQueueHandlerRegistration<OutboundQueueProvider> outboundQueueHandlerRegistration) {
198         this.outboundQueueHandlerRegistration = outboundQueueHandlerRegistration;
199     }
200
201     private void unregisterOutboundQueue() {
202         LOG.debug("Trying unregister outbound queue handler registration for node {}", nodeId);
203         if (outboundQueueHandlerRegistration != null) {
204             outboundQueueHandlerRegistration.close();
205             outboundQueueHandlerRegistration = null;
206         }
207     }
208
209     @Override
210     public synchronized void changeStateToHandshaking() {
211         connectionState = CONNECTION_STATE.HANDSHAKING;
212     }
213
214     @Override
215     public synchronized void changeStateToTimeouting() {
216         connectionState = CONNECTION_STATE.TIMEOUTING;
217     }
218
219     @Override
220     public synchronized void changeStateToWorking() {
221         connectionState = CONNECTION_STATE.WORKING;
222     }
223
224     @Override
225     public DeviceInfo getDeviceInfo() {
226         return this.deviceInfo;
227     }
228
229     @Override
230     public void handshakeSuccessful() {
231         Preconditions.checkNotNull(nodeId, "Cannot create DeviceInfo if 'NodeId' is not set!");
232         Preconditions.checkNotNull(featuresReply, "Cannot create DeviceInfo if 'features' is not set!");
233         this.deviceInfo = new DeviceInfoImpl(
234                 nodeId,
235                 DeviceStateUtil.createNodeInstanceIdentifier(nodeId),
236                 featuresReply.getVersion(),
237                 featuresReply.getDatapathId());
238     }
239
240     @Override
241     public void setHandshakeContext(HandshakeContext handshakeContext) {
242         this.handshakeContext = handshakeContext;
243     }
244
245
246     private class DeviceInfoImpl implements DeviceInfo {
247
248         final private NodeId nodeId;
249         final private KeyedInstanceIdentifier<Node, NodeKey> nodeII;
250         final private Short version;
251         final private BigInteger datapathId;
252
253         DeviceInfoImpl(
254                 final NodeId nodeId,
255                 final KeyedInstanceIdentifier<Node, NodeKey> nodeII,
256                 final Short version,
257                 final BigInteger datapathId) {
258             this.nodeId = nodeId;
259             this.nodeII = nodeII;
260             this.version = version;
261             this.datapathId = datapathId;
262         }
263
264         @Override
265         public NodeId getNodeId() {
266             return nodeId;
267         }
268
269         @Override
270         public KeyedInstanceIdentifier<Node, NodeKey> getNodeInstanceIdentifier() {
271             return nodeII;
272         }
273
274         @Override
275         public Short getVersion() {
276             return version;
277         }
278
279         @Override
280         public BigInteger getDatapathId() {
281             return datapathId;
282         }
283
284         @Override
285         public boolean equals(Object o) {
286             if (this == o) {
287                 return true;
288             }
289
290             if (o == null || getClass() != o.getClass()) {
291                 return false;
292             }
293
294             DeviceInfoImpl that = (DeviceInfoImpl) o;
295
296             return  (nodeId.equals(that.nodeId) &&
297                     nodeII.equals(that.nodeII) &&
298                     version.equals(that.version) &&
299                     datapathId.equals(that.datapathId));
300
301         }
302
303         @Override
304         public int hashCode() {
305             int result = nodeId.hashCode();
306             result = 31 * result + nodeII.hashCode();
307             result = 31 * result + version.hashCode();
308             result = 31 * result + datapathId.hashCode();
309             return result;
310         }
311     }
312 }