2 * Copyright (c) 2015 Cisco Systems, Inc. and others. All rights reserved.
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
8 package org.opendaylight.openflowplugin.impl.connection;
10 import com.google.common.base.MoreObjects;
11 import com.google.common.base.Preconditions;
12 import java.util.ArrayList;
13 import java.util.Collections;
14 import java.util.List;
15 import org.opendaylight.mdsal.singleton.common.api.ServiceGroupIdentifier;
16 import org.opendaylight.openflowjava.protocol.api.connection.ConnectionAdapter;
17 import org.opendaylight.openflowjava.protocol.api.connection.OutboundQueue;
18 import org.opendaylight.openflowjava.protocol.api.connection.OutboundQueueHandlerRegistration;
19 import org.opendaylight.openflowplugin.api.openflow.connection.ConnectionContext;
20 import org.opendaylight.openflowplugin.api.openflow.connection.DeviceConnectionStatusProvider;
21 import org.opendaylight.openflowplugin.api.openflow.connection.HandshakeContext;
22 import org.opendaylight.openflowplugin.api.openflow.connection.OutboundQueueProvider;
23 import org.opendaylight.openflowplugin.api.openflow.device.DeviceInfo;
24 import org.opendaylight.openflowplugin.api.openflow.device.handlers.DeviceDisconnectedHandler;
25 import org.opendaylight.openflowplugin.impl.statistics.ofpspecific.SessionStatistics;
26 import org.opendaylight.openflowplugin.impl.util.DeviceStateUtil;
27 import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.NodeId;
28 import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.nodes.Node;
29 import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.nodes.NodeKey;
30 import org.opendaylight.yang.gen.v1.urn.opendaylight.openflow.protocol.rev130731.FeaturesReply;
31 import org.opendaylight.yang.gen.v1.urn.opendaylight.openflow.protocol.rev130731.PortStatusMessage;
32 import org.opendaylight.yangtools.yang.binding.KeyedInstanceIdentifier;
33 import org.opendaylight.yangtools.yang.common.Uint64;
34 import org.opendaylight.yangtools.yang.common.Uint8;
35 import org.slf4j.Logger;
36 import org.slf4j.LoggerFactory;
38 public class ConnectionContextImpl implements ConnectionContext {
40 private final ConnectionAdapter connectionAdapter;
41 private volatile CONNECTION_STATE connectionState;
42 private FeaturesReply featuresReply;
43 private NodeId nodeId;
44 private DeviceDisconnectedHandler deviceDisconnectedHandler;
45 private static final Logger LOG = LoggerFactory.getLogger(ConnectionContextImpl.class);
46 private OutboundQueueProvider outboundQueueProvider;
47 private OutboundQueueHandlerRegistration<OutboundQueueProvider> outboundQueueHandlerRegistration;
48 private HandshakeContext handshakeContext;
49 private DeviceInfo deviceInfo;
50 private final List<PortStatusMessage> portStatusMessages = new ArrayList<>();
51 private final DeviceConnectionStatusProvider deviceConnectionStatusProvider;
56 * @param connectionAdapter - connection adapter
58 public ConnectionContextImpl(final ConnectionAdapter connectionAdapter,
59 final DeviceConnectionStatusProvider deviceConnectionStatusProvider) {
60 this.connectionAdapter = connectionAdapter;
61 this.deviceConnectionStatusProvider = deviceConnectionStatusProvider;
65 public ConnectionAdapter getConnectionAdapter() {
66 return connectionAdapter;
70 public OutboundQueue getOutboundQueueProvider() {
71 return this.outboundQueueProvider;
75 public void setOutboundQueueProvider(final OutboundQueueProvider outboundQueueProvider) {
76 this.outboundQueueProvider = outboundQueueProvider;
77 ((DeviceInfoImpl)this.deviceInfo).setOutboundQueueProvider(this.outboundQueueProvider);
81 public CONNECTION_STATE getConnectionState() {
82 return connectionState;
86 public NodeId getNodeId() {
91 public void setNodeId(final NodeId nodeId) {
96 public FeaturesReply getFeatures() {
101 public void setDeviceDisconnectedHandler(final DeviceDisconnectedHandler deviceDisconnectedHandler) {
102 this.deviceDisconnectedHandler = deviceDisconnectedHandler;
106 public void setFeatures(final FeaturesReply newFeaturesReply) {
107 this.featuresReply = newFeaturesReply;
111 public void closeConnection(final boolean propagate) {
112 disconnectDevice(propagate, true);
115 private void closeHandshakeContext() {
116 LOG.debug("Trying closing handshake context for node {}", getSafeNodeIdForLOG());
117 if (handshakeContext != null) {
118 handshakeContext.close();
119 handshakeContext = null;
124 public void onConnectionClosed() {
125 disconnectDevice(true, false);
128 private void disconnectDevice(final boolean propagate,
129 final boolean forced) {
130 final String device = nodeId != null ? nodeId.getValue() : getConnectionAdapter().getRemoteAddress().toString();
132 final Uint8 auxiliaryId;
133 if (featuresReply != null) {
134 final Uint8 id = featuresReply.getAuxiliaryId();
135 auxiliaryId = id == null ? Uint8.ZERO : id;
137 auxiliaryId = Uint8.ZERO;
140 if (connectionState == CONNECTION_STATE.RIP) {
141 LOG.debug("Connection for device {} with auxiliary ID {} is already {}, so skipping closing.",
142 device, auxiliaryId, getConnectionState());
146 connectionState = ConnectionContext.CONNECTION_STATE.RIP;
148 SessionStatistics.countEvent(device, forced
149 ? SessionStatistics.ConnectionStatus.CONNECTION_DISCONNECTED_BY_OFP
150 : SessionStatistics.ConnectionStatus.CONNECTION_DISCONNECTED_BY_DEVICE);
152 LOG.debug("{}: device={} | auxiliaryId={} | connectionState={}",
153 forced ? "Actively closing connection" : "Disconnecting",
156 getConnectionState());
158 portStatusMessages.clear();
159 unregisterOutboundQueue();
160 closeHandshakeContext();
162 if (forced && getConnectionAdapter().isAlive()) {
163 getConnectionAdapter().disconnect();
167 propagateDeviceDisconnectedEvent();
171 private void propagateDeviceDisconnectedEvent() {
172 if (deviceDisconnectedHandler != null) {
173 final Uint64 datapathId = featuresReply != null ? featuresReply.getDatapathId() : Uint64.ZERO;
174 if (LOG.isDebugEnabled()) {
175 LOG.debug("Propagating connection closed event: {}, datapathId:{}.",
176 connectionAdapter.getRemoteAddress(), datapathId);
178 deviceDisconnectedHandler.onDeviceDisconnected(this);
183 * Get safe nodeId for logging.
185 * @return string value od nodeId or string "null"
188 public String getSafeNodeIdForLOG() {
189 return nodeId == null ? "null" : nodeId.getValue();
193 public void setOutboundQueueHandleRegistration(
194 final OutboundQueueHandlerRegistration<OutboundQueueProvider> newRegistration) {
195 this.outboundQueueHandlerRegistration = newRegistration;
198 private void unregisterOutboundQueue() {
199 if (LOG.isDebugEnabled()) {
200 LOG.debug("Trying unregister outbound queue handler registration for node {}", getSafeNodeIdForLOG());
202 if (outboundQueueHandlerRegistration != null) {
203 outboundQueueHandlerRegistration.close();
204 outboundQueueHandlerRegistration = null;
209 public synchronized void changeStateToHandshaking() {
210 connectionState = CONNECTION_STATE.HANDSHAKING;
214 public synchronized void changeStateToTimeouting() {
215 connectionState = CONNECTION_STATE.TIMEOUTING;
219 public synchronized void changeStateToWorking() {
220 connectionState = CONNECTION_STATE.WORKING;
224 public void handlePortStatusMessage(final PortStatusMessage portStatusMessage) {
225 LOG.info("Received early port status message for node {} with reason {} and state {}",
226 getSafeNodeIdForLOG(),
227 portStatusMessage.getReason(),
228 MoreObjects.firstNonNull(portStatusMessage.getState(), portStatusMessage.getStateV10()));
230 LOG.debug("Early port status message body is {}", portStatusMessage);
231 portStatusMessages.add(portStatusMessage);
235 public List<PortStatusMessage> retrieveAndClearPortStatusMessages() {
236 final List<PortStatusMessage> immutablePortStatusMessages = Collections.unmodifiableList(portStatusMessages);
237 portStatusMessages.clear();
238 return immutablePortStatusMessages;
242 public DeviceInfo getDeviceInfo() {
243 return this.deviceInfo;
247 public void handshakeSuccessful() {
248 Preconditions.checkNotNull(nodeId, "Cannot create DeviceInfo if 'NodeId' is not set!");
249 Preconditions.checkNotNull(featuresReply, "Cannot create DeviceInfo if 'features' is not set!");
250 this.deviceInfo = new DeviceInfoImpl(
252 DeviceStateUtil.createNodeInstanceIdentifier(nodeId),
253 featuresReply.getVersion(),
254 featuresReply.getDatapathId(),
255 outboundQueueProvider);
259 public void setHandshakeContext(final HandshakeContext handshakeContext) {
260 this.handshakeContext = handshakeContext;
264 public boolean equals(final Object object) {
265 if (this == object) {
269 if (object == null || getClass() != object.getClass()) {
273 ConnectionContextImpl that = (ConnectionContextImpl) object;
275 if (!connectionAdapter.equals(that.connectionAdapter)) {
279 if (featuresReply != null ? !featuresReply.equals(that.featuresReply) : that.featuresReply != null) {
283 return nodeId != null ? nodeId.equals(that.nodeId) : that.nodeId == null;
288 public int hashCode() {
289 int result = connectionAdapter.hashCode();
290 result = 31 * result + (featuresReply != null ? featuresReply.hashCode() : 0);
291 result = 31 * result + (nodeId != null ? nodeId.hashCode() : 0);
295 private static class DeviceInfoImpl implements DeviceInfo {
297 private final NodeId nodeId;
298 private final KeyedInstanceIdentifier<Node, NodeKey> nodeII;
299 private final Uint8 version;
300 private final Uint64 datapathId;
301 private final ServiceGroupIdentifier serviceGroupIdentifier;
302 private OutboundQueue outboundQueueProvider;
306 final KeyedInstanceIdentifier<Node, NodeKey> nodeII,
308 final Uint64 datapathId,
309 final OutboundQueue outboundQueueProvider) {
310 this.nodeId = nodeId;
311 this.nodeII = nodeII;
312 this.version = version;
313 this.datapathId = datapathId;
314 this.outboundQueueProvider = outboundQueueProvider;
315 this.serviceGroupIdentifier = ServiceGroupIdentifier.create(this.nodeId.getValue());
319 public NodeId getNodeId() {
324 public KeyedInstanceIdentifier<Node, NodeKey> getNodeInstanceIdentifier() {
329 public short getVersion() {
330 return version.toJava();
334 public Uint64 getDatapathId() {
339 public ServiceGroupIdentifier getServiceIdentifier() {
340 return this.serviceGroupIdentifier;
344 public boolean equals(final Object object) {
345 if (this == object) {
349 if (object == null || getClass() != object.getClass()) {
353 DeviceInfoImpl that = (DeviceInfoImpl) object;
355 return nodeId.equals(that.nodeId)
356 && nodeII.equals(that.nodeII)
357 && version.equals(that.version)
358 && datapathId.equals(that.datapathId);
363 public int hashCode() {
364 int result = nodeId.hashCode();
365 result = 31 * result + nodeII.hashCode();
366 result = 31 * result + version.hashCode();
367 result = 31 * result + datapathId.hashCode();
372 public String toString() {
373 return nodeId == null ? "null" : getNodeId().getValue();
376 public void setOutboundQueueProvider(final OutboundQueue outboundQueueProvider) {
377 this.outboundQueueProvider = outboundQueueProvider;
381 public Long reserveXidForDeviceMessage() {
382 return outboundQueueProvider.reserveEntry();