All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.opendaylight.openflowplugin.impl.connection.ConnectionManagerImpl Maven / Gradle / Ivy

The newest version!
/*
 * Copyright (c) 2015 Cisco Systems, Inc. and others.  All rights reserved.
 *
 * This program and the accompanying materials are made available under the
 * terms of the Eclipse Public License v1.0 which accompanies this distribution,
 * and is available at http://www.eclipse.org/legal/epl-v10.html
 */
package org.opendaylight.openflowplugin.impl.connection;

import static java.util.Objects.requireNonNull;

import com.google.common.annotations.VisibleForTesting;
import com.google.common.util.concurrent.ThreadFactoryBuilder;
import java.math.BigInteger;
import java.net.InetAddress;
import java.time.LocalDateTime;
import java.util.List;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.ThreadFactory;
import org.eclipse.jdt.annotation.NonNull;
import org.opendaylight.mdsal.binding.api.DataBroker;
import org.opendaylight.mdsal.binding.api.DataObjectModification;
import org.opendaylight.mdsal.binding.api.DataTreeChangeListener;
import org.opendaylight.mdsal.binding.api.DataTreeIdentifier;
import org.opendaylight.mdsal.binding.api.DataTreeModification;
import org.opendaylight.mdsal.binding.api.NotificationPublishService;
import org.opendaylight.mdsal.common.api.LogicalDatastoreType;
import org.opendaylight.openflowjava.protocol.api.connection.ConnectionAdapter;
import org.opendaylight.openflowjava.protocol.api.connection.ConnectionReadyListener;
import org.opendaylight.openflowplugin.api.OFConstants;
import org.opendaylight.openflowplugin.api.openflow.connection.ConnectionContext;
import org.opendaylight.openflowplugin.api.openflow.connection.ConnectionManager;
import org.opendaylight.openflowplugin.api.openflow.connection.DeviceConnectionStatusProvider;
import org.opendaylight.openflowplugin.api.openflow.connection.HandshakeContext;
import org.opendaylight.openflowplugin.api.openflow.device.handlers.DeviceConnectedHandler;
import org.opendaylight.openflowplugin.api.openflow.device.handlers.DeviceDisconnectedHandler;
import org.opendaylight.openflowplugin.api.openflow.md.core.HandshakeListener;
import org.opendaylight.openflowplugin.api.openflow.md.core.HandshakeManager;
import org.opendaylight.openflowplugin.impl.common.DeviceConnectionRateLimiter;
import org.opendaylight.openflowplugin.impl.connection.listener.ConnectionReadyListenerImpl;
import org.opendaylight.openflowplugin.impl.connection.listener.HandshakeListenerImpl;
import org.opendaylight.openflowplugin.impl.connection.listener.OpenflowProtocolListenerInitialImpl;
import org.opendaylight.openflowplugin.impl.connection.listener.SystemNotificationsListenerImpl;
import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.Nodes;
import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.nodes.Node;
import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.openflow.provider.config.rev160510.OpenflowProviderConfig;
import org.opendaylight.yangtools.concepts.Registration;
import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

public class ConnectionManagerImpl implements ConnectionManager {

    private static final Logger LOG = LoggerFactory.getLogger(ConnectionManagerImpl.class);
    private static final Logger OF_EVENT_LOG = LoggerFactory.getLogger("OfEventLog");
    private static final boolean BITMAP_NEGOTIATION_ENABLED = true;
    private final ThreadFactory threadFactory = new ThreadFactoryBuilder()
            .setNameFormat("ConnectionHandler-%d")
            .setDaemon(false)
            .setUncaughtExceptionHandler((thread, ex) -> LOG.error("Uncaught exception {}", thread, ex))
            .build();
    private final ExecutorService executorsService = Executors.newCachedThreadPool(threadFactory);

    private DeviceConnectedHandler deviceConnectedHandler;
    private final OpenflowProviderConfig config;
    private final ExecutorService executorService;
    private final DeviceConnectionRateLimiter deviceConnectionRateLimiter;
    private final DataBroker dataBroker;
    private final int deviceConnectionHoldTime;
    private DeviceDisconnectedHandler deviceDisconnectedHandler;
    private DeviceConnectionStatusProvider deviceConnectionStatusProvider;
    private final NotificationPublishService notificationPublishService;

    public ConnectionManagerImpl(final OpenflowProviderConfig config, final ExecutorService executorService,
                                 final DataBroker dataBroker,
                                 @NonNull final NotificationPublishService notificationPublishService) {
        this.config = config;
        this.executorService = executorService;
        deviceConnectionRateLimiter = new DeviceConnectionRateLimiter(config);
        this.dataBroker = dataBroker;
        deviceConnectionHoldTime = config.getDeviceConnectionHoldTimeInSeconds().toJava();
        deviceConnectionStatusProvider = new DeviceConnectionStatusProviderImpl();
        deviceConnectionStatusProvider.init();
        this.notificationPublishService = notificationPublishService;
    }

    @Override
    public void onSwitchConnected(final ConnectionAdapter connectionAdapter) {
        connectionAdapter.setExecutorService(executorsService);
        OF_EVENT_LOG.debug("OnSwitchConnected event received for device {}", connectionAdapter.getRemoteAddress());
        LOG.trace("prepare connection context");
        final ConnectionContext connectionContext = new ConnectionContextImpl(connectionAdapter,
                deviceConnectionStatusProvider);
        connectionContext.setDeviceDisconnectedHandler(deviceDisconnectedHandler);

        HandshakeListener handshakeListener = new HandshakeListenerImpl(connectionContext, deviceConnectedHandler);
        final HandshakeManager handshakeManager = createHandshakeManager(connectionAdapter, handshakeListener);

        LOG.trace("prepare handshake context");
        HandshakeContext handshakeContext = new HandshakeContextImpl(executorService, handshakeManager);
        handshakeListener.setHandshakeContext(handshakeContext);
        connectionContext.setHandshakeContext(handshakeContext);

        LOG.trace("prepare connection listeners");
        final ConnectionReadyListener connectionReadyListener = new ConnectionReadyListenerImpl(
                connectionContext, handshakeContext);
        connectionAdapter.setConnectionReadyListener(connectionReadyListener);

        connectionAdapter.setMessageListener(
            new OpenflowProtocolListenerInitialImpl(connectionContext, handshakeContext));

        connectionAdapter.setSystemListener(new SystemNotificationsListenerImpl(connectionContext,
                config.getEchoReplyTimeout().getValue().toJava(), executorService, notificationPublishService));

        LOG.trace("connection ballet finished");
    }

    private HandshakeManager createHandshakeManager(final ConnectionAdapter connectionAdapter,
                                                    final HandshakeListener handshakeListener) {
        HandshakeManagerImpl handshakeManager = new HandshakeManagerImpl(connectionAdapter,
                OFConstants.VERSION_ORDER.get(0),
                OFConstants.VERSION_ORDER, new ErrorHandlerSimpleImpl(), handshakeListener, BITMAP_NEGOTIATION_ENABLED,
                deviceConnectionRateLimiter, deviceConnectionHoldTime, deviceConnectionStatusProvider);

        return handshakeManager;
    }

    @Override
    public boolean accept(final InetAddress switchAddress) {
        // TODO add connection accept logic based on address
        return true;
    }

    @Override
    public void setDeviceConnectedHandler(final DeviceConnectedHandler deviceConnectedHandler) {
        this.deviceConnectedHandler = deviceConnectedHandler;
    }

    @Override
    public void setDeviceDisconnectedHandler(final DeviceDisconnectedHandler deviceDisconnectedHandler) {
        this.deviceDisconnectedHandler = deviceDisconnectedHandler;
    }

    @VisibleForTesting
    DeviceConnectionStatusProvider getDeviceConnectionStatusProvider() {
        return deviceConnectionStatusProvider;
    }

    @Override
    public void close() throws Exception {
        if (deviceConnectionStatusProvider != null) {
            deviceConnectionStatusProvider.close();
            deviceConnectionStatusProvider = null;
        }
        if (executorsService != null) {
            executorsService.shutdownNow();
        }
    }

    class DeviceConnectionStatusProviderImpl implements DeviceConnectionStatusProvider, DataTreeChangeListener {
        private final Map deviceConnectionMap = new ConcurrentHashMap<>();

        private Registration listenerRegistration;

        @Override
        @SuppressWarnings({"checkstyle:IllegalCatch"})
        public void init() {
            final var treeId = DataTreeIdentifier.of(LogicalDatastoreType.OPERATIONAL, getWildCardPath());
            try {
                listenerRegistration = dataBroker.registerTreeChangeListener(treeId, this);
            } catch (Exception e) {
                LOG.error("DeviceConnectionStatusProvider listener registration failed", e);
            }
        }

        @Override
        public LocalDateTime getDeviceLastConnectionTime(final BigInteger nodeId) {
            return deviceConnectionMap.get(nodeId);
        }

        @Override
        public void addDeviceLastConnectionTime(final BigInteger nodeId, final LocalDateTime time) {
            deviceConnectionMap.put(nodeId, time);
        }

        @Override
        public void removeDeviceLastConnectionTime(final BigInteger nodeId) {
            deviceConnectionMap.remove(nodeId);
        }

        @Override
        public void onDataTreeChanged(final List> changes) {
            requireNonNull(changes, "Changes must not be null!");
            for (DataTreeModification change : changes) {
                final DataObjectModification mod = change.getRootNode();
                switch (mod.modificationType()) {
                    case DELETE:
                        break;
                    case SUBTREE_MODIFIED:
                        break;
                    case WRITE:
                        processNodeModification(change);
                        break;
                    default:
                        throw new IllegalArgumentException("Unhandled modification type " + mod.modificationType());
                }
            }
        }

        private InstanceIdentifier getWildCardPath() {
            return InstanceIdentifier.create(Nodes.class).child(Node.class);
        }

        private void processNodeModification(final DataTreeModification change) {
            final InstanceIdentifier key = change.getRootPath().path();
            final InstanceIdentifier nodeIdent = key.firstIdentifierOf(Node.class);
            String[] nodeIdentity = nodeIdent.firstKeyOf(Node.class).getId().getValue().split(":");
            String nodeId = nodeIdentity[1];
            LOG.info("Clearing the device connection timer for the device {}", nodeId);
            removeDeviceLastConnectionTime(new BigInteger(nodeId));
        }

        @Override
        public void close() {
            if (listenerRegistration != null) {
                listenerRegistration.close();
                listenerRegistration = null;
            }
        }
    }
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy