/*
* Copyright (c) 2017 Pantheon Technologies s.r.o. 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.device.initialization;
import com.google.common.base.Function;
import com.google.common.base.Preconditions;
import com.google.common.util.concurrent.FutureCallback;
import com.google.common.util.concurrent.Futures;
import com.google.common.util.concurrent.ListenableFuture;
import java.util.List;
import java.util.concurrent.Future;
import javax.annotation.Nonnull;
import javax.annotation.Nullable;
import org.opendaylight.controller.md.sal.common.api.data.LogicalDatastoreType;
import org.opendaylight.openflowplugin.api.openflow.connection.ConnectionContext;
import org.opendaylight.openflowplugin.api.openflow.device.DeviceContext;
import org.opendaylight.openflowplugin.api.openflow.device.DeviceInfo;
import org.opendaylight.openflowplugin.api.openflow.device.DeviceState;
import org.opendaylight.openflowplugin.api.openflow.device.MessageTranslator;
import org.opendaylight.openflowplugin.api.openflow.device.TxFacade;
import org.opendaylight.openflowplugin.api.openflow.md.core.TranslatorKey;
import org.opendaylight.openflowplugin.api.openflow.md.util.OpenflowVersion;
import org.opendaylight.openflowplugin.impl.datastore.MultipartWriterProvider;
import org.opendaylight.openflowplugin.impl.services.multilayer.MultiLayerMultipartCollectorService;
import org.opendaylight.openflowplugin.impl.services.singlelayer.SingleLayerMultipartCollectorService;
import org.opendaylight.openflowplugin.impl.util.DeviceInitializationUtil;
import org.opendaylight.openflowplugin.impl.util.DeviceStateUtil;
import org.opendaylight.openflowplugin.openflow.md.core.sal.convertor.ConvertorExecutor;
import org.opendaylight.openflowplugin.openflow.md.util.InventoryDataServiceUtil;
import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.FlowCapableNode;
import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.FlowCapableNodeBuilder;
import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.FlowCapableNodeConnector;
import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.NodeConnectorId;
import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.node.NodeConnector;
import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.node.NodeConnectorBuilder;
import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.node.NodeConnectorKey;
import org.opendaylight.yang.gen.v1.urn.opendaylight.multipart.types.rev170112.MultipartReply;
import org.opendaylight.yang.gen.v1.urn.opendaylight.openflow.common.types.rev130731.CapabilitiesV10;
import org.opendaylight.yang.gen.v1.urn.opendaylight.openflow.common.types.rev130731.MultipartType;
import org.opendaylight.yang.gen.v1.urn.opendaylight.openflow.protocol.rev130731.PortGrouping;
import org.opendaylight.yang.gen.v1.urn.opendaylight.port.statistics.rev131214.FlowCapableNodeConnectorStatisticsData;
import org.opendaylight.yang.gen.v1.urn.opendaylight.port.statistics.rev131214.FlowCapableNodeConnectorStatisticsDataBuilder;
import org.opendaylight.yangtools.yang.common.RpcResult;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
public class OF10DeviceInitializer extends AbstractDeviceInitializer {
private static final Logger LOG = LoggerFactory.getLogger(OF10DeviceInitializer.class);
@Override
protected Future<Void> initializeNodeInformation(@Nonnull final DeviceContext deviceContext,
final boolean switchFeaturesMandatory,
@Nullable final MultipartWriterProvider multipartWriterProvider,
@Nullable final ConvertorExecutor convertorExecutor) {
final ConnectionContext connectionContext = Preconditions.checkNotNull(deviceContext.getPrimaryConnectionContext());
final DeviceState deviceState = Preconditions.checkNotNull(deviceContext.getDeviceState());
final DeviceInfo deviceInfo = Preconditions.checkNotNull(deviceContext.getDeviceInfo());
final CapabilitiesV10 capabilitiesV10 = connectionContext.getFeatures().getCapabilitiesV10();
// Set capabilities for this device based on capabilities of connection context
LOG.debug("Setting capabilities for device {}", deviceInfo.getLOGValue());
DeviceStateUtil.setDeviceStateBasedOnV10Capabilities(deviceState, capabilitiesV10);
final ListenableFuture<Boolean> future = requestMultipart(MultipartType.OFPMPDESC, deviceContext);
Futures.addCallback(future, new FutureCallback<Boolean>() {
@Override
public void onSuccess(@Nullable final Boolean result) {
if (Boolean.TRUE.equals(result)) {
LOG.debug("Creating empty flow capable node: {}", deviceInfo.getLOGValue());
makeEmptyFlowCapableNode(deviceContext, deviceInfo);
LOG.debug("Creating empty tables for {}", deviceInfo.getLOGValue());
DeviceInitializationUtil.makeEmptyTables(
deviceContext,
deviceInfo,
deviceContext.getPrimaryConnectionContext().getFeatures().getTables());
}
}
@Override
public void onFailure(@Nonnull final Throwable t) {
LOG.warn("Error occurred in preparation node {} for protocol 1.0", deviceInfo.getLOGValue());
LOG.trace("Error for node {} : ", deviceInfo.getLOGValue(), t);
}
});
return Futures.transform(future, new Function<Boolean, Void>() {
@Nullable
@Override
public Void apply(@Nullable final Boolean input) {
writePhyPortInformation(deviceContext);
return null;
}
});
}
private static void writePhyPortInformation(final DeviceContext deviceContext) {
final DeviceInfo deviceInfo = deviceContext.getDeviceInfo();
final ConnectionContext connectionContext = deviceContext.getPrimaryConnectionContext();
final MessageTranslator<PortGrouping, FlowCapableNodeConnector> translator = deviceContext
.oook()
.lookupTranslator(new TranslatorKey(deviceInfo.getVersion(), PortGrouping.class.getName()));
connectionContext.getFeatures().getPhyPort().forEach(port -> {
final NodeConnectorId nodeConnectorId = InventoryDataServiceUtil.nodeConnectorIdfromDatapathPortNo(
deviceInfo.getDatapathId(),
port.getPortNo(),
OpenflowVersion.get(deviceInfo.getVersion()));
try {
deviceContext.writeToTransaction(LogicalDatastoreType.OPERATIONAL,
deviceInfo
.getNodeInstanceIdentifier()
.child(NodeConnector.class, new NodeConnectorKey(nodeConnectorId)),
new NodeConnectorBuilder()
.setId(nodeConnectorId)
.addAugmentation(
FlowCapableNodeConnector.class,
translator.translate(port, deviceInfo, null))
.addAugmentation(
FlowCapableNodeConnectorStatisticsData.class,
new FlowCapableNodeConnectorStatisticsDataBuilder().build())
.build());
} catch (final Exception e) {
LOG.debug("Failed to write node {} to DS ", deviceInfo.getLOGValue(), e);
}
});
}
private static void makeEmptyFlowCapableNode(final TxFacade txFacade, final DeviceInfo deviceInfo) {
try {
txFacade.writeToTransaction(LogicalDatastoreType.OPERATIONAL,
deviceInfo
.getNodeInstanceIdentifier()
.augmentation(FlowCapableNode.class),
new FlowCapableNodeBuilder().build());
} catch (final Exception e) {
LOG.debug("Failed to write empty node {} to DS ", deviceInfo.getLOGValue(), e);
}
}
private static ListenableFuture<Boolean> requestMultipart(final MultipartType multipartType,
final DeviceContext deviceContext) {
if (deviceContext.canUseSingleLayerSerialization()) {
final SingleLayerMultipartCollectorService service =
new SingleLayerMultipartCollectorService(deviceContext, deviceContext);
return Futures.transform(service.handleServiceCall(multipartType), new Function<RpcResult<List<MultipartReply>>, Boolean>() {
@Nullable
@Override
public Boolean apply(final RpcResult<List<MultipartReply>> input) {
return input.isSuccessful();
}
});
}
final MultiLayerMultipartCollectorService service =
new MultiLayerMultipartCollectorService(deviceContext, deviceContext);
return Futures.transform(service.handleServiceCall(multipartType), new Function<RpcResult<List<org.opendaylight.yang.gen.v1.urn.opendaylight.openflow.protocol.rev130731.MultipartReply>>, Boolean>() {
@Nullable
@Override
public Boolean apply(final RpcResult<List<org.opendaylight.yang.gen.v1.urn.opendaylight.openflow.protocol.rev130731.MultipartReply>> input) {
return input.isSuccessful();
}
});
}
}