X-Git-Url: https://git.opendaylight.org/gerrit/gitweb?a=blobdiff_plain;f=vpnmanager%2Fvpnmanager-impl%2Fsrc%2Fmain%2Fjava%2Forg%2Fopendaylight%2Fvpnservice%2FVpnInterfaceManager.java;h=b33fea8d226418e66572bde08f04bed564c31d7a;hb=f30638fcc162d85f21f33cef401b4fb5da05caaf;hp=6d7d7d02ca784be62ef7e88de74e991d9b172133;hpb=fab3933242466a4be69bdbc3bc2199fc35b61317;p=vpnservice.git diff --git a/vpnmanager/vpnmanager-impl/src/main/java/org/opendaylight/vpnservice/VpnInterfaceManager.java b/vpnmanager/vpnmanager-impl/src/main/java/org/opendaylight/vpnservice/VpnInterfaceManager.java index 6d7d7d02..b33fea8d 100644 --- a/vpnmanager/vpnmanager-impl/src/main/java/org/opendaylight/vpnservice/VpnInterfaceManager.java +++ b/vpnmanager/vpnmanager-impl/src/main/java/org/opendaylight/vpnservice/VpnInterfaceManager.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2015 Ericsson India Global Services Pvt Ltd. and others. All rights reserved. + * Copyright (c) 2015 - 2016 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,48 +7,60 @@ */ package org.opendaylight.vpnservice; +import org.opendaylight.vpnservice.utilities.InterfaceUtils; + +import com.google.common.util.concurrent.FutureCallback; +import com.google.common.util.concurrent.Futures; +import com.google.common.util.concurrent.JdkFutureAdapters; + +import org.opendaylight.controller.md.sal.binding.api.*; +import org.opendaylight.vpnservice.mdsalutil.*; +import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev100924.IpAddress; +import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.yang.types.rev130715.PhysAddress; +import org.opendaylight.yang.gen.v1.urn.opendaylight.l3vpn.rev130911.PrefixToInterface; +import org.opendaylight.yang.gen.v1.urn.opendaylight.l3vpn.rev130911.adjacency.list.AdjacencyKey; +import org.opendaylight.yang.gen.v1.urn.opendaylight.l3vpn.rev130911.prefix.to._interface.vpn.ids.Prefixes; +import org.opendaylight.yang.gen.v1.urn.opendaylight.l3vpn.rev130911.vpn.instance.op.data.VpnInstanceOpDataEntry; +import org.opendaylight.yang.gen.v1.urn.opendaylight.l3vpn.rev130911.vpn.instance.op.data.vpn.instance.op.data.entry.VpnToDpnList; +import org.opendaylight.yang.gen.v1.urn.opendaylight.l3vpn.rev130911.vpn.instance.op.data.vpn.instance.op.data.entry.VpnToDpnListBuilder; +import org.opendaylight.yang.gen.v1.urn.opendaylight.l3vpn.rev130911.vpn.instance.op.data.vpn.instance.op.data.entry.vpn.to.dpn.list.VpnInterfacesBuilder; +import org.opendaylight.yang.gen.v1.urn.opendaylight.l3vpn.rev130911.vpn.instance.op.data.vpn.instance.op.data.entry.vpn.to.dpn.list.VpnInterfacesKey; +import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.types.rev131026.instruction.list.Instruction; +import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.arputil.rev151126.OdlArputilService; +import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.arputil.rev151126.SendArpResponseInput; +import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.arputil.rev151126.SendArpResponseInputBuilder; +import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.servicebinding.rev151015.service.bindings.services.info.BoundServices; +import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.fibmanager.rev150330.FibEntries; +import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.fibmanager.rev150330.fibentries.VrfTables; +import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.fibmanager.rev150330.fibentries.VrfTablesBuilder; +import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.fibmanager.rev150330.fibentries.VrfTablesKey; +import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.fibmanager.rev150330.vrfentries.VrfEntry; +import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.fibmanager.rev150330.vrfentries.VrfEntryBuilder; +import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.fibmanager.rev150330.vrfentries.VrfEntryKey; +import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.idmanager.rev150403.IdManagerService; + import java.math.BigInteger; +import java.util.Collection; +import java.util.Iterator; import java.util.List; import java.util.ArrayList; -import java.util.concurrent.ExecutionException; -import java.util.concurrent.Future; +import java.util.concurrent.*; import com.google.common.base.Optional; -import com.google.common.util.concurrent.Futures; -import com.google.common.util.concurrent.FutureCallback; import org.opendaylight.bgpmanager.api.IBgpManager; -import org.opendaylight.controller.md.sal.binding.api.DataBroker; -import org.opendaylight.controller.md.sal.binding.api.DataChangeListener; -import org.opendaylight.vpnservice.interfacemgr.interfaces.IInterfaceManager; -import org.opendaylight.vpnservice.mdsalutil.FlowEntity; -import org.opendaylight.vpnservice.mdsalutil.InstructionInfo; -import org.opendaylight.vpnservice.mdsalutil.InstructionType; -import org.opendaylight.vpnservice.mdsalutil.MDSALUtil; -import org.opendaylight.vpnservice.mdsalutil.MatchFieldType; -import org.opendaylight.vpnservice.mdsalutil.MatchInfo; -import org.opendaylight.vpnservice.mdsalutil.MetaDataUtil; +import org.opendaylight.fibmanager.api.IFibManager; +import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.interfacemgr.rpcs.rev151003.OdlInterfaceRpcService; +import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.itm.rpcs.rev151217.ItmRpcService; import org.opendaylight.vpnservice.mdsalutil.interfaces.IMdsalApiManager; import org.opendaylight.yangtools.concepts.ListenerRegistration; -import org.opendaylight.yangtools.yang.binding.DataObject; import org.opendaylight.yangtools.yang.binding.InstanceIdentifier; import org.opendaylight.yangtools.yang.binding.InstanceIdentifier.InstanceIdentifierBuilder; -import org.opendaylight.yangtools.yang.common.RpcResult; -import org.opendaylight.controller.md.sal.binding.api.ReadOnlyTransaction; -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.AsyncDataBroker.DataChangeScope; -import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev140508.Interfaces; -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.interfaces.rev140508.interfaces.InterfaceKey; -import org.opendaylight.yang.gen.v1.urn.opendaylight.l3vpn.rev130911.AdjacencyList; +import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev140508.InterfacesState; import org.opendaylight.yang.gen.v1.urn.opendaylight.l3vpn.rev130911.adjacency.list.Adjacency; import org.opendaylight.yang.gen.v1.urn.opendaylight.l3vpn.rev130911.adjacency.list.AdjacencyBuilder; -import org.opendaylight.yang.gen.v1.urn.opendaylight.l3vpn.rev130911.VpnInstance1; -import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.idmanager.rev150403.GetUniqueIdInput; -import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.idmanager.rev150403.GetUniqueIdInputBuilder; -import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.idmanager.rev150403.GetUniqueIdOutput; -import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.idmanager.rev150403.IdManagerService; import org.opendaylight.yang.gen.v1.urn.huawei.params.xml.ns.yang.l3vpn.rev140815.VpnInterfaces; import org.opendaylight.yang.gen.v1.urn.opendaylight.l3vpn.rev130911.Adjacencies; import org.opendaylight.yang.gen.v1.urn.huawei.params.xml.ns.yang.l3vpn.rev140815.VpnAfConfig; @@ -57,41 +69,44 @@ import org.opendaylight.yang.gen.v1.urn.huawei.params.xml.ns.yang.l3vpn.rev14081 import org.opendaylight.yang.gen.v1.urn.huawei.params.xml.ns.yang.l3vpn.rev140815.vpn.instances.VpnInstanceKey; 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.VpnInterfaceKey; -import org.opendaylight.yang.gen.v1.urn.huawei.params.xml.ns.yang.l3vpn.rev140815.vpn.interfaces.VpnInterfaceBuilder; -import org.opendaylight.yang.gen.v1.urn.opendaylight.l3vpn.rev130911.AdjacenciesBuilder; +import org.opendaylight.yangtools.yang.common.RpcError; +import org.opendaylight.yangtools.yang.common.RpcResult; import org.slf4j.Logger; import org.slf4j.LoggerFactory; public class VpnInterfaceManager extends AbstractDataChangeListener implements AutoCloseable { private static final Logger LOG = LoggerFactory.getLogger(VpnInterfaceManager.class); - private ListenerRegistration listenerRegistration; + private ListenerRegistration listenerRegistration, opListenerRegistration; + private ConcurrentMap vpnIntfMap = new ConcurrentHashMap(); + private ExecutorService executorService = Executors.newSingleThreadExecutor(); private final DataBroker broker; private final IBgpManager bgpManager; + private IFibManager fibManager; private IMdsalApiManager mdsalManager; - private IInterfaceManager interfaceManager; + private OdlInterfaceRpcService interfaceManager; + private ItmRpcService itmProvider; private IdManagerService idManager; - - private static final FutureCallback DEFAULT_CALLBACK = - new FutureCallback() { - public void onSuccess(Void result) { - LOG.debug("Success in Datastore operation"); - } - - public void onFailure(Throwable error) { - LOG.error("Error in Datastore operation", error); - }; - }; - + private OdlArputilService arpManager; + private InterfaceStateChangeListener interfaceListener; + private VpnInterfaceOpListener vpnInterfaceOpListener; + private ArpNotificationHandler arpNotificationHandler; + protected enum UpdateRouteAction { + ADVERTISE_ROUTE, WITHDRAW_ROUTE + } /** * Responsible for listening to data change related to VPN Interface * Bind VPN Service on the interface and informs the BGP service - * + * * @param db - dataBroker service reference */ - public VpnInterfaceManager(final DataBroker db, final IBgpManager bgpManager) { + public VpnInterfaceManager(final DataBroker db, final IBgpManager bgpManager, NotificationService notificationService) { super(VpnInterface.class); broker = db; this.bgpManager = bgpManager; + interfaceListener = new InterfaceStateChangeListener(db, this); + vpnInterfaceOpListener = new VpnInterfaceOpListener(); + arpNotificationHandler = new ArpNotificationHandler(this, broker); + notificationService.registerNotificationListener(arpNotificationHandler); registerListener(db); } @@ -99,23 +114,38 @@ public class VpnInterfaceManager extends AbstractDataChangeListener getInterfaceListenerPath() { + return InstanceIdentifier.create(InterfacesState.class) + .child(org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev140508.interfaces.state.Interface.class); + } + @Override protected void add(final InstanceIdentifier identifier, final VpnInterface vpnInterface) { - LOG.info("key: {} , value: {}", identifier, vpnInterface ); + LOG.trace("VPN Interface key: {} , value: {}", identifier, vpnInterface ); addInterface(identifier, vpnInterface); } private void addInterface(final InstanceIdentifier identifier, final VpnInterface vpnInterface) { + LOG.trace("VPN Interface add event - key: {}, value: {}" ,identifier, vpnInterface ); final VpnInterfaceKey key = identifier.firstKeyOf(VpnInterface.class, VpnInterfaceKey.class); String interfaceName = key.getName(); - InstanceIdentifierBuilder idBuilder = - InstanceIdentifier.builder(Interfaces.class).child(Interface.class, new InterfaceKey(interfaceName)); - InstanceIdentifier id = idBuilder.build(); - Optional port = read(LogicalDatastoreType.CONFIGURATION, id); - if (port.isPresent()) { - Interface interf = port.get(); - bindServiceOnInterface(interf, getVpnId(vpnInterface.getVpnInstanceName())); - updateNextHops(identifier, vpnInterface); + + org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev140508.interfaces.state.Interface interfaceState = + InterfaceUtils.getInterfaceStateFromOperDS(broker, interfaceName); + if (interfaceState != null) { + // Interface state is up + processVpnInterfaceUp(InterfaceUtils.getDpIdFromInterface(interfaceState), interfaceName, interfaceState.getIfIndex()); + } else { + LOG.trace("VPN interfaces are not yet operational."); } } - private void updateNextHops(final InstanceIdentifier identifier, VpnInterface intf) { - //Read NextHops - InstanceIdentifier path = identifier.augmentation(Adjacencies.class); - Optional adjacencies = read(LogicalDatastoreType.CONFIGURATION, path); - String intfName = intf.getName(); + protected void processVpnInterfaceUp(BigInteger dpId, String interfaceName, int lPortTag) { - if (adjacencies.isPresent()) { - List nextHops = adjacencies.get().getAdjacency(); - List value = new ArrayList<>(); + VpnInterface vpnInterface = VpnUtil.getConfiguredVpnInterface(broker, interfaceName); + if(vpnInterface == null) { + LOG.info("Unable to process add/up for interface {} as it is not configured", interfaceName); + return; + } + String vpnName = vpnInterface.getVpnInstanceName(); + LOG.info("Binding vpn service to interface {} ", interfaceName); + long vpnId = VpnUtil.getVpnId(broker, vpnName); + if (vpnId == VpnConstants.INVALID_ID) { + LOG.trace("VpnInstance to VPNId mapping is not yet available, bailing out now."); + return; + } + synchronized (interfaceName.intern()) { + if (VpnUtil.getOperationalVpnInterface(broker, vpnInterface.getName()) != null) { + LOG.trace("VPN Interface already provisioned , bailing out from here."); + return; + } + bindService(dpId, vpnName, interfaceName, lPortTag); + updateDpnDbs(dpId, vpnName, interfaceName, true); + processVpnInterfaceAdjacencies(dpId, VpnUtil.getVpnInterfaceIdentifier(vpnInterface.getName()), vpnInterface); + } + + } + + private void updateDpnDbs(BigInteger dpId, String vpnName, String interfaceName, boolean add) { + long vpnId = VpnUtil.getVpnId(broker, vpnName); + if (dpId == null) { + dpId = InterfaceUtils.getDpnForInterface(interfaceManager, interfaceName); + } + if(!dpId.equals(BigInteger.ZERO)) { + if(add) + updateMappingDbs(vpnId, dpId, interfaceName, vpnName); + else + removeFromMappingDbs(vpnId, dpId, interfaceName, vpnName); + } - //Get the rd of the vpn instance - String rd = getRouteDistinguisher(intf.getVpnInstanceName()); + } - long dpnId = interfaceManager.getDpnForInterface(intfName); - String nextHopIp = interfaceManager.getEndpointIpForDpn(dpnId); + private void bindService(BigInteger dpId, String vpnInstanceName, String vpnInterfaceName, int lPortTag) { + int priority = VpnConstants.DEFAULT_FLOW_PRIORITY; + long vpnId = VpnUtil.getVpnId(broker, vpnInstanceName); - if (!nextHops.isEmpty()) { - LOG.info("NextHops are {}", nextHops); - for (Adjacency nextHop : nextHops) { - String key = nextHop.getIpAddress(); - long label = getUniqueId(key); + int instructionKey = 0; + List instructions = new ArrayList(); + + instructions.add(MDSALUtil.buildAndGetWriteMetadaInstruction(BigInteger.valueOf(vpnId), MetaDataUtil.METADATA_MASK_VRFID, ++instructionKey)); + instructions.add(MDSALUtil.buildAndGetGotoTableInstruction(NwConstants.L3_FIB_TABLE, ++instructionKey)); + + BoundServices + serviceInfo = + InterfaceUtils.getBoundServices(String.format("%s.%s.%s", "vpn",vpnInstanceName, vpnInterfaceName), + VpnConstants.L3VPN_SERVICE_IDENTIFIER, priority, + VpnConstants.COOKIE_VM_INGRESS_TABLE, instructions); + VpnUtil.syncWrite(broker, LogicalDatastoreType.CONFIGURATION, + InterfaceUtils.buildServiceId(vpnInterfaceName, VpnConstants.L3VPN_SERVICE_IDENTIFIER), serviceInfo); + makeArpFlow(dpId, VpnConstants.L3VPN_SERVICE_IDENTIFIER, lPortTag, vpnInterfaceName, + vpnId, ArpReplyOrRequest.REQUEST, NwConstants.ADD_FLOW); - updatePrefixToBGP(rd, nextHop, nextHopIp, label); - value.add(new AdjacencyBuilder(nextHop).setLabel(label).build()); - } - } - Adjacencies aug = VpnUtil.getVpnInterfaceAugmentation(value); - VpnInterface opInterface = VpnUtil.getVpnInterface(intfName, intf.getVpnInstanceName(), aug); - InstanceIdentifier interfaceId = VpnUtil.getVpnInterfaceIdentifier(intfName); - asyncWrite(LogicalDatastoreType.OPERATIONAL, interfaceId, opInterface, DEFAULT_CALLBACK); - } } - private Integer getUniqueId(String idKey) { - GetUniqueIdInput getIdInput = new GetUniqueIdInputBuilder() - .setPoolName(VpnConstants.VPN_IDPOOL_NAME) - .setIdKey(idKey).build(); + private void processVpnInterfaceAdjacencies(BigInteger dpnId, final InstanceIdentifier identifier, VpnInterface intf) { + String intfName = intf.getName(); - try { - Future> result = idManager.getUniqueId(getIdInput); - RpcResult rpcResult = result.get(); - if(rpcResult.isSuccessful()) { - return rpcResult.getResult().getIdValue().intValue(); - } else { - LOG.warn("RPC Call to Get Unique Id returned with Errors {}", rpcResult.getErrors()); + synchronized (intfName) { + // Read NextHops + InstanceIdentifier path = identifier.augmentation(Adjacencies.class); + Optional adjacencies = VpnUtil.read(broker, LogicalDatastoreType.CONFIGURATION, path); + + if (adjacencies.isPresent()) { + List nextHops = adjacencies.get().getAdjacency(); + List value = new ArrayList<>(); + + // Get the rd of the vpn instance + String rd = getRouteDistinguisher(intf.getVpnInstanceName()); + + String nextHopIp = InterfaceUtils.getEndpointIpAddressForDPN(broker, dpnId); + if (nextHopIp == null){ + LOG.error("NextHop for interface {} is null", intfName); + } + + LOG.trace("NextHops are {}", nextHops); + for (Adjacency nextHop : nextHops) { + String prefix = VpnUtil.getIpPrefix(nextHop.getIpAddress()); + long label = VpnUtil.getUniqueId(idManager, VpnConstants.VPN_IDPOOL_NAME, VpnUtil + .getNextHopLabelKey((rd == null) ? intf.getVpnInstanceName() : rd, prefix)); + String adjNextHop = nextHop.getNextHopIp(); + value.add(new AdjacencyBuilder(nextHop).setLabel(label).setNextHopIp((adjNextHop != null && !adjNextHop.isEmpty()) ? adjNextHop : nextHopIp) + .setIpAddress(prefix).setKey(new AdjacencyKey(prefix)).build()); + if(nextHop.getMacAddress() != null && !nextHop.getMacAddress().isEmpty()) { + VpnUtil.syncUpdate( + broker, + LogicalDatastoreType.OPERATIONAL, + VpnUtil.getPrefixToInterfaceIdentifier( + VpnUtil.getVpnId(broker, intf.getVpnInstanceName()), prefix), + VpnUtil.getPrefixToInterface(dpnId, intf.getName(), prefix)); + } else { + //Extra route adjacency + VpnUtil.syncUpdate( + broker, + LogicalDatastoreType.OPERATIONAL, + VpnUtil.getVpnToExtrarouteIdentifier( + (rd != null) ? rd : intf.getVpnInstanceName(), nextHop.getIpAddress()), + VpnUtil.getVpnToExtraroute(nextHop.getIpAddress(), nextHop.getNextHopIp())); + + } + } + + Adjacencies aug = VpnUtil.getVpnInterfaceAugmentation(value); + VpnInterface opInterface = VpnUtil.getVpnInterface(intfName, intf.getVpnInstanceName(), aug); + InstanceIdentifier interfaceId = VpnUtil.getVpnInterfaceIdentifier(intfName); + VpnUtil.syncWrite(broker, LogicalDatastoreType.OPERATIONAL, interfaceId, opInterface); + for (Adjacency nextHop : aug.getAdjacency()) { + long label = nextHop.getLabel(); + //String adjNextHop = nextHop.getNextHopIp(); + if (rd != null) { + addPrefixToBGP(rd, nextHop.getIpAddress(), + nextHopIp, label); + } else { + // ### add FIB route directly + addFibEntryToDS(intf.getVpnInstanceName(), nextHop.getIpAddress(), + nextHopIp, (int) label); + } + } } - } catch (NullPointerException | InterruptedException | ExecutionException e) { - LOG.warn("Exception when getting Unique Id",e); } - return 0; } - private long getVpnId(String vpnName) { - //TODO: This should be a Util function - InstanceIdentifier id = InstanceIdentifier.builder(VpnInstances.class) - .child(VpnInstance.class, new VpnInstanceKey(vpnName)).augmentation(VpnInstance1.class).build(); - Optional vpnInstance = read(LogicalDatastoreType.OPERATIONAL, id); - //TODO: Default vpnid should be a constant. - long vpnId = -1; - if(vpnInstance.isPresent()) { - vpnId = vpnInstance.get().getVpnId(); + private void makeArpFlow(BigInteger dpId,short sIndex, int lPortTag, String vpnInterfaceName, + long vpnId, ArpReplyOrRequest replyOrRequest, int addOrRemoveFlow){ + List matches = new ArrayList(); + BigInteger metadata = MetaDataUtil.getMetaDataForLPortDispatcher(lPortTag, ++sIndex, BigInteger.valueOf(vpnId)); + BigInteger metadataMask = MetaDataUtil.getMetaDataMaskForLPortDispatcher(MetaDataUtil.METADATA_MASK_SERVICE_INDEX, + MetaDataUtil.METADATA_MASK_LPORT_TAG, MetaDataUtil.METADATA_MASK_VRFID); + + // Matching Arp reply flows + matches.add(new MatchInfo(MatchFieldType.eth_type, new long[] { NwConstants.ETHTYPE_ARP })); + matches.add(new MatchInfo(MatchFieldType.metadata, new BigInteger[] { + metadata, metadataMask })); + + matches.add(new MatchInfo(MatchFieldType.arp_op, new long[] { replyOrRequest.getArpOperation() })); + + // Instruction to punt to controller + List instructions = new ArrayList(); + List actionsInfos = new ArrayList(); + actionsInfos.add(new ActionInfo(ActionType.punt_to_controller, new String[] {})); + instructions.add(new InstructionInfo(InstructionType.write_actions, actionsInfos)); + + // Install the flow entry in L3_INTERFACE_TABLE + String flowRef = VpnUtil.getFlowRef(dpId, NwConstants.L3_INTERFACE_TABLE, + NwConstants.ETHTYPE_ARP, lPortTag, replyOrRequest.getArpOperation()); + FlowEntity flowEntity; + flowEntity = MDSALUtil.buildFlowEntity(dpId, NwConstants.L3_INTERFACE_TABLE, flowRef, + NwConstants.DEFAULT_ARP_FLOW_PRIORITY, replyOrRequest.getName(), 0, 0, + VpnUtil.getCookieArpFlow(lPortTag), matches, instructions); + + if (addOrRemoveFlow == NwConstants.ADD_FLOW) { + LOG.debug("Creating ARP Flow for interface {}",vpnInterfaceName); + mdsalManager.installFlow(flowEntity); + } else { + LOG.debug("Deleting ARP Flow for interface {}",vpnInterfaceName); + mdsalManager.removeFlow(flowEntity); } - return vpnId; } private String getRouteDistinguisher(String vpnName) { InstanceIdentifier id = InstanceIdentifier.builder(VpnInstances.class) .child(VpnInstance.class, new VpnInstanceKey(vpnName)).build(); - Optional vpnInstance = read(LogicalDatastoreType.CONFIGURATION, id); + Optional vpnInstance = VpnUtil.read(broker, LogicalDatastoreType.CONFIGURATION, id); String rd = ""; if(vpnInstance.isPresent()) { VpnInstance instance = vpnInstance.get(); @@ -230,67 +369,78 @@ public class VpnInterfaceManager extends AbstractDataChangeListener id = VpnUtil.getVpnToDpnListIdentifier(rd, dpnId); + Optional dpnInVpn = VpnUtil.read(broker, LogicalDatastoreType.OPERATIONAL, id); + org.opendaylight.yang.gen.v1.urn.opendaylight.l3vpn.rev130911.vpn.instance.op.data.vpn.instance.op.data.entry.vpn.to.dpn.list.VpnInterfaces + vpnInterface = new VpnInterfacesBuilder().setInterfaceName(intfName).build(); + + if (dpnInVpn.isPresent()) { + VpnUtil.syncWrite(broker, LogicalDatastoreType.OPERATIONAL, id.child( + org.opendaylight.yang.gen.v1.urn.opendaylight.l3vpn.rev130911.vpn.instance + .op.data.vpn.instance.op.data.entry.vpn.to.dpn.list.VpnInterfaces.class, + new VpnInterfacesKey(intfName)), vpnInterface); + } else { + VpnUtil.syncUpdate(broker, LogicalDatastoreType.OPERATIONAL, + VpnUtil.getVpnInstanceOpDataIdentifier(rd), + VpnUtil.getVpnInstanceOpDataBuilder(rd, vpnId)); + VpnToDpnListBuilder vpnToDpnList = new VpnToDpnListBuilder().setDpnId(dpnId); + List vpnInterfaces = new ArrayList<>(); + vpnInterfaces.add(vpnInterface); + VpnUtil.syncWrite(broker, LogicalDatastoreType.OPERATIONAL, id, + vpnToDpnList.setVpnInterfaces(vpnInterfaces).build()); + + /** + * FIXME: DC Gateway tunnel should be built dynamically + //this is the first VM in this VPN on the DPN, may be a new DPN has come up, + //if tunnel to DC GW does not exist, create it + //if(!tunnelExists(dpnID, bgpManager.getDCGWIP())) + String dcGW = bgpManager.getDCGwIP(); + if(dcGW != null && !dcGW.isEmpty()) + { + LOG.debug("Building tunnel from DPN {} to DC GW {}", dpnId, dcGW); + itmProvider.buildTunnelFromDPNToDCGW(dpnId, new IpAddress(dcGW.toCharArray())); + }*/ + fibManager.populateFibOnNewDpn(dpnId, vpnId, (rd == null) ? vpnName : rd); } - - long portNo = interfaceManager.getPortForInterface(intf.getName()); - String flowRef = getVpnInterfaceFlowRef(dpId, VpnConstants.LPORT_INGRESS_TABLE, vpnId, portNo); - - String flowName = intf.getName(); - BigInteger COOKIE_VM_INGRESS_TABLE = new BigInteger("8000001", 16); - - int priority = VpnConstants.DEFAULT_FLOW_PRIORITY; - short gotoTableId = VpnConstants.FIB_TABLE; - - List mkInstructions = new ArrayList(); - mkInstructions.add(new InstructionInfo(InstructionType.write_metadata, new BigInteger[] { - BigInteger.valueOf(vpnId), MetaDataUtil.METADATA_MASK_VRFID })); - - mkInstructions.add(new InstructionInfo(InstructionType.goto_table, new long[] { gotoTableId })); - - List matches = new ArrayList(); - matches.add(new MatchInfo(MatchFieldType.in_port, new long[] { - dpId, portNo })); - - FlowEntity flowEntity = MDSALUtil.buildFlowEntity(dpId, VpnConstants.LPORT_INGRESS_TABLE, flowRef, - priority, flowName, 0, 0, COOKIE_VM_INGRESS_TABLE, matches, mkInstructions); - - mdsalManager.installFlow(flowEntity); } - private String getVpnInterfaceFlowRef(long dpId, short tableId, - long vpnId, long portNo) { - return new StringBuilder().append(dpId).append(tableId).append(vpnId).append(portNo).toString(); + private synchronized void removeFromMappingDbs(long vpnId, BigInteger dpnId, String intfName, String vpnName) { + //TODO: Delay 'DPN' removal so that other services can cleanup the entries for this dpn + String rd = VpnUtil.getVpnRd(broker, vpnName); + InstanceIdentifier id = VpnUtil.getVpnToDpnListIdentifier(rd, dpnId); + Optional dpnInVpn = VpnUtil.read(broker, LogicalDatastoreType.OPERATIONAL, id); + if (dpnInVpn.isPresent()) { + List vpnInterfaces = dpnInVpn.get().getVpnInterfaces(); + org.opendaylight.yang.gen.v1.urn.opendaylight.l3vpn.rev130911.vpn.instance.op.data.vpn.instance.op.data.entry.vpn.to.dpn.list.VpnInterfaces + currVpnInterface = new VpnInterfacesBuilder().setInterfaceName(intfName).build(); + + if (vpnInterfaces.remove(currVpnInterface)) { + if (vpnInterfaces.isEmpty()) { + VpnUtil.delete(broker, LogicalDatastoreType.OPERATIONAL, id, VpnUtil.DEFAULT_CALLBACK); + fibManager.cleanUpDpnForVpn(dpnId, vpnId, rd); + } else { + VpnUtil.delete(broker, LogicalDatastoreType.OPERATIONAL, id.child( + org.opendaylight.yang.gen.v1.urn.opendaylight.l3vpn.rev130911.vpn.instance.op.data + .vpn.instance.op.data.entry.vpn.to.dpn.list.VpnInterfaces.class, + new VpnInterfacesKey(intfName)), VpnUtil.DEFAULT_CALLBACK); + } + } + } } - private void updatePrefixToBGP(String rd, Adjacency nextHop, String nextHopIp, long label) { + private void addPrefixToBGP(String rd, String prefix, String nextHopIp, long label) { try { - bgpManager.addPrefix(rd, nextHop.getIpAddress(), nextHopIp, (int)label); + bgpManager.addPrefix(rd, prefix, nextHopIp, (int)label); } catch(Exception e) { LOG.error("Add prefix failed", e); } } - private Optional read(LogicalDatastoreType datastoreType, - InstanceIdentifier path) { - - ReadOnlyTransaction tx = broker.newReadOnlyTransaction(); - - Optional result = Optional.absent(); - try { - result = tx.read(datastoreType, path).get(); - } catch (Exception e) { - throw new RuntimeException(e); - } - - return result; - } private InstanceIdentifier getWildCardPath() { return InstanceIdentifier.create(VpnInterfaces.class).child(VpnInterface.class); @@ -298,94 +448,488 @@ public class VpnInterfaceManager extends AbstractDataChangeListener identifier, VpnInterface vpnInterface) { - LOG.info("Remove event - key: {}, value: {}" ,identifier, vpnInterface ); + LOG.trace("Remove event - key: {}, value: {}" ,identifier, vpnInterface ); final VpnInterfaceKey key = identifier.firstKeyOf(VpnInterface.class, VpnInterfaceKey.class); String interfaceName = key.getName(); - InstanceIdentifierBuilder idBuilder = - InstanceIdentifier.builder(Interfaces.class).child(Interface.class, new InterfaceKey(interfaceName)); - InstanceIdentifier id = idBuilder.build(); - Optional port = read(LogicalDatastoreType.CONFIGURATION, id); - if (port.isPresent()) { - Interface interf = port.get(); - unbindServiceOnInterface(interf, getVpnId(vpnInterface.getVpnInstanceName())); - removeNextHops(identifier, vpnInterface); + + InstanceIdentifier interfaceId = VpnUtil.getVpnInterfaceIdentifier(interfaceName); + Optional existingVpnInterface = VpnUtil.read(broker, LogicalDatastoreType.OPERATIONAL, interfaceId); + org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev140508.interfaces.state.Interface interfaceState = + InterfaceUtils.getInterfaceStateFromOperDS(broker, interfaceName); + + if (existingVpnInterface.isPresent() && interfaceState != null) { + processVpnInterfaceDown(InterfaceUtils.getDpIdFromInterface(interfaceState), interfaceName, interfaceState.getIfIndex(), false); } else { - LOG.info("No nexthops were available to handle remove event {}", interfaceName); + LOG.warn("VPN interface {} was unavailable in operational data store to handle remove event", interfaceName); } } - private void removeNextHops(final InstanceIdentifier identifier, VpnInterface intf) { + protected void processVpnInterfaceDown(BigInteger dpId, String interfaceName, int lPortTag, boolean isInterfaceStateDown) { + VpnInterface vpnInterface = VpnUtil.getOperationalVpnInterface(broker, interfaceName); + if(vpnInterface == null) { + LOG.info("Unable to process delete/down for interface {} as it is not available in operational data store", interfaceName); + return; + } + String vpnName = vpnInterface.getVpnInstanceName(); + InstanceIdentifier identifier = VpnUtil.getVpnInterfaceIdentifier(interfaceName); + + synchronized (interfaceName.intern()) { + removeAdjacenciesFromVpn(identifier, vpnInterface); + LOG.info("Unbinding vpn service from interface {} ", interfaceName); + unbindService(dpId, vpnName, interfaceName, lPortTag, isInterfaceStateDown); + + //wait till DCN for removal of vpn interface in operational DS arrives + Runnable notifyTask = new VpnNotifyTask(); + synchronized (interfaceName.intern()) { + vpnIntfMap.put(interfaceName, notifyTask); + synchronized (notifyTask) { + try { + notifyTask.wait(VpnConstants.WAIT_TIME_IN_MILLISECONDS); + } catch (InterruptedException e) { + } + } + } + + } + } + + private void removeAdjacenciesFromVpn(final InstanceIdentifier identifier, VpnInterface intf) { //Read NextHops InstanceIdentifier path = identifier.augmentation(Adjacencies.class); - Optional adjacencies = read(LogicalDatastoreType.OPERATIONAL, path); - String intfName = intf.getName(); - String rd = getRouteDistinguisher(intf.getVpnInstanceName()); + Optional adjacencies = VpnUtil.read(broker, LogicalDatastoreType.OPERATIONAL, path); + + String rd = VpnUtil.getVpnRd(broker, intf.getVpnInstanceName()); if (adjacencies.isPresent()) { List nextHops = adjacencies.get().getAdjacency(); if (!nextHops.isEmpty()) { LOG.trace("NextHops are " + nextHops); for (Adjacency nextHop : nextHops) { - removePrefixFromBGP(rd, nextHop); + VpnUtil.releaseId(idManager, VpnConstants.VPN_IDPOOL_NAME, + VpnUtil.getNextHopLabelKey(rd, nextHop.getIpAddress())); + /*VpnUtil.delete(broker, LogicalDatastoreType.OPERATIONAL, + VpnUtil.getPrefixToInterfaceIdentifier( + VpnUtil.getVpnId(broker, intf.getVpnInstanceName()), + nextHop.getIpAddress()), + VpnUtil.DEFAULT_CALLBACK);*/ + if (rd.equals(intf.getVpnInstanceName())) { + //this is an internal vpn - the rd is assigned to the vpn instance name; + //remove from FIB directly + removeFibEntryFromDS(intf.getVpnInstanceName(), nextHop.getIpAddress()); + } else { + removePrefixFromBGP(rd, nextHop.getIpAddress()); + } } } } - InstanceIdentifier interfaceId = VpnUtil.getVpnInterfaceIdentifier(intfName); - delete(LogicalDatastoreType.OPERATIONAL, interfaceId); } - private void delete(LogicalDatastoreType datastoreType, InstanceIdentifier path) { - WriteTransaction tx = broker.newWriteOnlyTransaction(); - tx.delete(datastoreType, path); - Futures.addCallback(tx.submit(), DEFAULT_CALLBACK); + + private void unbindService(BigInteger dpId, String vpnInstanceName, String vpnInterfaceName, + int lPortTag, boolean isInterfaceStateDown) { + if (!isInterfaceStateDown) { + VpnUtil.delete(broker, LogicalDatastoreType.CONFIGURATION, + InterfaceUtils.buildServiceId(vpnInterfaceName, + VpnConstants.L3VPN_SERVICE_IDENTIFIER), + VpnUtil.DEFAULT_CALLBACK); + } + long vpnId = VpnUtil.getVpnId(broker, vpnInstanceName); + makeArpFlow(dpId, VpnConstants.L3VPN_SERVICE_IDENTIFIER, lPortTag, vpnInterfaceName, + vpnId, ArpReplyOrRequest.REQUEST, NwConstants.DEL_FLOW); } - private void unbindServiceOnInterface(Interface intf, long vpnId) { - LOG.info("Unbind service on interface {} for VPN: {}", intf, vpnId); - long dpId = interfaceManager.getDpnForInterface(intf.getName()); - if(dpId == 0L) { - LOG.warn("DPN for interface {} not found. Unbind service on this interface aborted.", intf.getName()); - return; + private void removePrefixFromBGP(String rd, String prefix) { + try { + bgpManager.deletePrefix(rd, prefix); + } catch(Exception e) { + LOG.error("Delete prefix failed", e); + } + } + + @Override + protected void update(InstanceIdentifier identifier, VpnInterface original, VpnInterface update) { + if (LOG.isTraceEnabled()) { + LOG.trace("Updating VPN Interface : key " + identifier + ", original value=" + original + ", update " + + "value=" + update); + } + String oldVpnName = original.getVpnInstanceName(); + String newVpnName = update.getVpnInstanceName(); + List oldAdjs = original.getAugmentation(Adjacencies.class).getAdjacency(); + List newAdjs = update.getAugmentation(Adjacencies.class).getAdjacency(); + if (oldAdjs == null) { + oldAdjs = new ArrayList<>(); + } + if (newAdjs == null) { + newAdjs = new ArrayList<>(); + } + //handles switching between + if (!oldVpnName.equals(newVpnName)) { + remove(identifier, original); + add(identifier, update); + } + //handle both addition and removal of adjacencies + //currently, new adjacency may be an extra route + if (!oldAdjs.equals(newAdjs)) { + for (Adjacency adj : newAdjs) { + if (oldAdjs.contains(adj)) { + oldAdjs.remove(adj); + } else { + // add new adjacency - right now only extra route will hit this path + addNewAdjToVpnInterface(identifier, adj); + } + } + for (Adjacency adj : oldAdjs) { + delAdjFromVpnInterface(identifier, adj); + } } + } - long portNo = interfaceManager.getPortForInterface(intf.getName()); - String flowRef = getVpnInterfaceFlowRef(dpId, VpnConstants.LPORT_INGRESS_TABLE, vpnId, portNo); + public void processArpRequest(IpAddress srcIP, PhysAddress srcMac, IpAddress targetIP, String srcInterface){ + SendArpResponseInput input = new SendArpResponseInputBuilder().setInterface(srcInterface) + .setIpaddress(srcIP).setSrcIpAddress(targetIP).setMacaddress(srcMac).build(); + final String msgFormat = String.format("Send ARP Response on interface %s to destination %s", srcInterface, srcIP); + Future> future = arpManager.sendArpResponse(input); + Futures.addCallback(JdkFutureAdapters.listenInPoolThread(future), new FutureCallback>() { + @Override + public void onFailure(Throwable error) { + LOG.error("Error - {}", msgFormat, error); + } - String flowName = intf.getName(); + @Override + public void onSuccess(RpcResult result) { + if(!result.isSuccessful()) { + LOG.warn("Rpc call to {} failed", msgFormat, getErrorText(result.getErrors())); + } else { + LOG.debug("Successful RPC Result - {}", msgFormat); + } + } + }); + } - int priority = VpnConstants.DEFAULT_FLOW_PRIORITY; + private String getErrorText(Collection errors) { + StringBuilder errorText = new StringBuilder(); + for(RpcError error : errors) { + errorText.append(",").append(error.getErrorType()).append("-") + .append(error.getMessage()); + } + return errorText.toString(); + } - List matches = new ArrayList(); - matches.add(new MatchInfo(MatchFieldType.in_port, new long[] { - dpId, portNo })); + private String getTunnelInterfaceFlowRef(BigInteger dpnId, short tableId, String ifName) { + return new StringBuilder().append(dpnId).append(tableId).append(ifName).toString(); + } + + + + public synchronized void addFibEntryToDS(String rd, String prefix, + String nexthop, int label) { - FlowEntity flowEntity = MDSALUtil.buildFlowEntity(dpId, VpnConstants.LPORT_INGRESS_TABLE, flowRef, - priority, flowName, 0, 0, null, matches, null); + VrfEntry vrfEntry = new VrfEntryBuilder().setDestPrefix(prefix). + setNextHopAddress(nexthop).setLabel((long)label).build(); + LOG.debug("Created vrfEntry for {} nexthop {} label {}", prefix, nexthop, label); - mdsalManager.removeFlow(flowEntity); + List vrfEntryList = new ArrayList(); + vrfEntryList.add(vrfEntry); + + InstanceIdentifierBuilder idBuilder = + InstanceIdentifier.builder(FibEntries.class).child(VrfTables.class, new VrfTablesKey(rd)); + InstanceIdentifier vrfTableId = idBuilder.build(); + + VrfTables vrfTableNew = new VrfTablesBuilder().setRouteDistinguisher(rd). + setVrfEntry(vrfEntryList).build(); + + VpnUtil.syncUpdate(broker, LogicalDatastoreType.CONFIGURATION, vrfTableId, vrfTableNew); } - private void removePrefixFromBGP(String rd, Adjacency nextHop) { - //public void deletePrefix(String rd, String prefix) throws Exception; - try { - bgpManager.deletePrefix(rd, nextHop.getIpAddress()); - } catch(Exception e) { - LOG.error("Delete prefix failed", e); + public synchronized void removeFibEntryFromDS(String rd, String prefix) { + + LOG.debug("Removing fib entry with destination prefix {} from vrf table for rd {}", prefix, rd); + + InstanceIdentifierBuilder idBuilder = + InstanceIdentifier.builder(FibEntries.class).child(VrfTables.class, new VrfTablesKey(rd)).child(VrfEntry.class, new VrfEntryKey(prefix)); + InstanceIdentifier vrfEntryId = idBuilder.build(); + VpnUtil.delete(broker, LogicalDatastoreType.CONFIGURATION, vrfEntryId, VpnUtil.DEFAULT_CALLBACK); + + } + + public synchronized void removeVrfFromDS(String rd) { + LOG.debug("Removing vrf table for rd {}", rd); + + InstanceIdentifierBuilder idBuilder = + InstanceIdentifier.builder(FibEntries.class).child(VrfTables.class, new VrfTablesKey(rd)); + InstanceIdentifier vrfTableId = idBuilder.build(); + + VpnUtil.delete(broker, LogicalDatastoreType.CONFIGURATION, vrfTableId, VpnUtil.DEFAULT_CALLBACK); + + } + + protected void addNewAdjToVpnInterface(InstanceIdentifier identifier, Adjacency adj) { + + Optional optVpnInterface = VpnUtil.read(broker, LogicalDatastoreType.OPERATIONAL, identifier); + + if (optVpnInterface.isPresent()) { + VpnInterface currVpnIntf = optVpnInterface.get(); + String prefix = VpnUtil.getIpPrefix(adj.getIpAddress()); + String rd = getRouteDistinguisher(currVpnIntf.getVpnInstanceName()); + InstanceIdentifier adjPath = identifier.augmentation(Adjacencies.class); + Optional optAdjacencies = VpnUtil.read(broker, LogicalDatastoreType.OPERATIONAL, adjPath); + long label = + VpnUtil.getUniqueId(idManager, VpnConstants.VPN_IDPOOL_NAME, + VpnUtil.getNextHopLabelKey((rd != null) ? rd : currVpnIntf.getVpnInstanceName(), prefix)); + + List adjacencies; + if (optAdjacencies.isPresent()) { + adjacencies = optAdjacencies.get().getAdjacency(); + } else { + //This code will not be hit since VM adjacency will always be there + adjacencies = new ArrayList<>(); + } + + adjacencies.add(new AdjacencyBuilder(adj).setLabel(label).setNextHopIp(adj.getNextHopIp()) + .setIpAddress(prefix).setKey(new AdjacencyKey(prefix)).build()); + + Adjacencies aug = VpnUtil.getVpnInterfaceAugmentation(adjacencies); + VpnInterface newVpnIntf = VpnUtil.getVpnInterface(currVpnIntf.getName(), currVpnIntf.getVpnInstanceName(), aug); + + VpnUtil.syncUpdate(broker, LogicalDatastoreType.OPERATIONAL, identifier, newVpnIntf); + addExtraRoute(adj.getIpAddress(), adj.getNextHopIp(), rd, currVpnIntf.getVpnInstanceName(), (int) label, currVpnIntf.getName()); + } + } - @Override - protected void update(InstanceIdentifier identifier, - VpnInterface original, VpnInterface update) { - // TODO Auto-generated method stub + protected void delAdjFromVpnInterface(InstanceIdentifier identifier, Adjacency adj) { + Optional optVpnInterface = VpnUtil.read(broker, LogicalDatastoreType.OPERATIONAL, identifier); + + if (optVpnInterface.isPresent()) { + VpnInterface currVpnIntf = optVpnInterface.get(); + + InstanceIdentifier path = identifier.augmentation(Adjacencies.class); + Optional optAdjacencies = VpnUtil.read(broker, LogicalDatastoreType.OPERATIONAL, path); + if (optAdjacencies.isPresent()) { + List adjacencies = optAdjacencies.get().getAdjacency(); + + if (!adjacencies.isEmpty()) { + String rd = getRouteDistinguisher(currVpnIntf.getVpnInstanceName()); + LOG.trace("Adjacencies are " + adjacencies); + Iterator adjIt = adjacencies.iterator(); + while (adjIt.hasNext()) { + Adjacency adjElem = adjIt.next(); + if (adjElem.getIpAddress().equals(adj.getIpAddress())) { + VpnUtil.releaseId(idManager, VpnConstants.VPN_IDPOOL_NAME, + VpnUtil.getNextHopLabelKey(rd, adj.getIpAddress())); + adjIt.remove(); + + Adjacencies aug = VpnUtil.getVpnInterfaceAugmentation(adjacencies); + VpnInterface newVpnIntf = VpnUtil.getVpnInterface(currVpnIntf.getName(), + currVpnIntf.getVpnInstanceName(), + aug); + + VpnUtil.syncUpdate(broker, LogicalDatastoreType.OPERATIONAL, identifier, newVpnIntf); + + delExtraRoute(adj.getIpAddress(), rd, currVpnIntf.getVpnInstanceName()); + break; + } + + } + } + } + } + + } + protected void addExtraRoute(String destination, String nextHop, String rd, String routerID, int label, String intfName) { + + //add extra route to vpn mapping; advertise with nexthop as tunnel ip + VpnUtil.syncUpdate( + broker, + LogicalDatastoreType.OPERATIONAL, + VpnUtil.getVpnToExtrarouteIdentifier( + (rd != null) ? rd : routerID, destination), + VpnUtil.getVpnToExtraroute(destination, nextHop)); + + if(intfName != null && !intfName.isEmpty()) { + BigInteger dpnId = InterfaceUtils.getDpnForInterface(interfaceManager, intfName); + String nextHopIp = InterfaceUtils.getEndpointIpAddressForDPN(broker, dpnId); + if (nextHopIp == null && !nextHopIp.isEmpty()) { + LOG.error("NextHop for interface {} is null. Adding extra route {} without nextHop", intfName, + destination); + } + nextHop = nextHopIp; + } + if (rd != null) { + addPrefixToBGP(rd, destination, nextHop, label); + } else { + // ### add FIB route directly + addFibEntryToDS(routerID, destination, nextHop, label); + } } - private void asyncWrite(LogicalDatastoreType datastoreType, - InstanceIdentifier path, T data, FutureCallback callback) { - WriteTransaction tx = broker.newWriteOnlyTransaction(); - tx.put(datastoreType, path, data, true); - Futures.addCallback(tx.submit(), callback); + protected void delExtraRoute(String destination, String rd, String routerID) { + if (rd != null) { + removePrefixFromBGP(rd, destination); + } else { + // ### add FIB route directly + removeFibEntryFromDS(routerID, destination); + } } + + class VpnInterfaceOpListener extends org.opendaylight.vpnservice.mdsalutil.AbstractDataChangeListener { + + public VpnInterfaceOpListener() { + super(VpnInterface.class); + } + + @Override + protected void remove(InstanceIdentifier identifier, VpnInterface del) { + final VpnInterfaceKey key = identifier.firstKeyOf(VpnInterface.class, VpnInterfaceKey.class); + String interfaceName = key.getName(); + + //increment the vpn interface count in Vpn Instance Op Data + Long ifCnt = 0L; + String rd = getRouteDistinguisher(del.getVpnInstanceName()); + if(rd == null || rd.isEmpty()) rd = del.getVpnInstanceName(); + VpnInstanceOpDataEntry vpnInstOp = VpnUtil.getVpnInstanceOpData(broker, rd); + if(vpnInstOp != null && vpnInstOp.getVpnInterfaceCount() != null) { + ifCnt = vpnInstOp.getVpnInterfaceCount(); + } + + LOG.trace("VpnInterfaceOpListener remove: interface name {} rd {} interface count in Vpn Op Instance {}", interfaceName, rd, ifCnt); + + if(ifCnt != 0) { + VpnUtil.asyncUpdate(broker, LogicalDatastoreType.OPERATIONAL, + VpnUtil.getVpnInstanceOpDataIdentifier(rd), + VpnUtil.updateIntfCntInVpnInstOpData(ifCnt - 1, rd), VpnUtil.DEFAULT_CALLBACK); + } + + // Vpn Interface removed => No more adjacencies from it. + // Hence clean up interface from vpn-dpn-interface list. + Adjacency adjacency = del.getAugmentation(Adjacencies.class).getAdjacency().get(0); + Optional prefixToInterface = Optional.absent(); + prefixToInterface = VpnUtil.read(broker, LogicalDatastoreType.OPERATIONAL, + VpnUtil.getPrefixToInterfaceIdentifier(vpnInstOp.getVpnId(), + VpnUtil.getIpPrefix(adjacency.getIpAddress()))); + if (!prefixToInterface.isPresent()) { + prefixToInterface = VpnUtil.read(broker, LogicalDatastoreType.OPERATIONAL, + VpnUtil.getPrefixToInterfaceIdentifier(vpnInstOp.getVpnId(), + VpnUtil.getIpPrefix(adjacency.getNextHopIp()))); + } + if (prefixToInterface.isPresent()) { + VpnUtil.delete(broker, LogicalDatastoreType.OPERATIONAL, + VpnUtil.getPrefixToInterfaceIdentifier(vpnInstOp.getVpnId(), + prefixToInterface.get().getIpAddress()), + VpnUtil.DEFAULT_CALLBACK); + updateDpnDbs(prefixToInterface.get().getDpnId(), del.getVpnInstanceName(), interfaceName, false); + } + notifyTaskIfRequired(interfaceName); + } + + private void notifyTaskIfRequired(String intfName) { + Runnable notifyTask = vpnIntfMap.remove(intfName); + if (notifyTask == null) { + return; + } + executorService.execute(notifyTask); + } + + @Override + protected void update(InstanceIdentifier identifier, VpnInterface original, VpnInterface update) { + } + + @Override + protected void add(InstanceIdentifier identifier, VpnInterface add) { + final VpnInterfaceKey key = identifier.firstKeyOf(VpnInterface.class, VpnInterfaceKey.class); + String interfaceName = key.getName(); + + //increment the vpn interface count in Vpn Instance Op Data + Long ifCnt = 0L; + String rd = getRouteDistinguisher(add.getVpnInstanceName()); + if(rd == null || rd.isEmpty()) rd = add.getVpnInstanceName(); + VpnInstanceOpDataEntry vpnInstOp = VpnUtil.getVpnInstanceOpData(broker, rd); + if(vpnInstOp != null && vpnInstOp.getVpnInterfaceCount() != null) { + ifCnt = vpnInstOp.getVpnInterfaceCount(); + } + + LOG.trace("VpnInterfaceOpListener add: interface name {} rd {} interface count in Vpn Op Instance {}", interfaceName, rd, ifCnt); + + VpnUtil.asyncUpdate(broker, LogicalDatastoreType.OPERATIONAL, + VpnUtil.getVpnInstanceOpDataIdentifier(rd), + VpnUtil.updateIntfCntInVpnInstOpData(ifCnt + 1, rd), VpnUtil.DEFAULT_CALLBACK); + + + } + } + + protected void updatePrefixesForDPN(BigInteger dpnId, UpdateRouteAction action) { + + LOG.info("Tunnel event triggered {} for Dpn:{} ", action.name(), dpnId); + InstanceIdentifierBuilder idBuilder = InstanceIdentifier.builder(VpnInstances.class); + InstanceIdentifier vpnInstancesId = idBuilder.build(); + Optional vpnInstances = VpnUtil.read(broker, LogicalDatastoreType.CONFIGURATION, vpnInstancesId); + + if (vpnInstances.isPresent()) { + List vpnInstanceList = vpnInstances.get().getVpnInstance(); + Iterator vpnInstIter = vpnInstanceList.iterator(); + while (vpnInstIter.hasNext()) { + VpnInstance vpnInstance = vpnInstIter.next(); + try { + VpnAfConfig vpnConfig = vpnInstance.getIpv4Family(); + String rd = vpnConfig.getRouteDistinguisher(); + if (rd == null || rd.isEmpty()) { + rd = vpnInstance.getVpnInstanceName(); + } + InstanceIdentifier id = + VpnUtil.getVpnToDpnListIdentifier(rd, dpnId); + Optional dpnInVpn = + VpnUtil.read(broker, LogicalDatastoreType.OPERATIONAL, id); + if (dpnInVpn.isPresent()) { + // if (action == UpdateRouteAction.ADVERTISE_ROUTE) { + // fibManager.populateFibOnNewDpn(dpnId, VpnUtil + // .getVpnId(broker, vpnInstance.getVpnInstanceName()), rd); + // } + List + vpnInterfaces = dpnInVpn.get().getVpnInterfaces(); + for (org.opendaylight.yang.gen.v1.urn.opendaylight.l3vpn.rev130911.vpn.instance.op.data + .vpn.instance.op.data.entry.vpn.to.dpn.list.VpnInterfaces vpnInterface : vpnInterfaces) { + InstanceIdentifier vpnIntfId = + VpnUtil.getVpnInterfaceIdentifier(vpnInterface.getInterfaceName()); + InstanceIdentifier path = + vpnIntfId.augmentation(Adjacencies.class); + Optional adjacencies = + VpnUtil.read(broker, LogicalDatastoreType.OPERATIONAL, path); + + 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) + bgpManager.addPrefix(rd, adjacency.getIpAddress(), + adjacency.getNextHopIp(), + adjacency.getLabel().intValue()); + else if (action == UpdateRouteAction.WITHDRAW_ROUTE) + bgpManager.deletePrefix(rd, adjacency.getIpAddress()); + } catch (Exception e) { + LOG.error("Exception when updating prefix {} in vrf {} to BGP", + adjacency.getIpAddress(), rd); + } + } + } + + } + // if (action == UpdateRouteAction.WITHDRAW_ROUTE) { + // fibManager.cleanUpDpnForVpn(dpnId, VpnUtil.getVpnId(broker, vpnInstance.getVpnInstanceName()), rd); + // } + } + } catch (Exception e) { + LOG.error("updatePrefixesForDPN {} in vpn {} failed", dpnId, vpnInstance.getVpnInstanceName(), e); + } + } + } + } + }