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
9 package org.opendaylight.openflowplugin.impl.connection;
11 import com.google.common.base.MoreObjects;
12 import com.google.common.base.Preconditions;
13 import java.math.BigInteger;
14 import java.util.ArrayList;
15 import java.util.Collections;
16 import java.util.List;
17 import java.util.Objects;
18 import java.util.Optional;
19 import org.opendaylight.mdsal.singleton.common.api.ServiceGroupIdentifier;
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.yang.gen.v1.urn.opendaylight.openflow.protocol.rev130731.PortStatusMessage;
35 import org.opendaylight.yangtools.yang.binding.KeyedInstanceIdentifier;
36 import org.slf4j.Logger;
37 import org.slf4j.LoggerFactory;
39 public class ConnectionContextImpl implements ConnectionContext {
41 private final ConnectionAdapter connectionAdapter;
42 private volatile CONNECTION_STATE connectionState;
43 private FeaturesReply featuresReply;
44 private NodeId nodeId;
45 private DeviceDisconnectedHandler deviceDisconnectedHandler;
46 private static final Logger LOG = LoggerFactory.getLogger(ConnectionContextImpl.class);
47 private OutboundQueueProvider outboundQueueProvider;
48 private OutboundQueueHandlerRegistration<OutboundQueueProvider> outboundQueueHandlerRegistration;
49 private HandshakeContext handshakeContext;
50 private DeviceInfo deviceInfo;
51 private final List<PortStatusMessage> portStatusMessages = new ArrayList<>();
56 * @param connectionAdapter - connection adapter
58 public ConnectionContextImpl(final ConnectionAdapter connectionAdapter) {
59 this.connectionAdapter = connectionAdapter;
63 public ConnectionAdapter getConnectionAdapter() {
64 return connectionAdapter;
68 public OutboundQueue getOutboundQueueProvider() {
69 return this.outboundQueueProvider;
73 public void setOutboundQueueProvider(final OutboundQueueProvider outboundQueueProvider) {
74 this.outboundQueueProvider = outboundQueueProvider;
75 ((DeviceInfoImpl)this.deviceInfo).setOutboundQueueProvider(this.outboundQueueProvider);
79 public CONNECTION_STATE getConnectionState() {
80 return connectionState;
84 public NodeId getNodeId() {
89 public void setNodeId(final NodeId nodeId) {
94 public FeaturesReply getFeatures() {
99 public void setDeviceDisconnectedHandler(final DeviceDisconnectedHandler deviceDisconnectedHandler) {
100 this.deviceDisconnectedHandler = deviceDisconnectedHandler;
104 public void setFeatures(final FeaturesReply newFeaturesReply) {
105 this.featuresReply = newFeaturesReply;
109 public void closeConnection(final boolean propagate) {
110 disconnectDevice(propagate, true);
113 private void closeHandshakeContext() {
114 LOG.debug("Trying closing handshake context for node {}", getSafeNodeIdForLOG());
115 if (handshakeContext != null) {
116 handshakeContext.close();
117 handshakeContext = null;
122 public void onConnectionClosed() {
123 disconnectDevice(true, false);
126 private void disconnectDevice(final boolean propagate,
127 final boolean forced) {
128 final String device =
129 Objects.nonNull(nodeId) ? nodeId.getValue() : getConnectionAdapter().getRemoteAddress().toString();
130 final short auxiliaryId = Optional
131 .ofNullable(getFeatures())
132 .flatMap(features -> Optional
133 .ofNullable(features.getAuxiliaryId()))
136 if (connectionState == CONNECTION_STATE.RIP) {
137 LOG.debug("Connection for device {} with auxiliary ID {} is already {}, so skipping closing.",
138 device, auxiliaryId, getConnectionState());
142 connectionState = ConnectionContext.CONNECTION_STATE.RIP;
144 SessionStatistics.countEvent(device, forced
145 ? SessionStatistics.ConnectionStatus.CONNECTION_DISCONNECTED_BY_OFP
146 : SessionStatistics.ConnectionStatus.CONNECTION_DISCONNECTED_BY_DEVICE);
148 LOG.debug("{}: device={} | auxiliaryId={} | connectionState={}",
149 forced ? "Actively closing connection" : "Disconnecting",
152 getConnectionState());
154 portStatusMessages.clear();
155 unregisterOutboundQueue();
156 closeHandshakeContext();
158 if (forced && getConnectionAdapter().isAlive()) {
159 getConnectionAdapter().disconnect();
163 propagateDeviceDisconnectedEvent();
167 private void propagateDeviceDisconnectedEvent() {
168 if (Objects.nonNull(deviceDisconnectedHandler)) {
169 final BigInteger datapathId = featuresReply != null ? featuresReply.getDatapathId() : BigInteger.ZERO;
170 if (LOG.isDebugEnabled()) {
171 LOG.debug("Propagating connection closed event: {}, datapathId:{}.",
172 connectionAdapter.getRemoteAddress(), datapathId);
174 deviceDisconnectedHandler.onDeviceDisconnected(this);
179 * Get safe nodeId for logging.
181 * @return string value od nodeId or string "null"
184 public String getSafeNodeIdForLOG() {
185 return Objects.nonNull(nodeId) ? nodeId.getValue() : "null";
189 public void setOutboundQueueHandleRegistration(
190 OutboundQueueHandlerRegistration<OutboundQueueProvider> newRegistration) {
191 this.outboundQueueHandlerRegistration = newRegistration;
194 private void unregisterOutboundQueue() {
195 if (LOG.isDebugEnabled()) {
196 LOG.debug("Trying unregister outbound queue handler registration for node {}", getSafeNodeIdForLOG());
198 if (outboundQueueHandlerRegistration != null) {
199 outboundQueueHandlerRegistration.close();
200 outboundQueueHandlerRegistration = null;
205 public synchronized void changeStateToHandshaking() {
206 connectionState = CONNECTION_STATE.HANDSHAKING;
210 public synchronized void changeStateToTimeouting() {
211 connectionState = CONNECTION_STATE.TIMEOUTING;
215 public synchronized void changeStateToWorking() {
216 connectionState = CONNECTION_STATE.WORKING;
220 public void handlePortStatusMessage(final PortStatusMessage portStatusMessage) {
221 LOG.info("Received early port status message for node {} with reason {} and state {}",
222 getSafeNodeIdForLOG(),
223 portStatusMessage.getReason(),
224 MoreObjects.firstNonNull(portStatusMessage.getState(), portStatusMessage.getStateV10()));
226 LOG.debug("Early port status message body is {}", portStatusMessage);
227 portStatusMessages.add(portStatusMessage);
231 public List<PortStatusMessage> retrieveAndClearPortStatusMessages() {
232 final List<PortStatusMessage> immutablePortStatusMessages = Collections.unmodifiableList(portStatusMessages);
233 portStatusMessages.clear();
234 return immutablePortStatusMessages;
238 public DeviceInfo getDeviceInfo() {
239 return this.deviceInfo;
243 public void handshakeSuccessful() {
244 Preconditions.checkNotNull(nodeId, "Cannot create DeviceInfo if 'NodeId' is not set!");
245 Preconditions.checkNotNull(featuresReply, "Cannot create DeviceInfo if 'features' is not set!");
246 this.deviceInfo = new DeviceInfoImpl(
248 DeviceStateUtil.createNodeInstanceIdentifier(nodeId),
249 featuresReply.getVersion(),
250 featuresReply.getDatapathId(),
251 outboundQueueProvider);
255 public void setHandshakeContext(HandshakeContext handshakeContext) {
256 this.handshakeContext = handshakeContext;
260 public boolean equals(Object object) {
261 if (this == object) {
265 if (object == null || getClass() != object.getClass()) {
269 ConnectionContextImpl that = (ConnectionContextImpl) object;
271 if (!connectionAdapter.equals(that.connectionAdapter)) {
275 if (featuresReply != null ? !featuresReply.equals(that.featuresReply) : that.featuresReply != null) {
279 return nodeId != null ? nodeId.equals(that.nodeId) : that.nodeId == null;
284 public int hashCode() {
285 int result = connectionAdapter.hashCode();
286 result = 31 * result + (featuresReply != null ? featuresReply.hashCode() : 0);
287 result = 31 * result + (nodeId != null ? nodeId.hashCode() : 0);
291 private static class DeviceInfoImpl implements DeviceInfo {
293 private final NodeId nodeId;
294 private final KeyedInstanceIdentifier<Node, NodeKey> nodeII;
295 private final Short version;
296 private final BigInteger datapathId;
297 private final ServiceGroupIdentifier serviceGroupIdentifier;
298 private OutboundQueue outboundQueueProvider;
302 final KeyedInstanceIdentifier<Node, NodeKey> nodeII,
304 final BigInteger datapathId,
305 final OutboundQueue outboundQueueProvider) {
306 this.nodeId = nodeId;
307 this.nodeII = nodeII;
308 this.version = version;
309 this.datapathId = datapathId;
310 this.outboundQueueProvider = outboundQueueProvider;
311 this.serviceGroupIdentifier = ServiceGroupIdentifier.create(this.nodeId.getValue());
315 public NodeId getNodeId() {
320 public KeyedInstanceIdentifier<Node, NodeKey> getNodeInstanceIdentifier() {
325 public short getVersion() {
330 public BigInteger getDatapathId() {
335 public ServiceGroupIdentifier getServiceIdentifier() {
336 return this.serviceGroupIdentifier;
340 public boolean equals(Object object) {
341 if (this == object) {
345 if (object == null || getClass() != object.getClass()) {
349 DeviceInfoImpl that = (DeviceInfoImpl) object;
351 return nodeId.equals(that.nodeId)
352 && nodeII.equals(that.nodeII)
353 && version.equals(that.version)
354 && datapathId.equals(that.datapathId);
359 public int hashCode() {
360 int result = nodeId.hashCode();
361 result = 31 * result + nodeII.hashCode();
362 result = 31 * result + version.hashCode();
363 result = 31 * result + datapathId.hashCode();
368 public String toString() {
369 return Objects.isNull(nodeId) ? "null" : getNodeId().getValue();
372 public void setOutboundQueueProvider(final OutboundQueue outboundQueueProvider) {
373 this.outboundQueueProvider = outboundQueueProvider;
377 public Long reserveXidForDeviceMessage() {
378 return outboundQueueProvider.reserveEntry();