BUG-3774: 100k flows initial stats fail - fix
[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 java.math.BigInteger;
12 import java.net.InetSocketAddress;
13 import org.opendaylight.openflowjava.protocol.api.connection.ConnectionAdapter;
14 import org.opendaylight.openflowjava.protocol.api.connection.OutboundQueue;
15 import org.opendaylight.openflowjava.protocol.api.connection.OutboundQueueHandlerRegistration;
16 import org.opendaylight.openflowplugin.api.openflow.connection.ConnectionContext;
17 import org.opendaylight.openflowplugin.api.openflow.connection.HandshakeContext;
18 import org.opendaylight.openflowplugin.api.openflow.connection.OutboundQueueProvider;
19 import org.opendaylight.openflowplugin.api.openflow.device.handlers.DeviceDisconnectedHandler;
20 import org.opendaylight.openflowplugin.impl.statistics.ofpspecific.SessionStatistics;
21 import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.NodeId;
22 import org.opendaylight.yang.gen.v1.urn.opendaylight.openflow.protocol.rev130731.FeaturesReply;
23 import org.slf4j.Logger;
24 import org.slf4j.LoggerFactory;
25
26 /**
27  *
28  */
29 public class ConnectionContextImpl implements ConnectionContext {
30
31     private final ConnectionAdapter connectionAdapter;
32     private volatile CONNECTION_STATE connectionState;
33     private FeaturesReply featuresReply;
34     private NodeId nodeId;
35     private DeviceDisconnectedHandler deviceDisconnectedHandler;
36     private static final Logger LOG = LoggerFactory.getLogger(ConnectionContextImpl.class);
37     private OutboundQueueProvider outboundQueueProvider;
38     private OutboundQueueHandlerRegistration<OutboundQueueProvider> outboundQueueHandlerRegistration;
39     private HandshakeContext handshakeContext;
40
41     /**
42      * @param connectionAdapter
43      */
44     public ConnectionContextImpl(final ConnectionAdapter connectionAdapter) {
45         this.connectionAdapter = connectionAdapter;
46     }
47
48     @Override
49     public ConnectionAdapter getConnectionAdapter() {
50         return connectionAdapter;
51     }
52
53     @Override
54     public OutboundQueue getOutboundQueueProvider() {
55         return this.outboundQueueProvider;
56     }
57
58     @Override
59     public void setOutboundQueueProvider(final OutboundQueueProvider outboundQueueProvider) {
60         this.outboundQueueProvider = outboundQueueProvider;
61     }
62
63     @Override
64     public CONNECTION_STATE getConnectionState() {
65         return connectionState;
66     }
67
68     @Override
69     public NodeId getNodeId() {
70         return nodeId;
71     }
72
73     @Override
74     public void setNodeId(final NodeId nodeId) {
75         this.nodeId = nodeId;
76     }
77
78     @Override
79     public FeaturesReply getFeatures() {
80         return featuresReply;
81     }
82
83     @Override
84     public void setDeviceDisconnectedHandler(final DeviceDisconnectedHandler deviceDisconnectedHandler) {
85         this.deviceDisconnectedHandler = deviceDisconnectedHandler;
86     }
87
88     @Override
89     public void setFeatures(final FeaturesReply featuresReply) {
90         this.featuresReply = featuresReply;
91     }
92
93     @Override
94     public void closeConnection(boolean propagate) {
95         if (null == nodeId){
96             SessionStatistics.countEvent(connectionAdapter.getRemoteAddress().toString(), SessionStatistics.ConnectionStatus.CONNECTION_DISCONNECTED_BY_OFP);
97         } else {
98             SessionStatistics.countEvent(nodeId.toString(), SessionStatistics.ConnectionStatus.CONNECTION_DISCONNECTED_BY_OFP);
99         }
100         final BigInteger datapathId = featuresReply != null ? featuresReply.getDatapathId() : BigInteger.ZERO;
101         LOG.debug("Actively closing connection: {}, datapathId:{}.",
102                 connectionAdapter.getRemoteAddress(), datapathId);
103         connectionState = ConnectionContext.CONNECTION_STATE.RIP;
104
105         unregisterOutboundQueue();
106         closeHandshakeContext();
107
108         if (getConnectionAdapter().isAlive()) {
109             getConnectionAdapter().disconnect();
110         }
111
112         if (propagate) {
113             propagateDeviceDisconnectedEvent();
114         }
115     }
116
117     private void closeHandshakeContext() {
118         if (handshakeContext != null) {
119             try {
120                 handshakeContext.close();
121             } catch (Exception e) {
122                 LOG.info("handshake context closing failed: ", e);
123             } finally {
124                 handshakeContext = null;
125             }
126         }
127     }
128
129     @Override
130     public void onConnectionClosed() {
131         if (null == nodeId){
132             SessionStatistics.countEvent(connectionAdapter.getRemoteAddress().toString(), SessionStatistics.ConnectionStatus.CONNECTION_DISCONNECTED_BY_DEVICE);
133         } else {
134             SessionStatistics.countEvent(nodeId.toString(), SessionStatistics.ConnectionStatus.CONNECTION_DISCONNECTED_BY_DEVICE);
135         }
136         connectionState = ConnectionContext.CONNECTION_STATE.RIP;
137
138         final InetSocketAddress remoteAddress = connectionAdapter.getRemoteAddress();
139         final Short auxiliaryId;
140         if (null != getFeatures() && null != getFeatures().getAuxiliaryId()) {
141             auxiliaryId = getFeatures().getAuxiliaryId();
142         } else {
143             auxiliaryId = 0;
144         }
145
146         LOG.debug("disconnecting: node={}|auxId={}|connection state = {}",
147                 remoteAddress,
148                 auxiliaryId,
149                 getConnectionState());
150
151         unregisterOutboundQueue();
152         closeHandshakeContext();
153         propagateDeviceDisconnectedEvent();
154     }
155
156     private void propagateDeviceDisconnectedEvent() {
157         if (null != deviceDisconnectedHandler) {
158             final BigInteger datapathId = featuresReply != null ? featuresReply.getDatapathId() : BigInteger.ZERO;
159             LOG.debug("Propagating connection closed event: {}, datapathId:{}.",
160                     connectionAdapter.getRemoteAddress(), datapathId);
161             deviceDisconnectedHandler.onDeviceDisconnected(this);
162         }
163     }
164
165     @Override
166     public void setOutboundQueueHandleRegistration(OutboundQueueHandlerRegistration<OutboundQueueProvider> outboundQueueHandlerRegistration) {
167         this.outboundQueueHandlerRegistration = outboundQueueHandlerRegistration;
168     }
169
170     private void unregisterOutboundQueue() {
171         if (outboundQueueHandlerRegistration != null) {
172             outboundQueueHandlerRegistration.close();
173             outboundQueueHandlerRegistration = null;
174         }
175     }
176
177     @Override
178     public synchronized void changeStateToHandshaking() {
179         connectionState = CONNECTION_STATE.HANDSHAKING;
180     }
181
182     @Override
183     public synchronized void changeStateToTimeouting() {
184         connectionState = CONNECTION_STATE.TIMEOUTING;
185     }
186
187     @Override
188     public synchronized void changeStateToWorking() {
189         connectionState = CONNECTION_STATE.WORKING;
190     }
191
192     @Override
193     public void setHandshakeContext(HandshakeContext handshakeContext) {
194         this.handshakeContext = handshakeContext;
195     }
196 }