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 static java.util.Objects.requireNonNull;
11 import static java.util.Objects.requireNonNullElse;
13 import java.util.ArrayList;
14 import java.util.Collections;
15 import java.util.List;
16 import org.opendaylight.mdsal.singleton.common.api.ServiceGroupIdentifier;
17 import org.opendaylight.openflowjava.protocol.api.connection.ConnectionAdapter;
18 import org.opendaylight.openflowjava.protocol.api.connection.OutboundQueue;
19 import org.opendaylight.openflowjava.protocol.api.connection.OutboundQueueHandlerRegistration;
20 import org.opendaylight.openflowplugin.api.openflow.connection.ConnectionContext;
21 import org.opendaylight.openflowplugin.api.openflow.connection.DeviceConnectionStatusProvider;
22 import org.opendaylight.openflowplugin.api.openflow.connection.HandshakeContext;
23 import org.opendaylight.openflowplugin.api.openflow.connection.OutboundQueueProvider;
24 import org.opendaylight.openflowplugin.api.openflow.device.DeviceInfo;
25 import org.opendaylight.openflowplugin.api.openflow.device.handlers.DeviceDisconnectedHandler;
26 import org.opendaylight.openflowplugin.impl.statistics.ofpspecific.SessionStatistics;
27 import org.opendaylight.openflowplugin.impl.util.DeviceStateUtil;
28 import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.NodeId;
29 import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.nodes.Node;
30 import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.nodes.NodeKey;
31 import org.opendaylight.yang.gen.v1.urn.opendaylight.openflow.protocol.rev130731.FeaturesReply;
32 import org.opendaylight.yang.gen.v1.urn.opendaylight.openflow.protocol.rev130731.PortStatusMessage;
33 import org.opendaylight.yangtools.yang.binding.KeyedInstanceIdentifier;
34 import org.opendaylight.yangtools.yang.common.Uint32;
35 import org.opendaylight.yangtools.yang.common.Uint64;
36 import org.opendaylight.yangtools.yang.common.Uint8;
37 import org.slf4j.Logger;
38 import org.slf4j.LoggerFactory;
40 public class ConnectionContextImpl implements ConnectionContext {
41 private static final Logger LOG = LoggerFactory.getLogger(ConnectionContextImpl.class);
43 private final List<PortStatusMessage> portStatusMessages = new ArrayList<>();
44 private final ConnectionAdapter connectionAdapter;
46 private volatile CONNECTION_STATE connectionState;
47 private FeaturesReply featuresReply = null;
48 private NodeId nodeId;
49 private DeviceDisconnectedHandler deviceDisconnectedHandler;
50 private OutboundQueueProvider outboundQueueProvider;
51 private OutboundQueueHandlerRegistration<OutboundQueueProvider> outboundQueueHandlerRegistration;
52 private HandshakeContext handshakeContext = null;
53 private DeviceInfo deviceInfo = null;
58 * @param connectionAdapter - connection adapter
60 public ConnectionContextImpl(final ConnectionAdapter connectionAdapter,
61 final DeviceConnectionStatusProvider deviceConnectionStatusProvider) {
62 this.connectionAdapter = connectionAdapter;
66 public ConnectionAdapter getConnectionAdapter() {
67 return connectionAdapter;
71 public OutboundQueue getOutboundQueueProvider() {
72 return outboundQueueProvider;
76 public void setOutboundQueueProvider(final OutboundQueueProvider outboundQueueProvider) {
77 this.outboundQueueProvider = outboundQueueProvider;
78 ((DeviceInfoImpl)deviceInfo).setOutboundQueueProvider(this.outboundQueueProvider);
82 public CONNECTION_STATE getConnectionState() {
83 return connectionState;
87 public NodeId getNodeId() {
92 public void setNodeId(final NodeId nodeId) {
97 public FeaturesReply getFeatures() {
102 public void setDeviceDisconnectedHandler(final DeviceDisconnectedHandler deviceDisconnectedHandler) {
103 this.deviceDisconnectedHandler = deviceDisconnectedHandler;
107 public void setFeatures(final FeaturesReply newFeaturesReply) {
108 featuresReply = newFeaturesReply;
112 public void closeConnection(final boolean propagate) {
113 disconnectDevice(propagate, true);
116 private void closeHandshakeContext() {
117 LOG.debug("Trying closing handshake context for node {}", getSafeNodeIdForLOG());
118 if (handshakeContext != null) {
119 handshakeContext.close();
120 handshakeContext = null;
125 public void onConnectionClosed() {
126 disconnectDevice(true, false);
129 private void disconnectDevice(final boolean propagate,
130 final boolean forced) {
131 final String device = nodeId != null ? nodeId.getValue() : getConnectionAdapter().getRemoteAddress().toString();
133 final Uint8 auxiliaryId;
134 if (featuresReply != null) {
135 final Uint8 id = featuresReply.getAuxiliaryId();
136 auxiliaryId = id == null ? Uint8.ZERO : id;
138 auxiliaryId = Uint8.ZERO;
141 if (connectionState == CONNECTION_STATE.RIP) {
142 LOG.debug("Connection for device {} with auxiliary ID {} is already {}, so skipping closing.",
143 device, auxiliaryId, getConnectionState());
147 connectionState = ConnectionContext.CONNECTION_STATE.RIP;
149 SessionStatistics.countEvent(device, forced
150 ? SessionStatistics.ConnectionStatus.CONNECTION_DISCONNECTED_BY_OFP
151 : SessionStatistics.ConnectionStatus.CONNECTION_DISCONNECTED_BY_DEVICE);
153 LOG.debug("{}: device={} | auxiliaryId={} | connectionState={}",
154 forced ? "Actively closing connection" : "Disconnecting",
157 getConnectionState());
159 portStatusMessages.clear();
160 unregisterOutboundQueue();
161 closeHandshakeContext();
163 if (forced && getConnectionAdapter().isAlive()) {
164 getConnectionAdapter().disconnect();
168 propagateDeviceDisconnectedEvent();
172 private void propagateDeviceDisconnectedEvent() {
173 if (deviceDisconnectedHandler != null) {
174 final Uint64 datapathId = featuresReply != null ? featuresReply.getDatapathId() : Uint64.ZERO;
175 if (LOG.isDebugEnabled()) {
176 LOG.debug("Propagating connection closed event: {}, datapathId:{}.",
177 connectionAdapter.getRemoteAddress(), datapathId);
179 deviceDisconnectedHandler.onDeviceDisconnected(this);
184 * Get safe nodeId for logging.
186 * @return string value od nodeId or string "null"
189 public String getSafeNodeIdForLOG() {
190 return nodeId == null ? "null" : nodeId.getValue();
194 public void setOutboundQueueHandleRegistration(
195 final OutboundQueueHandlerRegistration<OutboundQueueProvider> newRegistration) {
196 outboundQueueHandlerRegistration = newRegistration;
199 private void unregisterOutboundQueue() {
200 if (LOG.isDebugEnabled()) {
201 LOG.debug("Trying unregister outbound queue handler registration for node {}", getSafeNodeIdForLOG());
203 if (outboundQueueHandlerRegistration != null) {
204 outboundQueueHandlerRegistration.close();
205 outboundQueueHandlerRegistration = null;
210 public synchronized void changeStateToHandshaking() {
211 connectionState = CONNECTION_STATE.HANDSHAKING;
215 public synchronized void changeStateToTimeouting() {
216 connectionState = CONNECTION_STATE.TIMEOUTING;
220 public synchronized void changeStateToWorking() {
221 connectionState = CONNECTION_STATE.WORKING;
225 public void handlePortStatusMessage(final PortStatusMessage portStatusMessage) {
226 LOG.info("Received early port status message for node {} with reason {} and state {}",
227 getSafeNodeIdForLOG(),
228 portStatusMessage.getReason(),
229 requireNonNullElse(portStatusMessage.getState(), portStatusMessage.getStateV10()));
231 LOG.debug("Early port status message body is {}", portStatusMessage);
232 portStatusMessages.add(portStatusMessage);
236 public List<PortStatusMessage> retrieveAndClearPortStatusMessages() {
237 final List<PortStatusMessage> immutablePortStatusMessages = Collections.unmodifiableList(portStatusMessages);
238 portStatusMessages.clear();
239 return immutablePortStatusMessages;
243 public DeviceInfo getDeviceInfo() {
248 public void handshakeSuccessful() {
249 requireNonNull(nodeId, "Cannot create DeviceInfo if 'NodeId' is not set!");
250 requireNonNull(featuresReply, "Cannot create DeviceInfo if 'features' is not set!");
251 deviceInfo = new DeviceInfoImpl(
253 DeviceStateUtil.createNodeInstanceIdentifier(nodeId),
254 featuresReply.getVersion(),
255 featuresReply.getDatapathId(),
256 outboundQueueProvider);
260 public void setHandshakeContext(final HandshakeContext handshakeContext) {
261 this.handshakeContext = handshakeContext;
265 public boolean equals(final Object object) {
266 if (this == object) {
270 if (object == null || getClass() != object.getClass()) {
274 ConnectionContextImpl that = (ConnectionContextImpl) object;
276 if (!connectionAdapter.equals(that.connectionAdapter)) {
280 if (featuresReply != null ? !featuresReply.equals(that.featuresReply) : that.featuresReply != null) {
284 return nodeId != null ? nodeId.equals(that.nodeId) : that.nodeId == null;
289 public int hashCode() {
290 int result = connectionAdapter.hashCode();
291 result = 31 * result + (featuresReply != null ? featuresReply.hashCode() : 0);
292 result = 31 * result + (nodeId != null ? nodeId.hashCode() : 0);
296 private static class DeviceInfoImpl implements DeviceInfo {
298 private final NodeId nodeId;
299 private final KeyedInstanceIdentifier<Node, NodeKey> nodeII;
300 private final Uint8 version;
301 private final Uint64 datapathId;
302 private final ServiceGroupIdentifier serviceGroupIdentifier;
303 private OutboundQueue outboundQueueProvider;
307 final KeyedInstanceIdentifier<Node, NodeKey> nodeII,
309 final Uint64 datapathId,
310 final OutboundQueue outboundQueueProvider) {
311 this.nodeId = nodeId;
312 this.nodeII = nodeII;
313 this.version = requireNonNull(version);
314 this.datapathId = datapathId;
315 this.outboundQueueProvider = outboundQueueProvider;
316 serviceGroupIdentifier = ServiceGroupIdentifier.create(this.nodeId.getValue());
320 public NodeId getNodeId() {
325 public KeyedInstanceIdentifier<Node, NodeKey> getNodeInstanceIdentifier() {
330 public Uint8 getVersion() {
335 public Uint64 getDatapathId() {
340 public ServiceGroupIdentifier getServiceIdentifier() {
341 return serviceGroupIdentifier;
345 public boolean equals(final Object object) {
346 if (this == object) {
350 if (object == null || getClass() != object.getClass()) {
354 DeviceInfoImpl that = (DeviceInfoImpl) object;
356 return nodeId.equals(that.nodeId)
357 && nodeII.equals(that.nodeII)
358 && version.equals(that.version)
359 && datapathId.equals(that.datapathId);
364 public int hashCode() {
365 int result = nodeId.hashCode();
366 result = 31 * result + nodeII.hashCode();
367 result = 31 * result + version.hashCode();
368 result = 31 * result + datapathId.hashCode();
373 public String toString() {
374 return nodeId == null ? "null" : getNodeId().getValue();
377 public void setOutboundQueueProvider(final OutboundQueue outboundQueueProvider) {
378 this.outboundQueueProvider = outboundQueueProvider;
382 public Uint32 reserveXidForDeviceMessage() {
383 return outboundQueueProvider.reserveEntry();