X-Git-Url: https://git.opendaylight.org/gerrit/gitweb?a=blobdiff_plain;f=vpnservice%2Fvpnmanager%2Fvpnmanager-impl%2Fsrc%2Fmain%2Fjava%2Forg%2Fopendaylight%2Fnetvirt%2Fvpnmanager%2FTunnelInterfaceStateListener.java;h=4ad3998ab2ee14d0831d96c1d42be4ce484b07c2;hb=b091bfc1e2b88330a079afe1102c3a773a1de7fd;hp=4420ce76951db822e8f76886b6b8adc15a903067;hpb=c12d5320963e8dcc6a4996ea8f07ab73bdbfb53c;p=netvirt.git diff --git a/vpnservice/vpnmanager/vpnmanager-impl/src/main/java/org/opendaylight/netvirt/vpnmanager/TunnelInterfaceStateListener.java b/vpnservice/vpnmanager/vpnmanager-impl/src/main/java/org/opendaylight/netvirt/vpnmanager/TunnelInterfaceStateListener.java index 4420ce7695..4ad3998ab2 100644 --- a/vpnservice/vpnmanager/vpnmanager-impl/src/main/java/org/opendaylight/netvirt/vpnmanager/TunnelInterfaceStateListener.java +++ b/vpnservice/vpnmanager/vpnmanager-impl/src/main/java/org/opendaylight/netvirt/vpnmanager/TunnelInterfaceStateListener.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2016 Ericsson India Global Services Pvt Ltd. and others. All rights reserved. + * Copyright © 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, @@ -7,283 +7,571 @@ */ package org.opendaylight.netvirt.vpnmanager; +import static java.util.stream.Collectors.toList; + import com.google.common.base.Optional; +import com.google.common.base.Strings; +import com.google.common.util.concurrent.ListenableFuture; import java.math.BigInteger; +import java.util.ArrayList; +import java.util.Collections; +import java.util.HashMap; +import java.util.HashSet; import java.util.Iterator; import java.util.List; +import java.util.Map; +import java.util.Set; +import java.util.concurrent.Callable; import java.util.concurrent.Future; +import javax.annotation.PostConstruct; +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.DataChangeListener; -import org.opendaylight.controller.md.sal.common.api.data.AsyncDataBroker; +import org.opendaylight.controller.md.sal.binding.api.WriteTransaction; import org.opendaylight.controller.md.sal.common.api.data.LogicalDatastoreType; -import org.opendaylight.netvirt.bgpmanager.api.IBgpManager; +import org.opendaylight.genius.datastoreutils.AsyncDataTreeChangeListenerBase; +import org.opendaylight.genius.mdsalutil.MDSALUtil; +import org.opendaylight.genius.mdsalutil.NwConstants; +import org.opendaylight.infrautils.jobcoordinator.JobCoordinator; import org.opendaylight.netvirt.fibmanager.api.IFibManager; -import org.opendaylight.yang.gen.v1.urn.huawei.params.xml.ns.yang.l3vpn.rev140815.VpnAfConfig; -import org.opendaylight.yang.gen.v1.urn.huawei.params.xml.ns.yang.l3vpn.rev140815.VpnInstances; -import org.opendaylight.yang.gen.v1.urn.huawei.params.xml.ns.yang.l3vpn.rev140815.vpn.instances.VpnInstance; +import org.opendaylight.netvirt.vpnmanager.api.InterfaceUtils; +import org.opendaylight.netvirt.vpnmanager.api.VpnExtraRouteHelper; +import org.opendaylight.netvirt.vpnmanager.api.VpnHelper; import org.opendaylight.yang.gen.v1.urn.huawei.params.xml.ns.yang.l3vpn.rev140815.vpn.interfaces.VpnInterface; +import org.opendaylight.yang.gen.v1.urn.huawei.params.xml.ns.yang.l3vpn.rev140815.vpn.interfaces.vpn._interface.VpnInstanceNames; +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.interfaces.rev140508.interfaces.Interface; +import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.yang.types.rev130715.Uuid; +import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.interfacemanager.rev160406.IfTunnel; +import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.interfacemanager.rev160406.ParentRefs; +import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.interfacemanager.rev160406.TunnelTypeMplsOverGre; +import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.interfacemanager.rev160406.TunnelTypeVxlan; +import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.interfacemanager.rpcs.rev160406.GetDpnInterfaceListInputBuilder; +import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.interfacemanager.rpcs.rev160406.GetDpnInterfaceListOutput; +import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.interfacemanager.rpcs.rev160406.OdlInterfaceRpcService; import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.itm.op.rev160406.TepTypeExternal; import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.itm.op.rev160406.TepTypeHwvtep; import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.itm.op.rev160406.TepTypeInternal; +import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.itm.op.rev160406.TunnelOperStatus; import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.itm.op.rev160406.TunnelsState; import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.itm.op.rev160406.tunnels_state.StateTunnelList; -import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.itm.rpcs.rev160406.IsDcgwPresentInputBuilder; -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.ItmRpcService; +import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.itm.rev160406.DcGatewayIpList; +import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.fibmanager.rev150330.extraroute.rds.map.extraroute.rds.DestPrefixes; import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.fibmanager.rev150330.vrfentries.VrfEntry; -import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.l3vpn.rev130911.Adjacencies; +import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.fibmanager.rev150330.vrfentrybase.RoutePaths; +import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.l3vpn.rev130911.AdjacenciesOp; +import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.l3vpn.rev130911.PortOpData; import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.l3vpn.rev130911.adjacency.list.Adjacency; -import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.l3vpn.rev130911.vpn.instance.op.data.vpn.instance.op.data.entry.VpnToDpnList; -import org.opendaylight.yangtools.concepts.ListenerRegistration; +import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.l3vpn.rev130911.port.op.data.PortOpDataEntry; +import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.l3vpn.rev130911.port.op.data.PortOpDataEntryKey; +import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.l3vpn.rev130911.vpn._interface.op.data.VpnInterfaceOpDataEntry; +import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.l3vpn.rev130911.vpn.instance.op.data.VpnInstanceOpDataEntry; import org.opendaylight.yangtools.yang.binding.InstanceIdentifier; import org.opendaylight.yangtools.yang.common.RpcResult; import org.slf4j.Logger; import org.slf4j.LoggerFactory; -public class TunnelInterfaceStateListener extends AbstractDataChangeListener - implements AutoCloseable{ +@Singleton +public class TunnelInterfaceStateListener extends AsyncDataTreeChangeListenerBase { private static final Logger LOG = LoggerFactory.getLogger(TunnelInterfaceStateListener.class); - private ListenerRegistration listenerRegistration; private final DataBroker dataBroker; - private final IBgpManager bgpManager; - private IFibManager fibManager; - private ItmRpcService itmRpcService; + private final IFibManager fibManager; + private final OdlInterfaceRpcService intfRpcService; + private final VpnInterfaceManager vpnInterfaceManager; + private final VpnSubnetRouteHandler vpnSubnetRouteHandler; + private final JobCoordinator jobCoordinator; + protected enum UpdateRouteAction { ADVERTISE_ROUTE, WITHDRAW_ROUTE } + protected enum TunnelAction { + TUNNEL_EP_ADD, + TUNNEL_EP_DELETE, + TUNNEL_EP_UPDATE + } + /** - * Responsible for listening to tunnel interface state change - * - * @param dataBroker dataBroker - * @param bgpManager bgpManager - * @param fibManager fibManager - * @param itmRpcService itmRpcService + * Responsible for listening to tunnel interface state change. */ + @Inject public TunnelInterfaceStateListener(final DataBroker dataBroker, - final IBgpManager bgpManager, - final IFibManager fibManager, - final ItmRpcService itmRpcService) { - super(StateTunnelList.class); + final IFibManager fibManager, + final OdlInterfaceRpcService ifaceMgrRpcService, + final VpnInterfaceManager vpnInterfaceManager, + final VpnSubnetRouteHandler vpnSubnetRouteHandler, + final JobCoordinator jobCoordinator) { + super(StateTunnelList.class, TunnelInterfaceStateListener.class); this.dataBroker = dataBroker; - this.bgpManager = bgpManager; this.fibManager = fibManager; - this.itmRpcService = itmRpcService; + this.intfRpcService = ifaceMgrRpcService; + this.vpnInterfaceManager = vpnInterfaceManager; + this.vpnSubnetRouteHandler = vpnSubnetRouteHandler; + this.jobCoordinator = jobCoordinator; } + @PostConstruct public void start() { LOG.info("{} start", getClass().getSimpleName()); - listenerRegistration = dataBroker.registerDataChangeListener(LogicalDatastoreType.OPERATIONAL, - getWildCardPath(), this, AsyncDataBroker.DataChangeScope.SUBTREE); + registerListener(LogicalDatastoreType.OPERATIONAL, dataBroker); } - private InstanceIdentifier getWildCardPath() { + @Override + protected InstanceIdentifier getWildCardPath() { return InstanceIdentifier.create(TunnelsState.class).child(StateTunnelList.class); } @Override - public void close() throws Exception { - if (listenerRegistration != null) { - listenerRegistration.close(); - listenerRegistration = null; - } - LOG.info("{} close", getClass().getSimpleName()); + protected TunnelInterfaceStateListener getDataTreeChangeListener() { + return TunnelInterfaceStateListener.this; } @Override protected void remove(InstanceIdentifier identifier, StateTunnelList del) { - LOG.trace("Tunnel deletion---- {}", del); - handlePrefixesForDPNs(del, UpdateRouteAction.WITHDRAW_ROUTE); + LOG.trace("remove: Tunnel deletion---- {}", del); + if (isGreTunnel(del)) { + programDcGwLoadBalancingGroup(del, NwConstants.DEL_FLOW); + } + handleTunnelEventForDPN(del, UpdateRouteAction.WITHDRAW_ROUTE, TunnelAction.TUNNEL_EP_DELETE); } @Override - protected void update(InstanceIdentifier identifier, StateTunnelList original, StateTunnelList update) { - LOG.trace("Tunnel updation---- {}", update); - LOG.trace("ITM Tunnel {} of type {} state event changed from :{} to :{}", - update.getTunnelInterfaceName(), - fibManager.getTransportTypeStr(update.getTransportType().toString()), - original.isTunnelState(), update.isTunnelState()); - //withdraw all prefixes in all vpns for this dpn - boolean isTunnelUp = update.isTunnelState(); - handlePrefixesForDPNs(update, isTunnelUp ? UpdateRouteAction.ADVERTISE_ROUTE : - UpdateRouteAction.WITHDRAW_ROUTE); + protected void update(InstanceIdentifier identifier, StateTunnelList original, + StateTunnelList update) { + LOG.trace("update: Tunnel updation---- {}", update); + LOG.info("update: ITM Tunnel {} of type {} state event changed from :{} to :{}", + update.getTunnelInterfaceName(), + fibManager.getTransportTypeStr(update.getTransportType().toString()), + original.getOperState(), update.getOperState()); + TunnelOperStatus tunOpStatus = update.getOperState(); + if (tunOpStatus != TunnelOperStatus.Down && tunOpStatus != TunnelOperStatus.Up) { + LOG.info("update: Returning from unsupported tunnelOperStatus {} for tunnel interface {}", tunOpStatus, + update.getTunnelInterfaceName()); + return; + } + if (isGreTunnel(update)) { + programDcGwLoadBalancingGroup(update, NwConstants.MOD_FLOW); + } + + //Remove the corresponding nexthop from the routepath under extraroute in fibentries. + BigInteger srcDpnId = new BigInteger(update.getSrcInfo().getTepDeviceId()); + String srcTepIp = String.valueOf(update.getSrcInfo().getTepIp().getValue()); + List vpnInstanceOpData = VpnUtil.getAllVpnInstanceOpData(dataBroker); + if (vpnInstanceOpData == null) { + LOG.trace("update: No vpnInstanceOpdata present"); + return; + } + WriteTransaction writeConfigTxn = dataBroker.newWriteOnlyTransaction(); + if (tunOpStatus == TunnelOperStatus.Up) { + handleTunnelEventForDPN(update, UpdateRouteAction.ADVERTISE_ROUTE, TunnelAction.TUNNEL_EP_ADD); + } else { + vpnInstanceOpData.stream().filter(opData -> { + if (opData.getVpnToDpnList() == null) { + return false; + } + return opData.getVpnToDpnList().stream().anyMatch(vpnToDpn -> vpnToDpn.getDpnId().equals(srcDpnId)); + }).forEach(opData -> { + List prefixes = VpnExtraRouteHelper.getExtraRouteDestPrefixes(dataBroker, + opData.getVpnId()); + prefixes.forEach(destPrefix -> { + VrfEntry vrfEntry = VpnUtil.getVrfEntry(dataBroker, opData.getVrfId(), + destPrefix.getDestPrefix()); + if (vrfEntry == null || vrfEntry.getRoutePaths() == null) { + return; + } + List routePaths = vrfEntry.getRoutePaths(); + routePaths.forEach(routePath -> { + if (routePath.getNexthopAddress().equals(srcTepIp)) { + fibManager.updateRoutePathForFibEntry(dataBroker, opData.getVrfId(), + destPrefix.getDestPrefix(), srcTepIp, routePath.getLabel(), + false, writeConfigTxn); + } + }); + }); + }); + } + writeConfigTxn.submit(); } @Override protected void add(InstanceIdentifier identifier, StateTunnelList add) { - LOG.trace("Tunnel addition---- {}", add); - - if (!add.isTunnelState()) { - LOG.trace("Tunnel {} is not yet UP.", + LOG.trace("add: Tunnel addition---- {}", add); + TunnelOperStatus tunOpStatus = add.getOperState(); + if (tunOpStatus != TunnelOperStatus.Down && tunOpStatus != TunnelOperStatus.Up) { + LOG.info("add: Returning from unsupported tunnelOperStatus {} for tunnel interface {}", tunOpStatus, add.getTunnelInterfaceName()); return; - } else { - LOG.trace("ITM Tunnel ,type {} ,State is UP b/w src: {} and dest: {}", - fibManager.getTransportTypeStr(add.getTransportType().toString()), - add.getSrcInfo().getTepDeviceId(), add.getDstInfo().getTepDeviceId()); - handlePrefixesForDPNs(add, UpdateRouteAction.ADVERTISE_ROUTE); } + if (tunOpStatus != TunnelOperStatus.Up) { + LOG.error("add: Tunnel {} is not yet UP.", add.getTunnelInterfaceName()); + } + if (isGreTunnel(add)) { + programDcGwLoadBalancingGroup(add, NwConstants.ADD_FLOW); + } + LOG.info("add: ITM Tunnel ,type {} ,added between src: {} and dest: {}", + fibManager.getTransportTypeStr(add.getTransportType().toString()), + add.getSrcInfo().getTepDeviceId(), add.getDstInfo().getTepDeviceId()); + handleTunnelEventForDPN(add, UpdateRouteAction.ADVERTISE_ROUTE, TunnelAction.TUNNEL_EP_ADD); } - private void handlePrefixesForDPNs(StateTunnelList stateTunnelList, UpdateRouteAction action) { - BigInteger srcDpnId = new BigInteger(stateTunnelList.getSrcInfo().getTepDeviceId()); - BigInteger destDpnId; - String srcTepIp = String.valueOf(stateTunnelList.getSrcInfo().getTepIp().getValue()); - String destTepIp = String.valueOf(stateTunnelList.getDstInfo().getTepIp().getValue()); + public enum TunnelEventProcessingMethod { + POPULATESUBNETS(0), MANAGEREMOTEROUTES(1); - InstanceIdentifier.InstanceIdentifierBuilder idBuilder = InstanceIdentifier.builder(VpnInstances.class); - InstanceIdentifier vpnInstancesId = idBuilder.build(); - Optional vpnInstances = VpnUtil.read(dataBroker, LogicalDatastoreType.CONFIGURATION, vpnInstancesId); - long tunTypeVal = 0, vpnId; + private final int method; - if (stateTunnelList.getDstInfo().getTepDeviceType() == TepTypeInternal.class) { - tunTypeVal = VpnConstants.ITMTunnelLocType.Internal.getValue(); - } else if (stateTunnelList.getDstInfo().getTepDeviceType() == TepTypeExternal.class) { - tunTypeVal = VpnConstants.ITMTunnelLocType.External.getValue(); - } else if (stateTunnelList.getDstInfo().getTepDeviceType() == TepTypeHwvtep.class) { - tunTypeVal = VpnConstants.ITMTunnelLocType.Hwvtep.getValue(); - } else { - tunTypeVal = VpnConstants.ITMTunnelLocType.Invalid.getValue(); + TunnelEventProcessingMethod(int id) { + this.method = id; } - LOG.trace("tunTypeVal is {}", tunTypeVal); - long dcgwPresentStatus = VpnConstants.DCGWPresentStatus.Invalid.getValue(); - if (tunTypeVal == VpnConstants.ITMTunnelLocType.External.getValue()) { - Future> result; + public int getValue() { + return method; + } + } + + // TODO Clean up the exception handling + @SuppressWarnings("checkstyle:IllegalCatch") + private void handleTunnelEventForDPN(StateTunnelList stateTunnelList, UpdateRouteAction action, + TunnelAction tunnelAction) { + final BigInteger srcDpnId = new BigInteger(stateTunnelList.getSrcInfo().getTepDeviceId()); + final String srcTepIp = String.valueOf(stateTunnelList.getSrcInfo().getTepIp().getValue()); + String destTepIp = String.valueOf(stateTunnelList.getDstInfo().getTepIp().getValue()); + String rd; + BigInteger remoteDpnId = null; + boolean isTepDeletedOnDpn = false; + + LOG.info("handleTunnelEventForDPN: Handle tunnel event for srcDpn {} SrcTepIp {} DestTepIp {} ", + srcDpnId, srcTepIp, destTepIp); + int tunTypeVal = getTunnelType(stateTunnelList); + LOG.trace("handleTunnelEventForDPN: tunTypeVal is {}", tunTypeVal); + try { + if (tunnelAction == TunnelAction.TUNNEL_EP_ADD) { + LOG.info("handleTunnelEventForDPN: Tunnel ADD event received for Dpn {} VTEP Ip {} destTepIp", + srcDpnId, srcTepIp, destTepIp); + if (isTunnelInLogicalGroup(stateTunnelList)) { + return; + } + } else if (tunnelAction == TunnelAction.TUNNEL_EP_DELETE) { + LOG.info("handleTunnelEventForDPN: Tunnel DELETE event received for Dpn {} VTEP Ip {} DestTepIp", + srcDpnId, srcTepIp, destTepIp); + // When tunnel EP is deleted on a DPN , VPN gets two deletion event. + // One for a DPN on which tunnel EP was deleted and another for other-end DPN. + // Update the adj for the vpninterfaces for a DPN on which TEP is deleted. + // Update the adj & VRF for the vpninterfaces for a DPN on which TEP is deleted. + // Dont update the adj & VRF for vpninterfaces for a DPN on which TEP is not deleted. + String endpointIpForDPN = null; + try { + endpointIpForDPN = InterfaceUtils.getEndpointIpAddressForDPN(dataBroker, srcDpnId); + } catch (Exception e) { + LOG.error("handleTunnelEventForDPN: Unable to resolve endpoint IP for srcDpn {}", srcDpnId); + /* this dpn does not have the VTEP */ + endpointIpForDPN = null; + } + + if (endpointIpForDPN == null) { + LOG.info("handleTunnelEventForDPN: Tunnel TEP is deleted on Dpn {} VTEP Ip {} destTepIp", srcDpnId, + srcTepIp, destTepIp); + isTepDeletedOnDpn = true; + } + } + + // Get the list of VpnInterfaces from Intf Mgr for a SrcDPN on which TEP is added/deleted + Future> result; + List srcDpninterfacelist = new ArrayList<>(); + List destDpninterfacelist = new ArrayList<>(); try { - result = itmRpcService.isDcgwPresent(new IsDcgwPresentInputBuilder() - .setDcgwIp(destTepIp) - .build()); - RpcResult rpcResult = result.get(); + result = + intfRpcService.getDpnInterfaceList(new GetDpnInterfaceListInputBuilder().setDpid(srcDpnId).build()); + RpcResult rpcResult = result.get(); if (!rpcResult.isSuccessful()) { - LOG.warn("RPC Call to isDcgwPresent {} returned with Errors {}", destTepIp, rpcResult.getErrors()); + LOG.error("handleTunnelEventForDPN: RPC Call to GetDpnInterfaceList for srcDpnid {} srcTepIp {}" + + " destTepIP {} returned with Errors {}", srcDpnId, srcTepIp, destTepIp, + rpcResult.getErrors()); } else { - dcgwPresentStatus = rpcResult.getResult().getRetVal(); + srcDpninterfacelist = rpcResult.getResult().getInterfacesList(); } } catch (Exception e) { - LOG.warn("Exception {} when querying for isDcgwPresent {}, trace {}", e, destTepIp, e.getStackTrace()); + LOG.error("handleTunnelEventForDPN: Exception {} when querying for GetDpnInterfaceList for srcDpnid {}" + + " srcTepIp {} destTepIp {}, trace {}", e, srcDpnId, srcTepIp, destTepIp, e.getStackTrace()); } - } - - if (vpnInstances.isPresent()) { - List vpnInstanceList = vpnInstances.get().getVpnInstance(); - Iterator vpnInstIter = vpnInstanceList.iterator(); - LOG.trace("vpnInstIter {}", vpnInstIter); - while (vpnInstIter.hasNext()) { - VpnInstance vpnInstance = vpnInstIter.next(); - LOG.trace("vpnInstance {}", vpnInstance); - vpnId = VpnUtil.getVpnId(dataBroker, vpnInstance.getVpnInstanceName()); + // Get the list of VpnInterfaces from Intf Mgr for a destDPN only for internal tunnel. + if (tunTypeVal == VpnConstants.ITMTunnelLocType.Internal.getValue()) { + remoteDpnId = new BigInteger(stateTunnelList.getDstInfo().getTepDeviceId()); try { - VpnAfConfig vpnConfig = vpnInstance.getIpv4Family(); - LOG.trace("vpnConfig {}", vpnConfig); - String rd = vpnConfig.getRouteDistinguisher(); - if (rd == null || rd.isEmpty()) { - rd = vpnInstance.getVpnInstanceName(); - LOG.trace("rd is null or empty. Assigning VpnInstanceName to rd {}", rd); + result = intfRpcService.getDpnInterfaceList( + new GetDpnInterfaceListInputBuilder().setDpid(remoteDpnId).build()); + RpcResult rpcResult = result.get(); + if (!rpcResult.isSuccessful()) { + LOG.error("handleTunnelEventForDPN: RPC Call to GetDpnInterfaceList for remoteDpnid {}" + + " srcTepIP {} destTepIp {} returned with Errors {}", remoteDpnId, srcTepIp, + destTepIp, rpcResult.getErrors()); + } else { + destDpninterfacelist = rpcResult.getResult().getInterfacesList(); } - InstanceIdentifier srcId = - VpnUtil.getVpnToDpnListIdentifier(rd, srcDpnId); - Optional srcDpnInVpn = - VpnUtil.read(dataBroker, LogicalDatastoreType.OPERATIONAL, srcId); - if (tunTypeVal == VpnConstants.ITMTunnelLocType.Internal.getValue()) { - destDpnId = new BigInteger(stateTunnelList.getDstInfo().getTepDeviceId()); - InstanceIdentifier destId = - VpnUtil.getVpnToDpnListIdentifier(rd, destDpnId); - Optional destDpnInVpn = - VpnUtil.read(dataBroker, LogicalDatastoreType.OPERATIONAL, destId); - if (!(srcDpnInVpn.isPresent() && - destDpnInVpn.isPresent())) { - LOG.trace(" srcDpn {} - destDPN {}, do not share the VPN {} with rd {}.", - srcDpnId, destDpnId, vpnInstance.getVpnInstanceName(), rd); - continue; - } + } catch (Exception e) { + LOG.error("handleTunnelEventForDPN: Exception {} when querying for GetDpnInterfaceList" + + " for remoteDpnid {} srcTepIp {} destTepIp {}, trace {}", e, remoteDpnId, + srcTepIp, destTepIp, e.getStackTrace()); + } + } + + /* + * Iterate over the list of VpnInterface for a SrcDpn on which TEP is added or deleted and read the adj. + * Update the adjacencies with the updated nexthop. + */ + Iterator interfacelistIter = srcDpninterfacelist.iterator(); + String intfName = null; + List subnetList = new ArrayList<>(); + Map vpnIdRdMap = new HashMap<>(); + Set listVpnName = new HashSet(); + + while (interfacelistIter.hasNext()) { + intfName = interfacelistIter.next(); + VpnInterface vpnInterface = + VpnUtil.getConfiguredVpnInterface(dataBroker, intfName); + if (vpnInterface != null) { + listVpnName.addAll(VpnHelper + .getVpnInterfaceVpnInstanceNamesString(vpnInterface.getVpnInstanceNames())); + handleTunnelEventForDPNVpn(stateTunnelList, action, vpnIdRdMap, + tunnelAction, isTepDeletedOnDpn, + subnetList, TunnelEventProcessingMethod.POPULATESUBNETS, + vpnInterface); + } + } + /* + * Iterate over the list of VpnInterface for destDPN and get the prefix . + * Create remote rule for each of those prefix on srcDPN. + */ + interfacelistIter = destDpninterfacelist.iterator(); + while (interfacelistIter.hasNext()) { + intfName = interfacelistIter.next(); + VpnInterface vpnInterface = + VpnUtil.getConfiguredVpnInterface(dataBroker, intfName); + if (vpnInterface != null) { + handleTunnelEventForDPNVpn(stateTunnelList, action, vpnIdRdMap, + tunnelAction, isTepDeletedOnDpn, + subnetList, TunnelEventProcessingMethod.MANAGEREMOTEROUTES, + vpnInterface); + } + } + + //Iterate over the VpnId-to-Rd map. + for (Map.Entry entry : vpnIdRdMap.entrySet()) { + Long vpnId = entry.getKey(); + rd = entry.getValue(); + if (tunnelAction == TunnelAction.TUNNEL_EP_ADD + && tunTypeVal == VpnConstants.ITMTunnelLocType.External.getValue()) { + fibManager.populateExternalRoutesOnDpn(srcDpnId, vpnId, rd, srcTepIp, destTepIp); + } else if (tunnelAction == TunnelAction.TUNNEL_EP_DELETE + && tunTypeVal == VpnConstants.ITMTunnelLocType.External.getValue()) { + fibManager.cleanUpExternalRoutesOnDpn(srcDpnId, vpnId, rd, srcTepIp, destTepIp); + } + } + if (listVpnName.size() >= 1) { + if (tunnelAction == TunnelAction.TUNNEL_EP_ADD) { + for (Uuid subnetId : subnetList) { + // Populate the List of subnets + vpnSubnetRouteHandler.updateSubnetRouteOnTunnelUpEvent(subnetId, srcDpnId); } - if (srcDpnInVpn.isPresent()) { - List - vpnInterfaces = srcDpnInVpn.get().getVpnInterfaces(); - for (org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.l3vpn.rev130911.vpn.instance.op.data - .vpn.instance.op.data.entry.vpn.to.dpn.list.VpnInterfaces vpnInterface : vpnInterfaces) { - InstanceIdentifier vpnIntfId = - VpnUtil.getVpnInterfaceIdentifier(vpnInterface.getInterfaceName()); - LOG.trace("vpnInterface {}", vpnInterface); - InstanceIdentifier path = - vpnIntfId.augmentation(Adjacencies.class); - Optional adjacencies = - VpnUtil.read(dataBroker, LogicalDatastoreType.OPERATIONAL, path); - LOG.trace("adjacencies {}", adjacencies); - if (adjacencies.isPresent()) { - List adjacencyList = adjacencies.get().getAdjacency(); - Iterator adjacencyIterator = adjacencyList.iterator(); - - while (adjacencyIterator.hasNext()) { - Adjacency adjacency = adjacencyIterator.next(); - try { - if (action == UpdateRouteAction.ADVERTISE_ROUTE) { - LOG.info("VPNInterfaceManager : Added Fib Entry rd {} prefix {} nextHop {} label {}", - rd, adjacency.getIpAddress(), adjacency.getNextHopIpList(), - adjacency.getLabel()); -// vrf = new VrfEntryBuilder().set - if (tunTypeVal == VpnConstants.ITMTunnelLocType.Internal.getValue()) { - fibManager.handleRemoteRoute(true, - new BigInteger(stateTunnelList.getSrcInfo().getTepDeviceId()), - new BigInteger(stateTunnelList.getDstInfo().getTepDeviceId()), - VpnUtil.getVpnId(dataBroker, vpnInstance.getVpnInstanceName()), - rd, adjacency.getIpAddress(), srcTepIp, destTepIp); - } - if (tunTypeVal == VpnConstants.ITMTunnelLocType.External.getValue()) { - fibManager.populateFibOnDpn(srcDpnId, vpnId, rd, srcTepIp, destTepIp); - } - } else if (action == UpdateRouteAction.WITHDRAW_ROUTE) { - LOG.info("VPNInterfaceManager : Removed Fib entry rd {} prefix {}", - rd, adjacency.getIpAddress()); - if (tunTypeVal == VpnConstants.ITMTunnelLocType.Internal.getValue()) { - fibManager.handleRemoteRoute(false, srcDpnId, - new BigInteger(stateTunnelList.getDstInfo().getTepDeviceId()), - vpnId, rd, adjacency.getIpAddress(), srcTepIp, destTepIp); - } - if ((tunTypeVal == VpnConstants.ITMTunnelLocType.External.getValue()) && - (dcgwPresentStatus == VpnConstants.DCGWPresentStatus.Absent.getValue())) { bgpManager.withdrawPrefix(rd, adjacency.getIpAddress()); - fibManager.cleanUpDpnForVpn(srcDpnId, vpnId, rd, srcTepIp, destTepIp); - } - } - } catch (Exception e) { - LOG.error("Exception when updating prefix {} in vrf {} to BGP", - adjacency.getIpAddress(), rd); - } + } + if ((tunnelAction == TunnelAction.TUNNEL_EP_DELETE) && isTepDeletedOnDpn) { + for (Uuid subnetId : subnetList) { + // Populate the List of subnets + vpnSubnetRouteHandler.updateSubnetRouteOnTunnelDownEvent(subnetId, srcDpnId); + } + } + } + } catch (RuntimeException e) { + LOG.error("handleTunnelEventForDpn: Unable to handle the tunnel event for srcDpnId {} srcTepIp {}" + + " remoteDpnId {} destTepIp {}", srcDpnId, srcTepIp, remoteDpnId, destTepIp, e); + } + } + + // TODO Clean up the exception handling + @SuppressWarnings("checkstyle:IllegalCatch") + private void handleTunnelEventForDPNVpn(StateTunnelList stateTunnelList, UpdateRouteAction action, + Map vpnIdRdMap, TunnelAction tunnelAction, + boolean isTepDeletedOnDpn, List subnetList, + TunnelEventProcessingMethod method, + VpnInterface cfgVpnInterface) { + String rd; + String intfName = cfgVpnInterface.getName(); + final BigInteger srcDpnId = new BigInteger(stateTunnelList.getSrcInfo().getTepDeviceId()); + String destTepIp = String.valueOf(stateTunnelList.getDstInfo().getTepIp().getValue()); + String srcTepIp = String.valueOf(stateTunnelList.getSrcInfo().getTepIp().getValue()); + int tunTypeVal = getTunnelType(stateTunnelList); + BigInteger remoteDpnId = null; + if (tunTypeVal == VpnConstants.ITMTunnelLocType.Internal.getValue()) { + remoteDpnId = new BigInteger(stateTunnelList.getDstInfo().getTepDeviceId()); + } + if (cfgVpnInterface.getVpnInstanceNames() == null) { + LOG.warn("handleTunnelEventForDpn: no vpnName found for interface {}", intfName); + return; + } + for (VpnInstanceNames vpnInstance : cfgVpnInterface.getVpnInstanceNames()) { + String vpnName = vpnInstance.getVpnName(); + if (method == TunnelEventProcessingMethod.POPULATESUBNETS) { + Optional opVpnInterface = VpnUtil + .getVpnInterfaceOpDataEntry(dataBroker, intfName, vpnName); + if (opVpnInterface.isPresent() && !opVpnInterface.get().isScheduledForRemove()) { + VpnInterfaceOpDataEntry vpnInterface = opVpnInterface.get(); + jobCoordinator.enqueueJob("VPNINTERFACE-" + intfName, + new UpdateVpnInterfaceOnTunnelEvent(tunnelAction, + vpnInterface, + stateTunnelList, + isTepDeletedOnDpn)); + + // Populate the List of subnets + InstanceIdentifier portOpIdentifier = + InstanceIdentifier.builder(PortOpData.class).child(PortOpDataEntry.class, + new PortOpDataEntryKey(intfName)).build(); + Optional optionalPortOp = + VpnUtil.read(dataBroker, LogicalDatastoreType.OPERATIONAL, portOpIdentifier); + if (optionalPortOp.isPresent()) { + List subnetIdList = optionalPortOp.get().getSubnetIds(); + if (subnetIdList != null) { + for (Uuid subnetId : subnetIdList) { + if (!subnetList.contains(subnetId)) { + subnetList.add(subnetId); } - } else { - LOG.trace("no adjacencies present for path {}.", path); } } - // if (action == UpdateRouteAction.WITHDRAW_ROUTE) { - // fibManager.cleanUpDpnForVpn(dpnId, VpnUtil.getVpnId(dataBroker, vpnInstance.getVpnInstanceName()), rd); - // } - // Go through all the VrfEntries and withdraw and readvertise the prefixes to BGP for which the nextHop is the SrcTepIp - if ((action == UpdateRouteAction.ADVERTISE_ROUTE) && - (tunTypeVal == VpnConstants.ITMTunnelLocType.External.getValue())) { - List vrfEntries = VpnUtil.getAllVrfEntries(dataBroker, rd); - if (vrfEntries != null) { - for (VrfEntry vrfEntry : vrfEntries) { - String destPrefix = vrfEntry.getDestPrefix().trim(); - int vpnLabel = vrfEntry.getLabel().intValue(); - List nextHops = vrfEntry.getNextHopAddressList(); - if (nextHops.contains(srcTepIp.trim())) { - bgpManager.withdrawPrefix(rd, destPrefix); - bgpManager.advertisePrefix(rd, destPrefix, nextHops, vpnLabel); - } - } + } + //Populate the map for VpnId-to-Rd + long vpnId = VpnUtil.getVpnId(dataBroker, vpnName); + rd = VpnUtil.getVpnRd(dataBroker, vpnName); + vpnIdRdMap.put(vpnId, rd); + } + } else if (method == TunnelEventProcessingMethod.MANAGEREMOTEROUTES) { + Optional opVpnInterface = VpnUtil.getVpnInterfaceOpDataEntry(dataBroker, + intfName, vpnName); + if (opVpnInterface.isPresent()) { + VpnInterfaceOpDataEntry vpnInterface = opVpnInterface.get(); + AdjacenciesOp adjacencies = vpnInterface.getAugmentation(AdjacenciesOp.class); + List adjList = adjacencies != null ? adjacencies.getAdjacency() + : Collections.emptyList(); + String prefix = null; + long vpnId = VpnUtil.getVpnId(dataBroker, vpnInterface.getVpnInstanceName()); + if (vpnIdRdMap.containsKey(vpnId)) { + rd = vpnIdRdMap.get(vpnId); + LOG.info("handleTunnelEventForDPN: Remote DpnId {} VpnId {} rd {} VpnInterface {} srcTepIp " + + "{} destTepIp {}", remoteDpnId, vpnId, rd , vpnInterface, srcTepIp, destTepIp); + for (Adjacency adj : adjList) { + prefix = adj.getIpAddress(); + long label = adj.getLabel(); + if (tunnelAction == TunnelAction.TUNNEL_EP_ADD + && tunTypeVal == VpnConstants.ITMTunnelLocType.Internal.getValue()) { + fibManager.manageRemoteRouteOnDPN(true, srcDpnId, vpnId, rd, prefix, destTepIp, label); + } + + if (tunnelAction == TunnelAction.TUNNEL_EP_DELETE + && tunTypeVal == VpnConstants.ITMTunnelLocType.Internal.getValue()) { + fibManager.manageRemoteRouteOnDPN(false, srcDpnId, vpnId, rd, prefix, destTepIp, label); } } - } else { - LOG.trace("dpnInVpn check failed for srcDpnId {}.", srcDpnId); } - } catch (Exception e) { - LOG.error("updatePrefixesForDPN {} in vpn {} failed", 0, vpnInstance.getVpnInstanceName(), e); } } + } + } + + private class UpdateVpnInterfaceOnTunnelEvent implements Callable { + private final VpnInterfaceOpDataEntry vpnInterface; + private final StateTunnelList stateTunnelList; + private final TunnelAction tunnelAction; + private final boolean isTepDeletedOnDpn; + + UpdateVpnInterfaceOnTunnelEvent(TunnelAction tunnelAction, + VpnInterfaceOpDataEntry vpnInterface, + StateTunnelList stateTunnelList, + boolean isTepDeletedOnDpn) { + this.stateTunnelList = stateTunnelList; + this.vpnInterface = vpnInterface; + this.tunnelAction = tunnelAction; + this.isTepDeletedOnDpn = isTepDeletedOnDpn; + } + + @Override + public List> call() throws Exception { + WriteTransaction writeConfigTxn = dataBroker.newWriteOnlyTransaction(); + WriteTransaction writeOperTxn = dataBroker.newWriteOnlyTransaction(); + List> futures = new ArrayList<>(); + + if (tunnelAction == TunnelAction.TUNNEL_EP_ADD) { + vpnInterfaceManager.updateVpnInterfaceOnTepAdd(vpnInterface, + stateTunnelList, + writeConfigTxn, + writeOperTxn); + } + + if (tunnelAction == TunnelAction.TUNNEL_EP_DELETE && isTepDeletedOnDpn) { + vpnInterfaceManager.updateVpnInterfaceOnTepDelete(vpnInterface, + stateTunnelList, + writeConfigTxn, + writeOperTxn); + } + + futures.add(writeOperTxn.submit()); + futures.add(writeConfigTxn.submit()); + return futures; + } + } + + private int getTunnelType(StateTunnelList stateTunnelList) { + int tunTypeVal = 0; + if (stateTunnelList.getDstInfo().getTepDeviceType() == TepTypeInternal.class) { + tunTypeVal = VpnConstants.ITMTunnelLocType.Internal.getValue(); + } else if (stateTunnelList.getDstInfo().getTepDeviceType() == TepTypeExternal.class) { + tunTypeVal = VpnConstants.ITMTunnelLocType.External.getValue(); + } else if (stateTunnelList.getDstInfo().getTepDeviceType() == TepTypeHwvtep.class) { + tunTypeVal = VpnConstants.ITMTunnelLocType.Hwvtep.getValue(); } else { - LOG.trace("No vpn instances present."); + tunTypeVal = VpnConstants.ITMTunnelLocType.Invalid.getValue(); + } + return tunTypeVal; + } + + private boolean isGreTunnel(StateTunnelList del) { + return del.getTransportType() == TunnelTypeMplsOverGre.class; + } + + private void programDcGwLoadBalancingGroup(StateTunnelList tunnelState, int addOrRemove) { + IpAddress dcGwIp = tunnelState.getDstInfo().getTepIp(); + String dcGwIpAddress = String.valueOf(dcGwIp.getValue()); + List availableDcGws = getDcGwIps(); + BigInteger dpId = new BigInteger(tunnelState.getSrcInfo().getTepDeviceId()); + boolean isTunnelUp = TunnelOperStatus.Up == tunnelState.getOperState(); + fibManager.programDcGwLoadBalancingGroup(availableDcGws, dpId, dcGwIpAddress, addOrRemove, isTunnelUp); + } + + private List getDcGwIps() { + InstanceIdentifier dcGatewayIpListid = + InstanceIdentifier.builder(DcGatewayIpList.class).build(); + DcGatewayIpList dcGatewayIpListConfig = + MDSALUtil.read(dataBroker, LogicalDatastoreType.CONFIGURATION, dcGatewayIpListid).orNull(); + if (dcGatewayIpListConfig == null) { + return Collections.EMPTY_LIST; + } + return dcGatewayIpListConfig.getDcGatewayIp() + .stream() + .filter(dcGwIp -> dcGwIp.getTunnnelType().equals(TunnelTypeMplsOverGre.class)) + .map(dcGwIp -> String.valueOf(dcGwIp.getIpAddress().getValue())).sorted() + .collect(toList()); + } + + private boolean isTunnelInLogicalGroup(StateTunnelList stateTunnelList) { + String ifaceName = stateTunnelList.getTunnelInterfaceName(); + if (getTunnelType(stateTunnelList) == VpnConstants.ITMTunnelLocType.Internal.getValue()) { + Interface configIface = InterfaceUtils.getInterface(dataBroker, stateTunnelList.getTunnelInterfaceName()); + IfTunnel ifTunnel = configIface != null ? configIface.getAugmentation(IfTunnel.class) : null; + if (ifTunnel != null && ifTunnel.getTunnelInterfaceType().isAssignableFrom(TunnelTypeVxlan.class)) { + ParentRefs refs = configIface.getAugmentation(ParentRefs.class); + if (refs != null && !Strings.isNullOrEmpty(refs.getParentInterface())) { + return true; //multiple VxLAN tunnels enabled, i.e. only logical tunnel should be treated + } + } } + LOG.trace("isTunnelInLogicalGroup: MULTIPLE_VxLAN_TUNNELS: ignoring the tunnel event for {}", ifaceName); + return false; } }