/* * Copyright (c) 2016, 2017 Ericsson India Global Services Pvt Ltd. 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.genius.itm.rpc; import com.google.common.base.Objects; import com.google.common.base.Optional; import com.google.common.util.concurrent.FutureCallback; import com.google.common.util.concurrent.Futures; import com.google.common.util.concurrent.ListenableFuture; import com.google.common.util.concurrent.MoreExecutors; import com.google.common.util.concurrent.SettableFuture; import java.math.BigInteger; import java.util.ArrayList; import java.util.Collection; import java.util.Collections; import java.util.HashMap; import java.util.List; import java.util.Map; import java.util.concurrent.Future; import java.util.stream.Collectors; import javax.annotation.PostConstruct; import javax.annotation.PreDestroy; import javax.inject.Inject; import javax.inject.Singleton; import org.opendaylight.controller.md.sal.binding.api.DataBroker; import org.opendaylight.controller.md.sal.binding.api.WriteTransaction; import org.opendaylight.controller.md.sal.common.api.data.LogicalDatastoreType; import org.opendaylight.controller.md.sal.common.api.data.ReadFailedException; import org.opendaylight.genius.datastoreutils.SingleTransactionDataBroker; import org.opendaylight.genius.itm.cache.DPNTEPsInfoCache; import org.opendaylight.genius.itm.confighelpers.ItmExternalTunnelAddWorker; import org.opendaylight.genius.itm.confighelpers.ItmExternalTunnelDeleteWorker; import org.opendaylight.genius.itm.globals.ITMConstants; import org.opendaylight.genius.itm.impl.ItmUtils; import org.opendaylight.genius.mdsalutil.MDSALUtil; import org.opendaylight.genius.mdsalutil.MatchInfo; import org.opendaylight.genius.mdsalutil.NwConstants; import org.opendaylight.genius.mdsalutil.interfaces.IMdsalApiManager; import org.opendaylight.genius.mdsalutil.matches.MatchTunnelId; import org.opendaylight.genius.tools.mdsal.rpc.FutureRpcResults; import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev130715.IpAddress; import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev130715.IpAddressBuilder; import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.FlowCapableNode; import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.tables.table.Flow; import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.interfacemanager.meta.rev160406.BridgeRefInfo; import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.interfacemanager.meta.rev160406.bridge.ref.info.BridgeRefEntry; import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.interfacemanager.meta.rev160406.bridge.ref.info.BridgeRefEntryKey; import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.interfacemanager.rev160406.TunnelTypeLogicalGroup; import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.interfacemanager.rev160406.TunnelTypeVxlan; import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.itm.config.rev160406.ItmConfig; import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.itm.op.rev160406.DpnEndpoints; import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.itm.op.rev160406.ExternalTunnelList; import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.itm.op.rev160406.dpn.endpoints.DPNTEPsInfo; import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.itm.op.rev160406.dpn.endpoints.DPNTEPsInfoKey; import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.itm.op.rev160406.dpn.endpoints.dpn.teps.info.TunnelEndPoints; import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.itm.op.rev160406.external.tunnel.list.ExternalTunnel; import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.itm.op.rev160406.external.tunnel.list.ExternalTunnelKey; import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.itm.op.rev160406.tunnel.list.InternalTunnel; import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.itm.rev160406.DcGatewayIpList; import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.itm.rev160406.TransportZones; import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.itm.rev160406.dc.gateway.ip.list.DcGatewayIp; import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.itm.rev160406.dc.gateway.ip.list.DcGatewayIpBuilder; import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.itm.rev160406.dc.gateway.ip.list.DcGatewayIpKey; import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.itm.rev160406.transport.zones.TransportZone; import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.itm.rev160406.transport.zones.TransportZoneKey; import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.itm.rev160406.transport.zones.transport.zone.Subnets; import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.itm.rev160406.transport.zones.transport.zone.SubnetsKey; import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.itm.rev160406.transport.zones.transport.zone.subnets.DeviceVteps; import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.itm.rev160406.transport.zones.transport.zone.subnets.DeviceVtepsBuilder; import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.itm.rev160406.transport.zones.transport.zone.subnets.DeviceVtepsKey; import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.itm.rev160406.transport.zones.transport.zone.subnets.Vteps; import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.itm.rpcs.rev160406.AddExternalTunnelEndpointInput; import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.itm.rpcs.rev160406.AddL2GwDeviceInput; import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.itm.rpcs.rev160406.AddL2GwMlagDeviceInput; import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.itm.rpcs.rev160406.BuildExternalTunnelFromDpnsInput; import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.itm.rpcs.rev160406.CreateTerminatingServiceActionsInput; import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.itm.rpcs.rev160406.DeleteL2GwDeviceInput; import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.itm.rpcs.rev160406.DeleteL2GwMlagDeviceInput; import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.itm.rpcs.rev160406.GetDpnEndpointIpsInput; import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.itm.rpcs.rev160406.GetDpnEndpointIpsOutput; import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.itm.rpcs.rev160406.GetDpnEndpointIpsOutputBuilder; import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.itm.rpcs.rev160406.GetDpnInfoInput; import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.itm.rpcs.rev160406.GetDpnInfoOutput; import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.itm.rpcs.rev160406.GetDpnInfoOutputBuilder; import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.itm.rpcs.rev160406.GetEgressActionsForTunnelInput; import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.itm.rpcs.rev160406.GetEgressActionsForTunnelOutput; import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.itm.rpcs.rev160406.GetExternalTunnelInterfaceNameInput; import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.itm.rpcs.rev160406.GetExternalTunnelInterfaceNameOutput; import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.itm.rpcs.rev160406.GetExternalTunnelInterfaceNameOutputBuilder; import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.itm.rpcs.rev160406.GetInternalOrExternalInterfaceNameInput; import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.itm.rpcs.rev160406.GetInternalOrExternalInterfaceNameOutput; import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.itm.rpcs.rev160406.GetInternalOrExternalInterfaceNameOutputBuilder; 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.GetTunnelInterfaceNameOutput; import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.itm.rpcs.rev160406.GetTunnelInterfaceNameOutputBuilder; import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.itm.rpcs.rev160406.GetTunnelTypeInput; import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.itm.rpcs.rev160406.GetTunnelTypeOutput; import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.itm.rpcs.rev160406.IsDcgwPresentInput; import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.itm.rpcs.rev160406.IsDcgwPresentOutput; import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.itm.rpcs.rev160406.IsDcgwPresentOutputBuilder; import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.itm.rpcs.rev160406.IsTunnelInternalOrExternalInput; import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.itm.rpcs.rev160406.IsTunnelInternalOrExternalOutput; import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.itm.rpcs.rev160406.IsTunnelInternalOrExternalOutputBuilder; import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.itm.rpcs.rev160406.ItmRpcService; import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.itm.rpcs.rev160406.RemoveExternalTunnelEndpointInput; import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.itm.rpcs.rev160406.RemoveExternalTunnelFromDpnsInput; import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.itm.rpcs.rev160406.RemoveTerminatingServiceActionsInput; import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.itm.rpcs.rev160406.SetBfdEnableOnTunnelInput; import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.itm.rpcs.rev160406.get.dpn.info.output.Computes; import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.itm.rpcs.rev160406.get.dpn.info.output.ComputesBuilder; 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.yangtools.yang.binding.InstanceIdentifier; import org.opendaylight.yangtools.yang.common.RpcError; import org.opendaylight.yangtools.yang.common.RpcResult; import org.opendaylight.yangtools.yang.common.RpcResultBuilder; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @Singleton public class ItmManagerRpcService implements ItmRpcService { private static final Logger LOG = LoggerFactory.getLogger(ItmManagerRpcService.class); private final DataBroker dataBroker; private final IMdsalApiManager mdsalManager; private final DPNTEPsInfoCache dpnTEPsInfoCache; private final ItmExternalTunnelAddWorker externalTunnelAddWorker; private final ItmConfig itmConfig; private final SingleTransactionDataBroker singleTransactionDataBroker; @Inject public ItmManagerRpcService(final DataBroker dataBroker, final IMdsalApiManager mdsalManager, final ItmConfig itmConfig, final DPNTEPsInfoCache dpnTEPsInfoCache) { this.dataBroker = dataBroker; this.mdsalManager = mdsalManager; this.dpnTEPsInfoCache = dpnTEPsInfoCache; this.externalTunnelAddWorker = new ItmExternalTunnelAddWorker(dataBroker, itmConfig, dpnTEPsInfoCache); this.itmConfig = itmConfig; this.singleTransactionDataBroker = new SingleTransactionDataBroker(dataBroker); } @PostConstruct public void start() { LOG.info("ItmManagerRpcService Started"); } @PreDestroy public void close() { LOG.info("ItmManagerRpcService Closed"); } @Override public Future> getTunnelInterfaceName(GetTunnelInterfaceNameInput input) { RpcResultBuilder resultBld = null; BigInteger sourceDpn = input.getSourceDpid(); BigInteger destinationDpn = input.getDestinationDpid(); Optional optTunnel = Optional.absent(); if (ItmUtils.isTunnelAggregationUsed(input.getTunnelType())) { optTunnel = ItmUtils.getInternalTunnelFromDS(sourceDpn, destinationDpn, TunnelTypeLogicalGroup.class, dataBroker); LOG.debug("MULTIPLE_VxLAN_TUNNELS: getTunnelInterfaceName {}", optTunnel); } if (!optTunnel.isPresent()) { optTunnel = ItmUtils.getInternalTunnelFromDS(sourceDpn, destinationDpn, input.getTunnelType(), dataBroker); } if (optTunnel.isPresent()) { InternalTunnel tunnel = optTunnel.get(); GetTunnelInterfaceNameOutputBuilder output = new GetTunnelInterfaceNameOutputBuilder() ; List tunnelInterfaces = tunnel.getTunnelInterfaceNames(); if (tunnelInterfaces != null && !tunnelInterfaces.isEmpty()) { output.setInterfaceName(tunnelInterfaces.get(0)); resultBld = RpcResultBuilder.success(); resultBld.withResult(output.build()); } else { resultBld = RpcResultBuilder.failed(); } } else { resultBld = RpcResultBuilder.failed(); } return Futures.immediateFuture(resultBld.build()); } @Override public Future> getEgressActionsForTunnel( GetEgressActionsForTunnelInput input) { //TODO return null; } @Override public Future> getTunnelType(GetTunnelTypeInput input) { //TODO return null; } @Override public Future> setBfdEnableOnTunnel(SetBfdEnableOnTunnelInput input) { //TODO return null; } @Override public Future> removeExternalTunnelEndpoint( RemoveExternalTunnelEndpointInput input) { //Ignore the Futures for now final SettableFuture> result = SettableFuture.create(); Collection meshedDpnList = dpnTEPsInfoCache.getAllPresent(); ItmExternalTunnelDeleteWorker.deleteTunnels(dataBroker, meshedDpnList, input.getDestinationIp(), input.getTunnelType()); InstanceIdentifier extPath = InstanceIdentifier.builder(DcGatewayIpList.class) .child(DcGatewayIp.class, new DcGatewayIpKey(input.getDestinationIp())).build(); WriteTransaction transaction = dataBroker.newWriteOnlyTransaction(); transaction.delete(LogicalDatastoreType.CONFIGURATION, extPath); ListenableFuture futureCheck = transaction.submit(); Futures.addCallback(futureCheck, new FutureCallback() { @Override public void onSuccess(Void voidInstance) { result.set(RpcResultBuilder.success().build()); } @Override public void onFailure(Throwable error) { String msg = "Unable to delete DcGatewayIp " + input.getDestinationIp() + " in datastore and tunnel type " + input.getTunnelType(); LOG.error("Unable to delete DcGatewayIp {} in datastore and tunnel type {}", input.getDestinationIp(), input.getTunnelType()); result.set(RpcResultBuilder.failed() .withError(RpcError.ErrorType.APPLICATION, msg, error).build()); } }); return result; } @Override public Future> removeExternalTunnelFromDpns( RemoveExternalTunnelFromDpnsInput input) { //Ignore the Futures for now final SettableFuture> result = SettableFuture.create(); List cfgDpnList = ItmUtils.getDpnTepListFromDpnId(dpnTEPsInfoCache, input.getDpnId()) ; ItmExternalTunnelDeleteWorker.deleteTunnels(dataBroker, cfgDpnList, input.getDestinationIp(), input.getTunnelType()); result.set(RpcResultBuilder.success().build()); return result; } @Override public Future> buildExternalTunnelFromDpns( BuildExternalTunnelFromDpnsInput input) { //Ignore the Futures for now final SettableFuture> result = SettableFuture.create(); List> extTunnelResultList = externalTunnelAddWorker .buildTunnelsFromDpnToExternalEndPoint(input.getDpnId(), input.getDestinationIp(),input.getTunnelType()); for (ListenableFuture extTunnelResult : extTunnelResultList) { Futures.addCallback(extTunnelResult, new FutureCallback() { @Override public void onSuccess(Void voidInstance) { result.set(RpcResultBuilder.success().build()); } @Override public void onFailure(Throwable error) { String msg = "Unable to create ext tunnel"; LOG.error("create ext tunnel failed. {}.", msg, error); result.set(RpcResultBuilder.failed() .withError(RpcError.ErrorType.APPLICATION, msg, error).build()); } }); } return result; } @Override public Future> addExternalTunnelEndpoint( AddExternalTunnelEndpointInput input) { // TODO Auto-generated method stub //Ignore the Futures for now final SettableFuture> result = SettableFuture.create(); Collection meshedDpnList = dpnTEPsInfoCache.getAllPresent(); externalTunnelAddWorker.buildTunnelsToExternalEndPoint(meshedDpnList, input.getDestinationIp(), input.getTunnelType()); InstanceIdentifier extPath = InstanceIdentifier.builder(DcGatewayIpList.class) .child(DcGatewayIp.class, new DcGatewayIpKey(input.getDestinationIp())).build(); DcGatewayIp dcGatewayIp = new DcGatewayIpBuilder().setIpAddress(input.getDestinationIp()) .setTunnnelType(input.getTunnelType()).build(); WriteTransaction writeTransaction = dataBroker.newWriteOnlyTransaction(); writeTransaction.put(LogicalDatastoreType.CONFIGURATION, extPath,dcGatewayIp, true); ListenableFuture futureCheck = writeTransaction.submit(); Futures.addCallback(futureCheck, new FutureCallback() { @Override public void onSuccess(Void voidInstance) { result.set(RpcResultBuilder.success().build()); } @Override public void onFailure(Throwable error) { String msg = "Unable to create DcGatewayIp {} in datastore for ip " + input.getDestinationIp() + "and " + "tunnel type " + input.getTunnelType(); LOG.error("Unable to create DcGatewayIp in datastore for ip {} and tunnel type {}", input.getDestinationIp() , input.getTunnelType()); result.set(RpcResultBuilder.failed() .withError(RpcError.ErrorType.APPLICATION, msg, error).build()); } }); return result; } @Override public Future> getExternalTunnelInterfaceName( GetExternalTunnelInterfaceNameInput input) { SettableFuture.create(); RpcResultBuilder resultBld; String sourceNode = input.getSourceNode(); String dstNode = input.getDestinationNode(); ExternalTunnelKey externalTunnelKey = new ExternalTunnelKey(dstNode, sourceNode, input.getTunnelType()); InstanceIdentifier path = InstanceIdentifier.create( ExternalTunnelList.class) .child(ExternalTunnel.class, externalTunnelKey); ExternalTunnel exTunnel = ItmUtils.getExternalTunnelbyExternalTunnelKey(externalTunnelKey, path, this.dataBroker); if (exTunnel != null) { GetExternalTunnelInterfaceNameOutputBuilder output = new GetExternalTunnelInterfaceNameOutputBuilder(); output.setInterfaceName(exTunnel.getTunnelInterfaceName()); resultBld = RpcResultBuilder.success(); resultBld.withResult(output.build()); } else { resultBld = RpcResultBuilder.failed(); } return Futures.immediateFuture(resultBld.build()); } @Override public Future> createTerminatingServiceActions(final CreateTerminatingServiceActionsInput input) { LOG.info("create terminatingServiceAction on DpnId = {} for service id {} and instructions {}", input.getDpnId() , input.getServiceId(), input.getInstruction()); final SettableFuture> result = SettableFuture.create(); int serviceId = input.getServiceId() ; final List mkMatches = getTunnelMatchesForServiceId(serviceId); Flow terminatingServiceTableFlow = MDSALUtil.buildFlowNew(NwConstants.INTERNAL_TUNNEL_TABLE, getFlowRef(NwConstants.INTERNAL_TUNNEL_TABLE,serviceId), 5, String.format("%s:%d","ITM Flow Entry ",serviceId), 0, 0, ITMConstants.COOKIE_ITM.add(BigInteger.valueOf(serviceId)),mkMatches, input.getInstruction()); ListenableFuture installFlowResult = mdsalManager.installFlow(input.getDpnId(), terminatingServiceTableFlow); Futures.addCallback(installFlowResult, new FutureCallback() { @Override public void onSuccess(Void voidInstance) { result.set(RpcResultBuilder.success().build()); } @Override public void onFailure(Throwable error) { String msg = String.format("Unable to install terminating service flow for %s", input.getDpnId()); LOG.error("create terminating service actions failed. {}", msg, error); result.set(RpcResultBuilder.failed().withError(RpcError.ErrorType.APPLICATION, msg, error) .build()); } }, MoreExecutors.directExecutor()); // result.set(RpcResultBuilder.success().build()); return result; } @Override public Future> removeTerminatingServiceActions(final RemoveTerminatingServiceActionsInput input) { LOG.info("remove terminatingServiceActions called with DpnId = {} and serviceId = {}", input.getDpnId(), input.getServiceId()); final SettableFuture> result = SettableFuture.create(); Flow terminatingServiceTableFlow = MDSALUtil.buildFlowNew(NwConstants.INTERNAL_TUNNEL_TABLE, getFlowRef(NwConstants.INTERNAL_TUNNEL_TABLE,input.getServiceId()), 5, String.format("%s:%d","ITM Flow Entry ",input.getServiceId()), 0, 0, ITMConstants.COOKIE_ITM.add(BigInteger.valueOf(input.getServiceId())), getTunnelMatchesForServiceId(input.getServiceId()), null); ListenableFuture installFlowResult = mdsalManager.removeFlow(input.getDpnId(), terminatingServiceTableFlow); Futures.addCallback(installFlowResult, new FutureCallback() { @Override public void onSuccess(Void voidInstance) { result.set(RpcResultBuilder.success().build()); } @Override public void onFailure(Throwable error) { String msg = String.format("Unable to remove terminating service flow for %s", input.getDpnId()); LOG.error("remove terminating service actions failed. {}", msg, error); result.set(RpcResultBuilder.failed().withError(RpcError.ErrorType.APPLICATION, msg, error) .build()); } }, MoreExecutors.directExecutor()); //result.set(RpcResultBuilder.success().build()); return result ; } public List getTunnelMatchesForServiceId(int serviceId) { final List mkMatches = new ArrayList<>(); // Matching metadata mkMatches.add(new MatchTunnelId(BigInteger.valueOf(serviceId))); return mkMatches; } private String getFlowRef(long termSvcTable, int svcId) { return String.valueOf(termSvcTable) + svcId; } @Override public Future> getInternalOrExternalInterfaceName( GetInternalOrExternalInterfaceNameInput input) { RpcResultBuilder resultBld = RpcResultBuilder.failed(); BigInteger srcDpn = input.getSourceDpid() ; IpAddress dstIp = input.getDestinationIp() ; InstanceIdentifier path1 = InstanceIdentifier.create(ExternalTunnelList.class) .child(ExternalTunnel.class, new ExternalTunnelKey(String.valueOf(dstIp.getValue()), srcDpn.toString(), input.getTunnelType())); Optional optExtTunnel = ItmUtils.read(LogicalDatastoreType.CONFIGURATION, path1, dataBroker); if (optExtTunnel != null && optExtTunnel.isPresent()) { ExternalTunnel extTunnel = optExtTunnel.get(); GetInternalOrExternalInterfaceNameOutputBuilder output = new GetInternalOrExternalInterfaceNameOutputBuilder() .setInterfaceName(extTunnel.getTunnelInterfaceName()); resultBld = RpcResultBuilder.success(); resultBld.withResult(output.build()) ; } else { Collection meshedDpnList = dpnTEPsInfoCache.getAllPresent(); // Look for external tunnels if not look for internal tunnel for (DPNTEPsInfo teps : meshedDpnList) { TunnelEndPoints firstEndPt = teps.getTunnelEndPoints().get(0); if (dstIp.equals(firstEndPt.getIpAddress())) { Optional optTunnel = Optional.absent(); if (ItmUtils.isTunnelAggregationUsed(input.getTunnelType())) { optTunnel = ItmUtils.getInternalTunnelFromDS(srcDpn, teps.getDPNID(), TunnelTypeLogicalGroup.class, dataBroker); LOG.debug("MULTIPLE_VxLAN_TUNNELS: getInternalOrExternalInterfaceName {}", optTunnel); } if (!optTunnel.isPresent()) { optTunnel = ItmUtils.getInternalTunnelFromDS(srcDpn, teps.getDPNID(), input.getTunnelType(), dataBroker); } if (optTunnel.isPresent()) { InternalTunnel tunnel = optTunnel.get(); List tunnelInterfaces = tunnel.getTunnelInterfaceNames(); if (tunnelInterfaces != null && !tunnelInterfaces.isEmpty()) { GetInternalOrExternalInterfaceNameOutputBuilder output = new GetInternalOrExternalInterfaceNameOutputBuilder() .setInterfaceName(tunnelInterfaces.get(0)); resultBld = RpcResultBuilder.success(); resultBld.withResult(output.build()); } else { LOG.error("No tunnel interface found between source DPN {} ans destination IP {}", srcDpn, dstIp); } break; } else { LOG.error("Tunnel not found for source DPN {} ans destination IP {}", srcDpn, dstIp); } } } } return Futures.immediateFuture(resultBld.build()); } @SuppressWarnings("checkstyle:IllegalCatch") @Override public Future> deleteL2GwDevice(DeleteL2GwDeviceInput input) { final SettableFuture> result = SettableFuture.create(); boolean foundVxlanTzone = false; try { final IpAddress hwIp = input.getIpAddress(); final String nodeId = input.getNodeId(); InstanceIdentifier containerPath = InstanceIdentifier.create(TransportZones.class); Optional transportZonesOptional = ItmUtils.read(LogicalDatastoreType.CONFIGURATION, containerPath, dataBroker); if (transportZonesOptional.isPresent()) { TransportZones transportZones = transportZonesOptional.get(); if (transportZones.getTransportZone() == null || transportZones.getTransportZone().isEmpty()) { LOG.error("No teps configured"); result.set(RpcResultBuilder.failed() .withError(RpcError.ErrorType.APPLICATION, "No teps Configured").build()); return result; } for (TransportZone tzone : transportZones.getTransportZone()) { if (!tzone.getTunnelType().equals(TunnelTypeVxlan.class)) { continue; } foundVxlanTzone = true; String transportZone = tzone.getZoneName(); if (tzone.getSubnets() == null || tzone.getSubnets().isEmpty()) { result.set(RpcResultBuilder.failed() .withError(RpcError.ErrorType.APPLICATION, "No subnets Configured").build()); return result; } SubnetsKey subnetsKey = tzone.getSubnets().get(0).getKey(); DeviceVtepsKey deviceVtepKey = new DeviceVtepsKey(hwIp, nodeId); InstanceIdentifier path = InstanceIdentifier.builder(TransportZones.class) .child(TransportZone.class, new TransportZoneKey(transportZone)) .child(Subnets.class, subnetsKey).child(DeviceVteps.class, deviceVtepKey) .build(); WriteTransaction transaction = dataBroker.newWriteOnlyTransaction(); //TO DO: add retry if it fails transaction.delete(LogicalDatastoreType.CONFIGURATION, path); ListenableFuture futureCheck = transaction.submit(); Futures.addCallback(futureCheck, new FutureCallback() { @Override public void onSuccess(Void voidInstance) { result.set(RpcResultBuilder.success().build()); } @Override public void onFailure(Throwable error) { String msg = String.format("Unable to delete HwVtep %s from datastore", nodeId); LOG.error("Unable to delete HwVtep {}, {} from datastore", nodeId, hwIp); result.set(RpcResultBuilder.failed() .withError(RpcError.ErrorType.APPLICATION, msg, error).build()); } }); } } else { result.set(RpcResultBuilder.failed() .withError(RpcError.ErrorType.APPLICATION, "No TransportZones configured").build()); return result; } if (!foundVxlanTzone) { result.set(RpcResultBuilder.failed() .withError(RpcError.ErrorType.APPLICATION, "No VxLan TransportZones configured") .build()); } return result; } catch (Exception e) { RpcResultBuilder resultBuilder = RpcResultBuilder.failed() .withError(RpcError.ErrorType.APPLICATION, "Deleting l2 Gateway to DS Failed", e); return Futures.immediateFuture(resultBuilder.build()); } } @SuppressWarnings("checkstyle:IllegalCatch") @Override public Future> addL2GwDevice(AddL2GwDeviceInput input) { final SettableFuture> result = SettableFuture.create(); boolean foundVxlanTzone = false; try { final IpAddress hwIp = input.getIpAddress(); final String nodeId = input.getNodeId(); //iterate through all transport zones and put TORs under vxlan //if no vxlan tzone is cnfigured, return an error. InstanceIdentifier containerPath = InstanceIdentifier.create(TransportZones.class); Optional transportZonesOptional = ItmUtils.read(LogicalDatastoreType.CONFIGURATION, containerPath, dataBroker); if (transportZonesOptional.isPresent()) { TransportZones transportZones = transportZonesOptional.get(); if (transportZones.getTransportZone() == null || transportZones.getTransportZone().isEmpty()) { LOG.error("No transportZone configured"); result.set(RpcResultBuilder.failed() .withError(RpcError.ErrorType.APPLICATION, "No transportZone Configured").build()); return result; } for (TransportZone tzone : transportZones.getTransportZone()) { if (!tzone.getTunnelType().equals(TunnelTypeVxlan.class)) { continue; } String transportZone = tzone.getZoneName(); if (tzone.getSubnets() == null || tzone.getSubnets().isEmpty()) { continue; } foundVxlanTzone = true; SubnetsKey subnetsKey = tzone.getSubnets().get(0).getKey(); DeviceVtepsKey deviceVtepKey = new DeviceVtepsKey(hwIp, nodeId); InstanceIdentifier path = InstanceIdentifier.builder(TransportZones.class) .child(TransportZone.class, new TransportZoneKey(transportZone)) .child(Subnets.class, subnetsKey).child(DeviceVteps.class, deviceVtepKey) .build(); DeviceVteps deviceVtep = new DeviceVtepsBuilder().setKey(deviceVtepKey).setIpAddress(hwIp) .setNodeId(nodeId).setTopologyId(input.getTopologyId()).build(); WriteTransaction transaction = dataBroker.newWriteOnlyTransaction(); //TO DO: add retry if it fails transaction.put(LogicalDatastoreType.CONFIGURATION, path, deviceVtep, true); ListenableFuture futureCheck = transaction.submit(); Futures.addCallback(futureCheck, new FutureCallback() { @Override public void onSuccess(Void voidInstance) { result.set(RpcResultBuilder.success().build()); } @Override public void onFailure(Throwable error) { String msg = String.format("Unable to write HwVtep %s to datastore", nodeId); LOG.error("Unable to write HwVtep {}, {} to datastore", nodeId, hwIp); result.set(RpcResultBuilder.failed() .withError(RpcError.ErrorType.APPLICATION, msg, error).build()); } }); } } else { result.set(RpcResultBuilder.failed() .withError(RpcError.ErrorType.APPLICATION, "No TransportZones configured").build()); return result; } if (!foundVxlanTzone) { result.set(RpcResultBuilder.failed() .withError(RpcError.ErrorType.APPLICATION, "No VxLan TransportZones configured") .build()); } return result; } catch (Exception e) { RpcResultBuilder resultBuilder = RpcResultBuilder.failed() .withError(RpcError.ErrorType.APPLICATION, "Adding l2 Gateway to DS Failed", e); return Futures.immediateFuture(resultBuilder.build()); } } @SuppressWarnings("checkstyle:IllegalCatch") @Override public Future> addL2GwMlagDevice(AddL2GwMlagDeviceInput input) { final SettableFuture> result = SettableFuture.create(); try { final IpAddress hwIp = input.getIpAddress(); final List nodeId = input.getNodeId(); InstanceIdentifier containerPath = InstanceIdentifier.create(TransportZones.class); Optional transportZonesOptional = ItmUtils.read(LogicalDatastoreType.CONFIGURATION, containerPath, dataBroker); if (transportZonesOptional.isPresent()) { TransportZones transportZones = transportZonesOptional.get(); if (transportZones.getTransportZone() == null || transportZones.getTransportZone().isEmpty()) { LOG.error("No teps configured"); result.set(RpcResultBuilder.failed() .withError(RpcError.ErrorType.APPLICATION, "No teps Configured").build()); return result; } String transportZone = transportZones.getTransportZone().get(0).getZoneName(); if (transportZones.getTransportZone().get(0).getSubnets() == null || transportZones.getTransportZone().get(0).getSubnets().isEmpty()) { result.set(RpcResultBuilder.failed() .withError(RpcError.ErrorType.APPLICATION, "No subnets Configured").build()); return result; } SubnetsKey subnetsKey = transportZones.getTransportZone().get(0).getSubnets().get(0).getKey(); DeviceVtepsKey deviceVtepKey = new DeviceVtepsKey(hwIp, nodeId.get(0)); InstanceIdentifier path = InstanceIdentifier.builder(TransportZones.class) .child(TransportZone.class, new TransportZoneKey(transportZone)) .child(Subnets.class, subnetsKey).child(DeviceVteps.class, deviceVtepKey).build(); DeviceVteps deviceVtep = new DeviceVtepsBuilder().setKey(deviceVtepKey).setIpAddress(hwIp) .setNodeId(nodeId.get(0)).setTopologyId(input.getTopologyId()).build(); WriteTransaction writeTransaction = dataBroker.newWriteOnlyTransaction(); //TO DO: add retry if it fails LOG.trace("writing hWvtep{}",deviceVtep); writeTransaction.put(LogicalDatastoreType.CONFIGURATION, path, deviceVtep, true); if (nodeId.size() == 2) { LOG.trace("second node-id {}",nodeId.get(1)); DeviceVtepsKey deviceVtepKey2 = new DeviceVtepsKey(hwIp, nodeId.get(1)); InstanceIdentifier path2 = InstanceIdentifier.builder(TransportZones.class) .child(TransportZone.class, new TransportZoneKey(transportZone)) .child(Subnets.class, subnetsKey).child(DeviceVteps.class, deviceVtepKey2).build(); DeviceVteps deviceVtep2 = new DeviceVtepsBuilder().setKey(deviceVtepKey2).setIpAddress(hwIp) .setNodeId(nodeId.get(1)) .setTopologyId(input.getTopologyId()).build(); //TO DO: add retry if it fails LOG.trace("writing {}",deviceVtep2); writeTransaction.put(LogicalDatastoreType.CONFIGURATION, path2, deviceVtep2, true); } ListenableFuture futureCheck = writeTransaction.submit(); Futures.addCallback(futureCheck, new FutureCallback() { @Override public void onSuccess(Void voidInstance) { result.set(RpcResultBuilder.success().build()); } @Override public void onFailure(Throwable error) { String msg = String.format("Unable to write HwVtep %s to datastore", nodeId); LOG.error("Unable to write HwVtep {}, {} to datastore", nodeId , hwIp); result.set(RpcResultBuilder.failed().withError(RpcError.ErrorType.APPLICATION, msg, error) .build()); } }, MoreExecutors.directExecutor()); } return result; } catch (RuntimeException e) { RpcResultBuilder resultBuilder = RpcResultBuilder.failed() .withError(RpcError.ErrorType.APPLICATION, "Adding l2 Gateway to DS Failed", e); return Futures.immediateFuture(resultBuilder.build()); } } @SuppressWarnings("checkstyle:IllegalCatch") @Override public Future> deleteL2GwMlagDevice(DeleteL2GwMlagDeviceInput input) { final SettableFuture> result = SettableFuture.create(); try { final IpAddress hwIp = input.getIpAddress(); final List nodeId = input.getNodeId(); InstanceIdentifier containerPath = InstanceIdentifier.create(TransportZones.class); Optional transportZonesOptional = ItmUtils.read(LogicalDatastoreType.CONFIGURATION, containerPath, dataBroker); if (transportZonesOptional.isPresent()) { TransportZones tzones = transportZonesOptional.get(); if (tzones.getTransportZone() == null || tzones.getTransportZone().isEmpty()) { LOG.error("No teps configured"); result.set(RpcResultBuilder.failed() .withError(RpcError.ErrorType.APPLICATION, "No teps Configured").build()); return result; } String transportZone = tzones.getTransportZone().get(0).getZoneName(); if (tzones.getTransportZone().get(0).getSubnets() == null || tzones.getTransportZone() .get(0).getSubnets().isEmpty()) { result.set(RpcResultBuilder.failed() .withError(RpcError.ErrorType.APPLICATION, "No subnets Configured").build()); return result; } SubnetsKey subnetsKey = tzones.getTransportZone().get(0).getSubnets().get(0).getKey(); DeviceVtepsKey deviceVtepKey = new DeviceVtepsKey(hwIp, nodeId.get(0)); InstanceIdentifier path = InstanceIdentifier.builder(TransportZones.class) .child(TransportZone.class, new TransportZoneKey(transportZone)) .child(Subnets.class, subnetsKey).child(DeviceVteps.class, deviceVtepKey).build(); WriteTransaction transaction = dataBroker.newWriteOnlyTransaction(); //TO DO: add retry if it fails transaction.delete(LogicalDatastoreType.CONFIGURATION, path); DeviceVtepsKey deviceVtepKey2 = new DeviceVtepsKey(hwIp, nodeId.get(1)); InstanceIdentifier path2 = InstanceIdentifier.builder(TransportZones.class) .child(TransportZone.class, new TransportZoneKey(transportZone)) .child(Subnets.class, subnetsKey).child(DeviceVteps.class, deviceVtepKey2).build(); //TO DO: add retry if it fails transaction.delete(LogicalDatastoreType.CONFIGURATION, path2); ListenableFuture futureCheck = transaction.submit(); Futures.addCallback(futureCheck, new FutureCallback() { @Override public void onSuccess(Void voidInstance) { result.set(RpcResultBuilder.success().build()); } @Override public void onFailure(Throwable error) { String msg = String.format("Unable to write HwVtep %s to datastore", nodeId); LOG.error("Unable to write HwVtep {}, {} to datastore", nodeId , hwIp); result.set(RpcResultBuilder.failed().withError(RpcError.ErrorType.APPLICATION, msg, error) .build()); } }); } return result; } catch (Exception e) { RpcResultBuilder resultBuilder = RpcResultBuilder.failed() .withError(RpcError.ErrorType.APPLICATION, "Deleting l2 Gateway to DS Failed", e); return Futures.immediateFuture(resultBuilder.build()); } } @Override public Future> isTunnelInternalOrExternal( IsTunnelInternalOrExternalInput input) { RpcResultBuilder resultBld; String tunIfName = input.getTunnelInterfaceName(); long tunVal = 0; IsTunnelInternalOrExternalOutputBuilder output = new IsTunnelInternalOrExternalOutputBuilder() .setTunnelType(tunVal); if (ItmUtils.ITM_CACHE.getInternalTunnel(tunIfName) != null) { tunVal = 1; } else if (ItmUtils.ITM_CACHE.getExternalTunnel(tunIfName) != null) { tunVal = 2; } output.setTunnelType(tunVal); resultBld = RpcResultBuilder.success(); resultBld.withResult(output.build()); return Futures.immediateFuture(resultBld.build()); } @Override public Future> isDcgwPresent(IsDcgwPresentInput input) { RpcResultBuilder resultBld = RpcResultBuilder.success(); List dcGatewayIpList = ItmUtils.getDcGatewayIpList(dataBroker); String dcgwIpStr = input.getDcgwIp(); IpAddress dcgwIpAddr = IpAddressBuilder.getDefaultInstance(dcgwIpStr); long retVal; if (dcGatewayIpList != null && !dcGatewayIpList.isEmpty() && dcGatewayIpList.stream().anyMatch(gwIp -> Objects.equal(gwIp.getIpAddress(), dcgwIpAddr))) { //Match found retVal = 1; IsDcgwPresentOutputBuilder output = new IsDcgwPresentOutputBuilder().setRetVal(retVal); resultBld.withResult(output.build()); } else { //Match not found retVal = 2; IsDcgwPresentOutputBuilder output = new IsDcgwPresentOutputBuilder().setRetVal(retVal); resultBld.withResult(output.build()); } return Futures.immediateFuture(resultBld.build()); } @Override public Future> getDpnEndpointIps(GetDpnEndpointIpsInput input) { BigInteger srcDpn = input.getSourceDpid() ; RpcResultBuilder resultBld = RpcResultBuilder.failed(); InstanceIdentifier tunnelInfoId = InstanceIdentifier.builder(DpnEndpoints.class).child(DPNTEPsInfo.class, new DPNTEPsInfoKey(srcDpn)).build(); Optional tunnelInfo = ItmUtils.read(LogicalDatastoreType.CONFIGURATION, tunnelInfoId, dataBroker); if (!tunnelInfo.isPresent()) { LOG.error("tunnelInfo is not present"); return Futures.immediateFuture(resultBld.build()); } List tunnelEndPointList = tunnelInfo.get().getTunnelEndPoints(); if (tunnelEndPointList == null || tunnelEndPointList.isEmpty()) { LOG.error("tunnelEndPointList is null or empty"); return Futures.immediateFuture(resultBld.build()); } List nexthopIpList = new ArrayList<>(); tunnelEndPointList.forEach(tunnelEndPoint -> nexthopIpList.add(tunnelEndPoint.getIpAddress())); GetDpnEndpointIpsOutputBuilder output = new GetDpnEndpointIpsOutputBuilder().setNexthopipList(nexthopIpList); resultBld = RpcResultBuilder.success(); resultBld.withResult(output.build()) ; return Futures.immediateFuture(resultBld.build()); } @Override public Future> getDpnInfo(GetDpnInfoInput input) { return FutureRpcResults.fromListenableFuture(LOG, "getDpnInfo", input, () -> Futures.immediateFuture(getDpnInfoInternal(input))).build(); } private GetDpnInfoOutput getDpnInfoInternal(GetDpnInfoInput input) throws ReadFailedException { Map computeNamesVsDpnIds = getDpnIdByComputeNodeNameFromOpInventoryNodes(input.getComputeNames()); Map dpnIdVsVtepsComputes = getTunnelEndPointByDpnIdFromTranPortZone(computeNamesVsDpnIds.values()); List computes = computeNamesVsDpnIds.entrySet().stream() .map(entry -> dpnIdVsVtepsComputes.get(entry.getValue()).setComputeName(entry.getKey()).build()) .collect(Collectors.toList()); return new GetDpnInfoOutputBuilder().setComputes(computes).build(); } private Map getTunnelEndPointByDpnIdFromTranPortZone(Collection dpnIds) throws ReadFailedException { TransportZones transportZones = singleTransactionDataBroker.syncRead( LogicalDatastoreType.CONFIGURATION, InstanceIdentifier.builder(TransportZones.class).build()); if (transportZones.getTransportZone() == null || transportZones.getTransportZone().isEmpty()) { throw new IllegalStateException("Failed to find transport zones in config datastore"); } Map result = new HashMap<>(); for (TransportZone transportZone : transportZones.getTransportZone()) { if (transportZone.getSubnets() == null || transportZone.getSubnets().isEmpty()) { LOG.debug("Transport Zone {} has no subnets", transportZone.getZoneName()); continue; } for (Subnets sub : transportZone.getSubnets()) { if (sub.getVteps() == null || sub.getVteps().isEmpty()) { LOG.debug("Transport Zone {} subnet {} has no vteps configured", transportZone.getZoneName(), sub.getPrefix()); continue; } for (Vteps vtep : sub.getVteps()) { if (dpnIds.contains(vtep.getDpnId())) { result.putIfAbsent(vtep.getDpnId(), new ComputesBuilder() .setZoneName(transportZone.getZoneName()) .setPrefix(sub.getPrefix()) .setDpnId(vtep.getDpnId()) .setPortName(vtep.getPortname()) .setNodeId(getNodeId(vtep.getDpnId())) .setTepIp(Collections.singletonList(vtep.getIpAddress()))); } } } } for (BigInteger dpnId : dpnIds) { if (!result.containsKey(dpnId)) { throw new IllegalStateException("Failed to find dpn id " + dpnId + " in transport zone"); } } return result; } private Map getDpnIdByComputeNodeNameFromOpInventoryNodes(List nodeNames) throws ReadFailedException { Nodes operInventoryNodes = singleTransactionDataBroker.syncRead( LogicalDatastoreType.OPERATIONAL, InstanceIdentifier.builder(Nodes.class).build()); if (operInventoryNodes.getNode() == null || operInventoryNodes.getNode().isEmpty()) { throw new IllegalStateException("Failed to find operational inventory nodes datastore"); } Map result = new HashMap<>(); for (Node node : operInventoryNodes.getNode()) { String name = node.getAugmentation(FlowCapableNode.class).getDescription(); if (nodeNames.contains(name)) { String[] nodeId = node.getId().getValue().split(":"); result.put(name, new BigInteger(nodeId[1])); } } for (String nodeName : nodeNames) { if (!result.containsKey(nodeName)) { throw new IllegalStateException("Failed to find dpn id of compute node name from oper inventory " + nodeName); } } return result; } private String getNodeId(BigInteger dpnId) throws ReadFailedException { InstanceIdentifier path = InstanceIdentifier .builder(BridgeRefInfo.class) .child(BridgeRefEntry.class, new BridgeRefEntryKey(dpnId)).build(); BridgeRefEntry bridgeRefEntry = singleTransactionDataBroker.syncRead(LogicalDatastoreType.OPERATIONAL, path); return bridgeRefEntry.getBridgeReference().getValue() .firstKeyOf(org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021 .network.topology.topology.Node.class).getNodeId().getValue(); } }