/*
* Copyright (c) 2016, 2017 Ericsson Corp. 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.sfc.genius.util;
import java.util.List;
import java.util.Optional;
import java.util.concurrent.ExecutionException;
import org.opendaylight.controller.sal.binding.api.RpcProviderRegistry;
import org.opendaylight.yang.gen.v1.urn.ericsson.params.xml.ns.yang.sfc.sff.logical.rev160620.DpnIdType;
import org.opendaylight.yang.gen.v1.urn.opendaylight.action.types.rev131112.action.list.Action;
import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.interfacemanager.rev160406.TunnelTypeVxlanGpe;
import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.interfacemanager.rpcs.rev160406.GetDpidFromInterfaceInput;
import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.interfacemanager.rpcs.rev160406.GetDpidFromInterfaceInputBuilder;
import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.interfacemanager.rpcs.rev160406.GetDpidFromInterfaceOutput;
import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.interfacemanager.rpcs.rev160406.GetEgressActionsForInterfaceInput;
import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.interfacemanager.rpcs.rev160406.GetEgressActionsForInterfaceInputBuilder;
import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.interfacemanager.rpcs.rev160406.GetEgressActionsForInterfaceOutput;
import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.interfacemanager.rpcs.rev160406.OdlInterfaceRpcService;
import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.itm.rpcs.rev160406.GetTunnelInterfaceNameInput;
import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.itm.rpcs.rev160406.GetTunnelInterfaceNameInputBuilder;
import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.itm.rpcs.rev160406.GetTunnelInterfaceNameOutput;
import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.itm.rpcs.rev160406.ItmRpcService;
import org.opendaylight.yangtools.yang.common.RpcResult;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
/**
* This class centralizes all Genius RPC accesses which SFC openflow renderer
* needs when using logical SFFs.
*
* @author Diego Granados (diego.jesus.granados.lopez@ericsson.com)
*/
public class SfcGeniusRpcClient {
private static final Logger LOG = LoggerFactory.getLogger(SfcGeniusRpcClient.class);
private ItmRpcService itmRpcService;
private OdlInterfaceRpcService interfaceManagerRpcService;
/*
* Tunnel key used in the transport zone created to support the logical SFF
*/
private static final long LOGICAL_SFF_TZ_DEFAULT_TUNNEL_KEY = 0;
/**
* Constructor.
*
* @param rpcProviderRegistry
* The registry used to retrieve RPC services
*/
public SfcGeniusRpcClient(RpcProviderRegistry rpcProviderRegistry) {
LOG.debug("SfcGeniusRpcClient: starting");
if (rpcProviderRegistry != null) {
itmRpcService = rpcProviderRegistry.getRpcService(ItmRpcService.class);
interfaceManagerRpcService = rpcProviderRegistry.getRpcService(OdlInterfaceRpcService.class);
}
}
/**
* Retrieve egress actions from Genius.
*
* @param targetInterfaceName
* the interface to use
* @param interfaceIsPartOfTheTransportZone
* true when the interface is part of the transport zone (i.e. it
* is an interface between switching elements in different
* compute nodes); false when it is the Neutron interface of a SF
* @param actionOffset
* offsets the order parameter of the actions gotten from genius
* RPC
* @return The egress instructions to use, or empty when the RPC invocation
* failed
*/
public Optional<List<Action>> getEgressActionsFromGeniusRPC(String targetInterfaceName,
boolean interfaceIsPartOfTheTransportZone, int actionOffset) {
Optional<List<Action>> result = Optional.empty();
boolean successful = false;
LOG.debug("getEgressActionsFromGeniusRPC: starting (target interface={} in the transport zone:{})",
targetInterfaceName, interfaceIsPartOfTheTransportZone);
GetEgressActionsForInterfaceInputBuilder builder = new GetEgressActionsForInterfaceInputBuilder()
.setIntfName(targetInterfaceName).setActionKey(actionOffset);
if (interfaceIsPartOfTheTransportZone) {
builder.setTunnelKey(LOGICAL_SFF_TZ_DEFAULT_TUNNEL_KEY);
}
GetEgressActionsForInterfaceInput input = builder.build();
try {
OdlInterfaceRpcService service = getInterfaceManagerRpcService();
if (service != null) {
RpcResult<GetEgressActionsForInterfaceOutput> output = service.getEgressActionsForInterface(input)
.get();
if (output.isSuccessful()) {
result = Optional.of(output.getResult().getAction());
LOG.debug("getEgressInstructionsFromGeniusRPC({}) succeeded", input);
successful = true;
} else {
LOG.error("getEgressInstructionsFromGeniusRPC({}) failed", input);
}
} else {
LOG.error("getEgressInstructionsFromGeniusRPC({}) failed (service couldn't be retrieved)", input);
}
} catch (InterruptedException | ExecutionException e) {
LOG.error("failed to retrieve egress instructions for input {}: ", input, e);
}
if (!successful) {
result = Optional.empty();
}
return result;
}
/**
* Given a pair of data plane node identifiers, the method returns the
* interface to use for sending traffic from the first dpn to the second.
* This method assumes that a Genius' transport zone exists and that it
* including all the dataplane nodes involved in the SFC chain, so vxlan-gpe
* tunnels exist beforehand between all data plane nodes.
*
* @param srcDpid
* DPN ID for the source dataplane node
* @param dstDpid
* DPN ID for the target dataplane node
* @return The interface to use for traffic steering between the given
* dataplane nodes(empty when some problem arises during the
* retrieval)
*/
public Optional<String> getTargetInterfaceFromGeniusRPC(DpnIdType srcDpid, DpnIdType dstDpid) {
Optional<String> interfaceName = Optional.empty();
boolean successful = false;
LOG.debug("getTargetInterfaceFromGeniusRPC: starting (src dpnid:{} dst dpnid:{})", srcDpid, dstDpid);
GetTunnelInterfaceNameInputBuilder builder = new GetTunnelInterfaceNameInputBuilder();
builder.setSourceDpid(srcDpid.getValue());
builder.setDestinationDpid(dstDpid.getValue());
builder.setTunnelType(TunnelTypeVxlanGpe.class);
GetTunnelInterfaceNameInput input = builder.build();
ItmRpcService service = getItmRpcService();
if (service != null) {
RpcResult<GetTunnelInterfaceNameOutput> output;
try {
output = service.getTunnelInterfaceName(input).get();
if (output.isSuccessful()) {
interfaceName = Optional.of(output.getResult().getInterfaceName());
LOG.debug("getTargetInterfaceFromGeniusRPC({}) succeeded", input);
successful = true;
} else {
LOG.error("getTargetInterfaceFromGeniusRPC({}) failed", input);
}
} catch (InterruptedException | ExecutionException e) {
LOG.error("failed to retrieve target interface name: ", e);
}
} else {
LOG.error("getTargetInterfaceFromGeniusRPC({}) failed (service couldn't be retrieved)", input);
}
if (!successful) {
interfaceName = Optional.empty();
}
return interfaceName;
}
/**
* Given a Neutron interface to which a VM (hosting a SF instance) is
* attached, the method returns the DPN ID for the dataplane node in the
* compute node where the VM is running.
*
* @param logicalInterfaceName
* the Neutron interface that the SF is attached to
* @return the DPN ID for the dataplane node in the compute node hosting the
* SF, or empty when the value cannot be retrieved
*/
public Optional<DpnIdType> getDpnIdFromInterfaceNameFromGeniusRPC(String logicalInterfaceName) {
Optional<DpnIdType> dpnid = Optional.empty();
boolean successful = false;
LOG.debug("getDpnIdFromInterfaceNameFromGeniusRPC: starting (logical interface={})", logicalInterfaceName);
GetDpidFromInterfaceInputBuilder builder = new GetDpidFromInterfaceInputBuilder();
builder.setIntfName(logicalInterfaceName);
GetDpidFromInterfaceInput input = builder.build();
try {
OdlInterfaceRpcService service = getInterfaceManagerRpcService();
if (service != null) {
LOG.debug("getDpnIdFromInterfaceNameFromGeniusRPC: service is not null, invoking rpc");
RpcResult<GetDpidFromInterfaceOutput> output = service.getDpidFromInterface(input).get();
if (output.isSuccessful()) {
dpnid = Optional.of(new DpnIdType(output.getResult().getDpid()));
LOG.debug("getDpnIdFromInterfaceNameFromGeniusRPC({}) succeeded: {}", input, output);
successful = true;
} else {
LOG.error("getDpnIdFromInterfaceNameFromGeniusRPC({}) failed: {}", input, output);
}
} else {
LOG.error("getDpnIdFromInterfaceNameFromGeniusRPC({}) failed (service couldn't be retrieved)", input);
}
} catch (InterruptedException | ExecutionException e) {
LOG.error("failed to retrieve target interface name: ", e);
}
if (!successful) {
dpnid = Optional.empty();
}
return dpnid;
}
private ItmRpcService getItmRpcService() {
return itmRpcService;
}
private OdlInterfaceRpcService getInterfaceManagerRpcService() {
return interfaceManagerRpcService;
}
}